Parent-Death Signals: Close the Startup Race in a Supervised Device Helper

Set PR_SET_PDEATHSIG in the helper, then verify that its parent is still the expected supervisor captured before fork. The identity check catches a supervisor that died before the helper armed the notification; the armed signal covers a later death. This closes a missed-notification startup window, but it does not make every helper operation atomic with the supervisor’s lifetime.

This guide follows Linux man-pages 6.12. The primary procedure assumes a single-threaded supervisor forks a helper and remains its intended parent. Multithreaded creators, subreapers, privilege transitions and exec require the additional boundaries below. No parent-death signal fixture or supervisor termination was executed for this article.

Capture the expected parent before the race begins

In the supervisor, record its process identity before fork and pass that expected value through inherited state to the helper. Do not have the helper establish its expectation by calling getppid only after it starts: the supervisor might already have exited, so the helper could accidentally accept its new reaper as the intended parent.

The PR_SET_PDEATHSIG contract sends a signal on subsequent parent-thread termination. It does not retroactively report every death that occurred before the setting was installed. A helper that merely calls prctl and then starts serving can therefore remain alive after a very fast supervisor exit.

Choose the helper’s reaction before choosing a signal. It may perform bounded cleanup and exit, or stop accepting work and notify a separate recovery owner. The selected signal’s handler, mask and disposition must implement that decision. Setting the kernel option does not guarantee the signal is unblocked or that the helper’s default action matches the product requirement.

A supervisor captures its identity before fork; the helper prepares signaling, arms parent-death notification and checks the expected parent before continuing, with explicit non-instantaneous-shutdown limitations.
Original startup race model. The identity check covers death before arming; the signal path covers later parent-thread death.

Use an arm-then-check startup gate

  1. The supervisor records the expected parent PID before fork, with a defined creating-thread model.
  2. The helper establishes its chosen signal-handling or synchronous-consumption path before arming the notification.
  3. The helper calls prctl(PR_SET_PDEATHSIG, chosen_signal) and checks the result.
  4. It compares getppid with the inherited expected supervisor identity.
  5. If they differ, it enters the parent-gone path immediately rather than waiting for a signal that may never arrive.
  6. If they match, it continues only under the established notification and shutdown policy.

This is an ordering specification, not drop-in C code. The launch wrapper must handle signal masks, exec failure and cleanup according to its actual architecture. A prctl failure must not silently turn the helper into an unsupervised long-lived service.

Consider three synthetic orderings. If the supervisor dies before arming, the subsequent parent check detects reparenting. If it dies after arming but before the check, the signal path and possibly the check detect the event. If it dies after a successful check, the armed signal remains the notification mechanism. Testing only the last ordering misses the original startup defect.

Do not turn notification into a work-authorization guarantee

The supervisor can die immediately after the helper’s final check. Signal delivery and application handling take time, and a handler may be delayed by masking or scheduling. The helper can therefore still execute some instructions after the death. PR_SET_PDEATHSIG is not a hard deadline, instantaneous stop or hardware interlock.

If a device operation must never begin after a supervisor loses authority, use an operation-level admission protocol or independent safety mechanism appropriate to that requirement. Parent-death notification can initiate cleanup, but it cannot establish that a command already issued to hardware was canceled or rolled back.

Make shutdown idempotent. Both the explicit failed-parent check and the signal path may request it. One owner should close admission, resolve in-flight work and release resources. Keep arbitrary cleanup outside an asynchronous signal handler unless each operation is documented safe there; a minimal notification to the ordinary event loop is often easier to audit.

The parent is the creating thread

The manual’s caveat is precise: the relevant parent is the thread that created the helper, not necessarily the lifetime of the entire supervisor process. If a worker thread forks and then exits while other supervisor threads continue, the helper can receive its parent-death signal.

For a multithreaded supervisor, identify which thread creates helpers and how long it remains alive. A numeric parent-process comparison alone does not replace this thread-lifetime contract. Either use a deliberately long-lived creator or select a supervision mechanism whose lifetime matches the intended authority.

The signal is process-directed. The signal model therefore matters for a multithreaded helper as well: masks and eligible delivery threads must be coordinated. Do not assume that the thread calling prctl is always the one that later handles the notification.

Audit fork, exec, credentials and adoption

Transition Required review
Helper creates another child The setting is cleared in the forked child; decide its own supervision policy.
Ordinary exec The setting is normally preserved, but signal disposition and mask behavior still need qualification.
Privileged executable or listed credential changes The parent-death setting can be cleared; verify the final helper identity and setup order.
Reparenting to a subreaper Subsequent subreaper termination can also produce the documented notification.

The pinned reference lists clearing on set-user-ID/set-group-ID or file-capability execution and on changes to effective or filesystem user/group IDs. A setup sequence that arms the option and then drops credentials can therefore invalidate its own assumption. Review the final privilege-transition sequence and reestablish the intended contract where supported, rather than declaring setup complete at the first successful prctl.

Subreaper adoption also changes the simple “parent becomes PID 1” story. The subreaper documentation describes adoption by the nearest living ancestor subreaper. Compare against the expected supervisor, not a hard-coded assumption that every orphan’s getppid must equal one.

Qualify bounded failure orderings

Use an approved disposable process tree with pipe barriers so the test controller can pause the helper before arming and before its parent check. Let only owned launcher processes exit. Verify early-parent exit, normal arm/check completion, later parent exit, blocked notification and exec failure as separate cases.

Add the actual credential and creating-thread transitions only in a controlled environment that authorizes them. Record the expected parent, observed parent, prctl result, notification consumption and final cleanup state. Do not infer the exact moment of death from a buffered log timestamp.

The release artifact is a startup race diagram plus a lifecycle matrix. It should prove that an already-gone supervisor is not silently accepted, later loss reaches the intended control path, and helper resources reach a defined terminal state. Those are narrower and more defensible claims than promising that a child can never outlive its parent for even one instruction.

Similar Posts