launchd residual-process-group cleanup after main-job death: supported signals and timing

For current macOS 27, I am trying to establish the supported behavior of residual process-group cleanup before selecting an architecture.

Consider a per-user launchd job whose actual main process O directly creates one fixed child F. F remains in the job's process group, creates no descendants, and does not change its process group or session. AbandonProcessGroup is not enabled. O may exit normally, crash, or receive SIGKILL while F remains alive. This is a documentary question; I am not presenting runtime observations or a reproducer.

The installed launchd.plist(5) manual (dated 30 July 2019) describes cleanup of remaining same-process-group members when a job dies. It describes ExitTimeOut in terms of stopping a job. Historical Apple source contains a SIGTERM attempt in job_reap, but I do not assume that code describes current macOS behavior:
https://github.com/apple-oss-distributions/launchd/blob/49a9c79b2949192dfca697b1054245cdfb645788/src/core.c

  1. What signals and escalation, if any, are supported for F after O has already died? Does the answer differ for normal exit, crash, or SIGKILL, or by per-user job domain?
  2. Does ExitTimeOut apply to that residual group after O is dead, or only to stopping the main job process?
  3. Is there a supported finite upper bound from O permanently ceasing execution to F being unable to execute further, including stopped or blocked F and O dying during child creation? If so, what is its documented timing origin and treatment of system sleep? If there is no supported bound, that clarification is sufficient.

I have read the DTS answer about job runtime and CPU-versus-wall-time limits:
https://developer.apple.com/forums/thread/845944
My question concerns residual-group cleanup after the actual main job process dies, rather than a separate requester's disappearance or the runtime limit of a still-live job.

Answered by DTS Engineer in 911345022

The only documentation you’re gonna find about this is in man pages, and I believe you’ve found the relevant bits in the launchd.plist man page. If you need more constraints to be documentation, I encourage you to file an ER against that man page.

As to what will happen in practice:

  • I suspect that F will be killed via a SIGTERM, with no backoff to SIGKILL. This is a best effort operation because, as we discussed in your other thread [1], the process can avoid being killed simply by changing its process group.
  • It doesn’t matter how the job stopped.
  • ExitTimeOut isn’t relevant to F.
  • There are no real-time guarantees.

Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] Well, I’m presuming that’s use operating under a different account. It seems unlikely that multiple folks would be independently asking about the same dusty corner of macOS in the same week.

The only documentation you’re gonna find about this is in man pages, and I believe you’ve found the relevant bits in the launchd.plist man page. If you need more constraints to be documentation, I encourage you to file an ER against that man page.

As to what will happen in practice:

  • I suspect that F will be killed via a SIGTERM, with no backoff to SIGKILL. This is a best effort operation because, as we discussed in your other thread [1], the process can avoid being killed simply by changing its process group.
  • It doesn’t matter how the job stopped.
  • ExitTimeOut isn’t relevant to F.
  • There are no real-time guarantees.

Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] Well, I’m presuming that’s use operating under a different account. It seems unlikely that multiple folks would be independently asking about the same dusty corner of macOS in the same week.