summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/detached/server.zig17
-rw-r--r--test/fs.py18
2 files changed, 34 insertions, 1 deletions
diff --git a/src/detached/server.zig b/src/detached/server.zig
index 5bf2384b..b47bda1b 100644
--- a/src/detached/server.zig
+++ b/src/detached/server.zig
@@ -1181,6 +1181,17 @@ pub const Session = struct {
}
};
+/// SIGTERM, SIGINT or SIGHUP: quit as Exit does, through the loop, so its
+/// sockets are unlinked on the way out rather than left for the next
+/// session to trip on. The handler only sets the flag and wakes the loop.
+var quit_signalled = std.atomic.Value(bool).init(false);
+var quit_wake: c_int = -1;
+
+fn onQuitSignal(_: std.posix.SIG) callconv(.c) void {
+ quit_signalled.store(true, .release);
+ if (quit_wake >= 0) _ = libc.send(quit_wake, "q", 1, nosignal);
+}
+
pub fn run(init: std.process.Init, opts: pardes.Options, name: []const u8) !void {
const gpa = init.gpa;
const allocs = pardes.memory.init(gpa);
@@ -1231,7 +1242,11 @@ pub fn run(init: std.process.Init, opts: pardes.Options, name: []const u8) !void
core.host = h;
while (core.nextEffect()) |effect| core.perform(effect);
session.in_loop = true;
- while (!session.core.quit) {
+ quit_wake = session.mailbox.wake[1];
+ const on_quit: std.posix.Sigaction = .{ .handler = .{ .handler = onQuitSignal }, .mask = std.posix.sigemptyset(), .flags = 0 };
+ for ([_]std.posix.SIG{ .HUP, .INT, .TERM }) |sig| std.posix.sigaction(sig, &on_quit, null);
+ defer quit_wake = -1;
+ while (!session.core.quit and !quit_signalled.load(.acquire)) {
pardes.turn.restoreSettled();
try session.core.pump(h);
if (session.core.quit) break;
diff --git a/test/fs.py b/test/fs.py
index b55ad5ab..45c38c2e 100644
--- a/test/fs.py
+++ b/test/fs.py
@@ -3,6 +3,7 @@ import contextlib
import fcntl
import json
import os
+import signal
from pathlib import Path
import subprocess
import struct
@@ -424,10 +425,27 @@ def exit_answers(binary):
raise AssertionError("Exit did not quit the editor")
+def signal_cleans_up(binary):
+ """A detached session told to stop by a signal unlinks its sockets."""
+ for sig in [signal.SIGTERM, signal.SIGINT, signal.SIGHUP]:
+ with tempfile.TemporaryDirectory(prefix='pardes-sig-') as directory:
+ root = Path(directory)
+ seen = {}
+ with session(binary, root, 'sig', terminal=seen) as (client, address):
+ detached = root / 'pardes-detached-sig.sock'
+ assert address.exists() and detached.exists()
+ os.kill(seen['pid'], sig)
+ deadline = time.monotonic() + 5
+ while (address.exists() or detached.exists()) and time.monotonic() < deadline:
+ time.sleep(.01)
+ assert not address.exists() and not detached.exists(), (sig, list(root.iterdir()))
+
+
def test(binary, quic=False):
started = time.monotonic()
run_file(binary)
exit_answers(binary)
+ signal_cleans_up(binary)
for options, message in [
(['--fs'], b'no such option'),
(['--fs9'], b'no such option'),