Change session exit detection

Previously we waited for all opened file descriptors to the terminal
to be closed. This caused problem when e.g. running "sleep 900 &"
and then exiting the shell, with sleep keeping the session alive and
had to be killed manually (killing the process group did not help -
the shell had already exited and was in zombie state). This is also
what most other terminal emulators do.

Relatedly, switch to sending SIGKILL to force quit a session instead
of SIGHUP, since SIGHUP can be ignored.
This commit is contained in:
Fredrik Fornwall
2016-06-08 01:37:08 +02:00
parent f047160fd6
commit 2104252244
3 changed files with 28 additions and 38 deletions

View File

@@ -40,15 +40,6 @@ final class JNI {
*/
public static native int waitFor(int processId);
/**
* Send SIGHUP to a process group.
*
* There exists a kill(2) system call wrapper in {@link android.os.Process#sendSignal(int, int)}, but that makes a
* "if (pid > 0)" check so cannot be used for sending to a process group:
* https://android.googlesource.com/platform/frameworks/base/+/donut-release/core/jni/android_util_Process.cpp
*/
public static native void hangupProcessGroup(int processId);
/** Close a file descriptor through the close(2) system call. */
public static native void close(int fileDescriptor);

View File

@@ -1,5 +1,13 @@
package com.termux.terminal;
import android.annotation.SuppressLint;
import android.os.Handler;
import android.os.Message;
import android.system.ErrnoException;
import android.system.Os;
import android.system.OsConstants;
import android.util.Log;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
@@ -9,11 +17,6 @@ import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.util.UUID;
import android.annotation.SuppressLint;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
/**
* A terminal session, consisting of a process coupled to a terminal interface.
* <p>
@@ -190,10 +193,6 @@ public final class TerminalSession extends TerminalOutput {
}
} catch (Exception e) {
// Ignore, just shutting down.
} finally {
// Now wait for process exit:
int processExitCode = JNI.waitFor(mShellPid);
mMainThreadHandler.sendMessage(mMainThreadHandler.obtainMessage(MSG_PROCESS_EXITED, processExitCode));
}
}
}.start();
@@ -213,7 +212,16 @@ public final class TerminalSession extends TerminalOutput {
}
}
}.start();
}
new Thread("TermSessionWaiter[pid=" + mShellPid + "]") {
@Override
public void run() {
int processExitCode = JNI.waitFor(mShellPid);
mMainThreadHandler.sendMessage(mMainThreadHandler.obtainMessage(MSG_PROCESS_EXITED, processExitCode));
}
}.start();
}
/** Write data to the shell process. */
@Override
@@ -273,20 +281,16 @@ public final class TerminalSession extends TerminalOutput {
notifyScreenUpdate();
}
/**
* Finish this terminal session. Frees resources used by the terminal emulator and closes the attached
* <code>InputStream</code> and <code>OutputStream</code>.
*/
public void finishIfRunning() {
if (isRunning()) {
JNI.hangupProcessGroup(mShellPid);
// Stop the reader and writer threads, and close the I/O streams. Note that
// cleanupResources() will be run later.
mTerminalToProcessIOQueue.close();
mProcessToTerminalIOQueue.close();
JNI.close(mTerminalFileDescriptor);
}
}
/** Finish this terminal session by sending SIGKILL to the shell. */
public void finishIfRunning() {
if (isRunning()) {
try {
Os.kill(mShellPid, OsConstants.SIGKILL);
} catch (ErrnoException e) {
Log.w("termux", "Failed sending SIGKILL: " + e.getMessage());
}
}
}
/** Cleanup resources when the process exits. */
void cleanupResources(int exitStatus) {

View File

@@ -208,11 +208,6 @@ JNIEXPORT int JNICALL Java_com_termux_terminal_JNI_waitFor(JNIEnv* TERMUX_UNUSED
}
}
JNIEXPORT void JNICALL Java_com_termux_terminal_JNI_hangupProcessGroup(JNIEnv* TERMUX_UNUSED(env), jclass TERMUX_UNUSED(clazz), jint procId)
{
killpg(procId, SIGHUP);
}
JNIEXPORT void JNICALL Java_com_termux_terminal_JNI_close(JNIEnv* TERMUX_UNUSED(env), jclass TERMUX_UNUSED(clazz), jint fileDescriptor)
{
close(fileDescriptor);