Skip to content

EOF after the parent disappears

 2 min A small guardian process ties a command group to its Python parent’s lifetime through a pipe, even when Python cannot run its own cleanup.
Published

Aug 17, 2026

A Python wrapper can clean up a child in finally only if Python gets to run that block. An abrupt parent exit can leave the command’s processes alive and their inherited pipes open.

In Python Spice’s process wrapper, the POSIX path starts the command in a new process group and a small shell guardian in a separate session. The guardian waits on a pipe whose writer belongs to the Python parent.

Normal completion writes a newline-terminated marker. A successful read disarms the guardian. If the parent disappears and the pipe reaches EOF without that marker, the guardian sends TERM to the command group, waits a quarter second, and follows with KILL if the first signal succeeded.

The normal wait adds no polling loop to Python. The pipe’s lifetime carries the signal. A separate executable also avoids running a custom Python child after forking a process that may already have threads.

The group matters because its leader can exit before descendants that still hold output pipes. Cleanup targets the process group rather than assuming that a finished leader means all its work is finished. Reaping the direct child remains a separate obligation.

There are explicit limits. This guardian is the POSIX implementation; Windows retains a different cleanup path. If spawning the guardian fails, the helper returns an unarmed guard. Processes that leave the command group are not covered merely by being descendants. The guarantee belongs to the group and a successfully started observer.

The implementation also waits for or terminates the guardian when disarming it. A lifetime helper should not become the process the caller forgets to collect.