GUIBRUSHR.Retrieval.ExofastMCMC.process_safety module

Process-safety helpers for the retrieval worker fan-out.

The retrieval main process forks worker processes (and a Manager server) with the fork start method. They are non-daemon and the tree has no process group / session isolation, so two failure modes need explicit handling:

  1. Parent dies -> children must die too. If the main process crashes (segfault inside petitRADTRANS Fortran, OOM kill, …) the forked children are reparented to init (PID 1) and keep burning CPU/RAM as orphans. install_parent_death_signal uses the Linux prctl(PR_SET_PDEATHSIG) so the kernel kills the child the instant its parent dies.

  2. A child dies -> the parent must survive and report it. describe_exitcode turns a multiprocessing.Process.exitcode into a human-readable cause (negative exitcode == killed by signal; SIGSEGV=-11, SIGKILL/OOM=-9, …), so the parent can log why a worker died instead of failing silently.

GUIBRUSHR.Retrieval.ExofastMCMC.process_safety.mp_context()[source]

Return a multiprocessing context safe for forking model_obj.

On Linux the default fork is used (CoW makes spawn cost ~0). On macOS Python 3.8+ defaults to spawn which would re-pickle the full pRT atmosphere (~hundreds of MB) for every Process, costing minutes-to-hours per run (see B8 audit). We force fork on macOS and set OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES so Apple’s fork-safety check doesn’t abort the workers - safe here because pRT workers do pure Python + Fortran and never touch Cocoa/CoreFoundation.

Shared by map_optimizer and ModelData so the Manager server and the worker Processes always use the same (fork) start method.

GUIBRUSHR.Retrieval.ExofastMCMC.process_safety.install_parent_death_signal(sig: int = Signals.SIGKILL) None[source]

Ask the kernel to send sig to this process when its parent dies.

Linux only (uses prctl). Intended to be called as the very first statement of a forked worker target (or as a Manager start initializer) so the child cannot outlive a crashed parent. On macOS / other platforms this is a no-op.

Also closes the fork/prctl race: if the parent already died between fork() and the prctl call, this process was reparented to PID 1 and the death signal will never be delivered - detect that and exit now.

GUIBRUSHR.Retrieval.ExofastMCMC.process_safety.describe_exitcode(exitcode) str[source]

Return a human-readable explanation of a Process.exitcode.

None -> still running / not joined; 0 -> normal exit; negative -> killed by signal -exitcode; positive -> non-zero exit status.