Hi Quinn,
Following your recommendation by email, I’m posting this as a new thread. Thank you again for your guidance on Virtualization.framework.
This is a separate question about ordinary host-side subprocess ownership and timeout recovery, not VM cleanup.
Target environment:
- Intel x86_64
- macOS Monterey 12.7.6, build 21H1320
- Python 3.13.15
- Public, supported mechanisms; no root privileges, private APIs or kernel extensions
We are verifying a subprocess supervision component with this process structure:
Trusted caller process → runner → pytest → private helper → native subprocess
Each parent normally owns the consuming wait for its direct child. The private helper exclusively manages signalling and reaping of its native child. Outer processes do not signal saved helper/native PIDs.
Cancellation is cooperative, through channels and file/token delivery. The runner observes its fresh pytest child, drains stdout/stderr with bounded retention, and consumes its exact child’s status after exit is observed.
The runner, pytest and helper are launched in separate sessions. Consequently, signalling pytest’s process group would not cover the separately sessioned helper and its native child.
The unresolved failure case is:
- A fresh pytest invocation starts.
- Cancellation delivery fails, or delivery succeeds but the work does not finish.
- The runner continues observation and bounded output draining within the remaining deadline.
- The deadline expires while pytest or processes below it may still be alive.
- The runner reports an unresolved outcome and may exit.
The caller also has a bounded deadline and may return without consuming its runner child.
Closing capture pipes can cause EPIPE and disturb the child’s cleanup. Exiting a consuming parent also relinquishes its ability to collect that child’s eventual status. The outer caller does not automatically acquire wait rights over pytest or its descendants.
Our current policy retains affected files, preserves the original failure, and prevents subsequent tests from starting. We do not treat cancellation delivery, pipe EOF, successful signal delivery, or direct-child reap as proof that every descendant has stopped.
This prevents false success, but does not resolve responsibility for work that remains alive.
We have considered separating the caller’s response lifetime from the consuming owners’ lifetimes: the caller could return an unresolved response while both existing parents remain alive, draining output and collecting their direct children later. However, keeping them alive adds no termination authority and does not address a crash of either owner.
I am not asking for an absolute guarantee against arbitrary kernel failures, or a promise that SIGKILL always completes within a fixed time. I would like to understand the supported architectural approach on Monterey.
My questions are:
-
Is retaining the existing consuming parents beyond the response deadline the appropriate pattern, or is there a supported macOS facility that provides a better ownership and recovery boundary?
-
What safe termination authority should those owners retain over their fresh direct children? If process groups are part of the solution, what lifecycle rules are needed to avoid acting on a reused identifier, particularly after leader exit or reaping?
-
Is there a supported way to manage the separately sessioned helper/native work if an intermediate parent exits? Or must each level independently retain its own supervision and cleanup responsibility?
-
If the consuming owner itself crashes, is there a supported recovery mechanism for ordinary subprocesses? Would launchd or XPC materially help, and what limitations would remain for descendants in separate sessions?
-
Which design constraint would you recommend changing: cooperative-only cancellation, the fixed lifetime of the runner, or the process topology? These are our current choices, not restrictions we assume macOS imposes.
Our practical goal is a bounded response while an identifiable owner remains responsible for unsettled work, with appropriate termination authority and an honest unresolved outcome when cleanup cannot be established.
The immediate qualification scope is only three simple tests, using shell bodies such as exit, kill -9 $$, and echo with ordinary exit statuses. They contain no intentional background work, pipelines or command substitutions. We would prefer a proportionate supported pattern rather than a new general supervision framework.
If a reduced example would help clarify the question, I can provide one.
Thank you for your time and guidance.