Three related reaper problems (R5 from design/pf-zerocopy-sweep-handoff.md):
- sweep_reaper called kill() + blocking wait() while holding the global
REAPER mutex. A worker wedged in a driver ioctl is in D state and ignores
SIGKILL, so wait() never returned — parking every later spawn() and every
importer drop() behind the lock. Expired entries are now drained under the
lock and killed outside it, with a bounded (~100 ms) try_wait poll; a
worker that still won't die is parked again for a later sweep (re-killing
is harmless) instead of blocking anyone.
- No PR_SET_PDEATHSIG: if the host died, the worker survived holding its
CUcontext + BufferPool — by the code's own comment, hundreds of MB of
VRAM. The pre_exec closure (async-signal-safe: prctl/getppid/dup2/fcntl
only, no allocation) now arms SIGKILL-on-parent-death with the standard
getppid race guard.
Not taken: arming the 20 s kill deadline from a timer instead of the next
spawn/drop (the handoff's optional third leg). PDEATHSIG closes the
worst-case orphan; a wedged worker after the LAST capture of a session
still waits for the next spawn to be swept.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>