Skip to content

fix(exec): kill child processes on agent shutdown + Linux PR_SET_PDEATHSIG helper (issue #24) - #39

Merged
labtgbot merged 2 commits into
mainfrom
fix/issue-24-zombie-processes
Jun 15, 2026
Merged

fix(exec): kill child processes on agent shutdown + Linux PR_SET_PDEATHSIG helper (issue #24)#39
labtgbot merged 2 commits into
mainfrom
fix/issue-24-zombie-processes

Conversation

@xdevrobot

@xdevrobot xdevrobot commented Jun 15, 2026

Copy link
Copy Markdown
Collaborator

Summary

Fixes issue #24 and #26 — detached subprocesses spawned by exec_run surviving parent process death.

Changes

src/index.ts

  • Import killAllSpawnedProcesses from ./agent/tools/exec/runner.js
  • Call it in stopAgent() after bridge disconnect (graceful shutdown path)
  • Add process.on('exit') safety net for forced exits (uncaught exception)

src/agent/tools/exec/runner.ts

  • Add PDEATHSIG_HELPER path constant pointing to bin/prctl-pdeathsig
  • On Linux, if the helper binary exists, use it as a wrapper for all spawned commands so the kernel automatically sends SIGKILL to children when the parent dies (PR_SET_PDEATHSIG)
  • On non-Linux or when helper is absent, behavior is unchanged
  • Track all spawned processes in spawnedProcesses Set for cleanup

src/agent/tools/exec/tests/runner.test.ts

  • Update timeout kill test to match child.kill() API (was process.kill(-pid))

bin/prctl-pdeathsig.c (new)

  • Tiny C helper: calls prctl(PR_SET_PDEATHSIG, SIGKILL) then execvp the real command
  • Build: gcc -o bin/prctl-pdeathsig bin/prctl-pdeathsig.c
  • Optional — if not compiled, everything works as before

Behavior matrix

Scenario Before After
SIGTERM/SIGINT Children survive Killed in stopAgent()
Uncaught exception Children survive Killed in process.on('exit')
Linux crash (SIGKILL to parent) Children survive Kernel kills via PR_SET_PDEATHSIG (if helper compiled)
Normal command exit Clean Clean (unchanged)

Closes #24
Closes #26

🤖 Generated with Claude Code

…THSIG helper (issue #24)

- Wire killAllSpawnedProcesses() into stopAgent() so all remaining
  child processes are SIGKILL'd when the agent stops (SIGTERM/SIGINT).
- Add process.on('exit') safety net for forced exits (uncaught exception).
- Add optional prctl-pdeathsig Linux helper (bin/prctl-pdeathsig.c):
  when compiled and present in bin/, it wraps every spawned command
  so the kernel automatically sends SIGKILL to the child when the
  parent dies (PR_SET_PDEATHSIG). No-op on non-Linux platforms.
- Helper is loaded at startup; if absent, commands spawn directly
  as before with no behavioral change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Old test asserted process.kill(-pid, 'SIGTERM') which was the previous
detached-process-tree approach. Current code uses child.kill('SIGTERM')
directly on the spawned child process. Update the assertion accordingly.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants