mirror of
https://github.com/logos-co/logos-liblogos.git
synced 2026-08-27 12:51:10 +00:00
fix(host): tie worker lifetime to the daemon (no orphan leak on crash)
Pairs the process-group isolation (setsid) with explicit parent-death cleanup so a worker never lingers if the daemon dies WITHOUT cleaning it up (a crash). setsid detaches the worker from the launcher's controlling terminal, which also removes the incidental SIGHUP that used to reap orphans — so we replace it with something reliable: PR_SET_PDEATHSIG(SIGKILL) on Linux (kernel-level, immediate), plus a portable getppid() watchdog (covers macOS and backs up PDEATHSIG) that exits if our parent changes. Compares against the daemon's actual pid (not pid 1) so a daemon that is itself PID 1 (a container) is handled correctly. Graceful shutdown is unchanged (daemon still kills workers per-PID). Verified: workers isolate into their own group; after kill -9 of the daemon, every worker exits on its own (no leak). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
fd00bcbccb
commit
272c6b5bc7
@@ -9,9 +9,13 @@
|
||||
#include <csignal>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <thread>
|
||||
|
||||
#include <execinfo.h>
|
||||
#include <unistd.h>
|
||||
#ifdef __linux__
|
||||
#include <sys/prctl.h>
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -157,6 +161,40 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
// Tie this worker's lifetime to the daemon's. If the daemon (our parent)
|
||||
// dies WITHOUT cleaning us up — i.e. it crashes — make sure we don't linger
|
||||
// as an orphaned process. This is the explicit replacement for the
|
||||
// controlling-terminal SIGHUP that setsid() above intentionally detached us
|
||||
// from: graceful shutdown still kills us per-PID from the daemon, and now a
|
||||
// daemon *crash* cleans us up too.
|
||||
{
|
||||
const pid_t daemon_pid = ::getppid();
|
||||
#ifdef __linux__
|
||||
// Kernel-level + immediate. PR_SET_PDEATHSIG is delivered when the
|
||||
// thread that forked us exits; here that is the daemon's long-lived
|
||||
// event-loop/io thread, so it only fires on real daemon death.
|
||||
::prctl(PR_SET_PDEATHSIG, SIGKILL);
|
||||
#endif
|
||||
// Race guard: if the daemon died during/just before the setup above, our
|
||||
// parent has already changed (we've been reparented) — exit now. We
|
||||
// compare against the daemon's actual pid, NOT pid 1, so a daemon that is
|
||||
// itself PID 1 (e.g. in a container) is handled correctly.
|
||||
if (::getppid() != daemon_pid) {
|
||||
_exit(0);
|
||||
}
|
||||
// Portable watchdog (covers platforms without PR_SET_PDEATHSIG, e.g.
|
||||
// macOS, and backs it up elsewhere): if our parent changes — the daemon
|
||||
// died and the OS reparented us — exit so we never leak.
|
||||
std::thread([daemon_pid] {
|
||||
while (::getppid() == daemon_pid) {
|
||||
::sleep(1);
|
||||
}
|
||||
_exit(0);
|
||||
}).detach();
|
||||
}
|
||||
#endif
|
||||
|
||||
ModuleArgs args = parseCommandLineArgs(argc, argv);
|
||||
if (!args.valid) {
|
||||
return 1;
|
||||
|
||||
Reference in New Issue
Block a user