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.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
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.
|
* 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 {
|
public final class LinuxPty implements AutoCloseable {
|
||||||
static final Linker LINKER = Linker.nativeLinker();
|
static final Linker LINKER = Linker.nativeLinker();
|
||||||
private static final SymbolLookup LIBC = LINKER.defaultLookup();
|
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 AddressLayout C_POINTER = (AddressLayout) LINKER.canonicalLayouts().get("void*");
|
||||||
static final ValueLayout.OfShort C_SHORT = (ValueLayout.OfShort) LINKER.canonicalLayouts().get("short");
|
static final ValueLayout.OfShort C_SHORT = (ValueLayout.OfShort) LINKER.canonicalLayouts().get("short");
|
||||||
@@ -275,14 +282,43 @@ public final class LinuxPty implements AutoCloseable {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
if (closed) {
|
if (!markClosed()) {
|
||||||
return;
|
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;
|
closed = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void closeMaster() {
|
||||||
callKill(pid, closeSignal);
|
callKill(pid, closeSignal);
|
||||||
callInt(CLOSE, masterFd);
|
callInt(CLOSE, masterFd);
|
||||||
reap();
|
|
||||||
arena.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void reap() {
|
private void reap() {
|
||||||
|
|||||||
@@ -180,8 +180,27 @@ public final class ShellSession implements AutoCloseable {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
closed = true;
|
if (!markClosed()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
reader.shutdownNow();
|
reader.shutdownNow();
|
||||||
pty.close();
|
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
|
@Override
|
||||||
public void close() {
|
public void close() {
|
||||||
if (session != null) {
|
if (session != null) {
|
||||||
session.close();
|
session.closeDetached();
|
||||||
session = null;
|
session = null;
|
||||||
}
|
}
|
||||||
mouseEncoder.close();
|
mouseEncoder.close();
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ final class TerminalWindow {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Fully tears this window down (FX thread, idempotent): stops rendering, closes the compositor —
|
* 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
|
* 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.
|
* the WM close button and the last-pane-closed hook route through here.
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user