instantly close panes instead of waiting for process to end
This commit is contained in:
@@ -15,6 +15,8 @@ import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
/**
|
||||
* A Linux PTY backed by libc via the Foreign Function & Memory API.
|
||||
@@ -33,6 +35,11 @@ import java.util.Map;
|
||||
public final class LinuxPty implements AutoCloseable {
|
||||
static final Linker LINKER = Linker.nativeLinker();
|
||||
private static final SymbolLookup LIBC = LINKER.defaultLookup();
|
||||
private static final ExecutorService REAPER = Executors.newCachedThreadPool(runnable -> {
|
||||
Thread thread = new Thread(runnable, "pty-reaper");
|
||||
thread.setDaemon(true);
|
||||
return thread;
|
||||
});
|
||||
|
||||
static final AddressLayout C_POINTER = (AddressLayout) LINKER.canonicalLayouts().get("void*");
|
||||
static final ValueLayout.OfShort C_SHORT = (ValueLayout.OfShort) LINKER.canonicalLayouts().get("short");
|
||||
@@ -275,14 +282,43 @@ public final class LinuxPty implements AutoCloseable {
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if (closed) {
|
||||
if (!markClosed()) {
|
||||
return;
|
||||
}
|
||||
closeMaster();
|
||||
try {
|
||||
reap();
|
||||
} finally {
|
||||
arena.close();
|
||||
}
|
||||
}
|
||||
|
||||
/** Send the configured close signal and close the master fd now; reap off the caller thread. */
|
||||
public void closeDetached() {
|
||||
if (!markClosed()) {
|
||||
return;
|
||||
}
|
||||
closeMaster();
|
||||
REAPER.submit(() -> {
|
||||
try {
|
||||
reap();
|
||||
} finally {
|
||||
arena.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private synchronized boolean markClosed() {
|
||||
if (closed) {
|
||||
return false;
|
||||
}
|
||||
closed = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
private void closeMaster() {
|
||||
callKill(pid, closeSignal);
|
||||
callInt(CLOSE, masterFd);
|
||||
reap();
|
||||
arena.close();
|
||||
}
|
||||
|
||||
private void reap() {
|
||||
|
||||
@@ -180,8 +180,27 @@ public final class ShellSession implements AutoCloseable {
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
closed = true;
|
||||
if (!markClosed()) {
|
||||
return;
|
||||
}
|
||||
reader.shutdownNow();
|
||||
pty.close();
|
||||
}
|
||||
|
||||
/** Signal and disconnect the pty immediately, but leave child reaping to a background thread. */
|
||||
public void closeDetached() {
|
||||
if (!markClosed()) {
|
||||
return;
|
||||
}
|
||||
reader.shutdownNow();
|
||||
pty.closeDetached();
|
||||
}
|
||||
|
||||
private synchronized boolean markClosed() {
|
||||
if (closed) {
|
||||
return false;
|
||||
}
|
||||
closed = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -383,7 +383,7 @@ public final class TerminalPane implements AutoCloseable, RenderTarget {
|
||||
@Override
|
||||
public void close() {
|
||||
if (session != null) {
|
||||
session.close();
|
||||
session.closeDetached();
|
||||
session = null;
|
||||
}
|
||||
mouseEncoder.close();
|
||||
|
||||
@@ -86,7 +86,7 @@ final class TerminalWindow {
|
||||
|
||||
/**
|
||||
* Fully tears this window down (FX thread, idempotent): stops rendering, closes the compositor —
|
||||
* which reaps the pane shells via the configured {@code close_signal} — disposes the Stage, and
|
||||
* which signals pane shells via the configured {@code close_signal} — disposes the Stage, and
|
||||
* notifies the manager so it can drop the window (and, in standalone mode, exit the JVM). Both
|
||||
* the WM close button and the last-pane-closed hook route through here.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user