When a child process forked from a parent dies, it still exists to some extent and is left in a zombie state, until it is reaped from a wait() call.
Is is possible to detach this parent-child relationship and have the children be automatically reaped? Maybe orphan off the child to init, or something?
Possible use case: Creating a lot of fire-and-forget processes in a long-lived program, without "holding" on to an increasing list of zombie PIDs that cannot be recycled by the OS.
Detach process by putting it into the background If you have a command running, and need to put it into the background to free up your terminal, you can press Ctrl + Z on your keyboard to stop the process. Here's an example. To see a list of jobs in the background, use the jobs command.
The child process does not inherit the following: Priority class. Handles returned by LocalAlloc, GlobalAlloc, HeapCreate, and HeapAlloc.
A child process may also be called a subprocess or a subtask. A child process is created as its parent process's copy and inherits most of its attributes. If a child process has no parent process, it was created directly by the kernel.
Per the POSIX _exit() documentation:
If the parent process of the calling process has set its
SA_NOCLDWAIT
flag or has set the action for theSIGCHLD
signal toSIG_IGN
:
The process' status information (see Status Information), if any, shall be discarded.
The lifetime of the calling process shall end immediately. If
SA_NOCLDWAIT
is set, it is implementation-defined whether aSIGCHLD
signal is sent to the parent process.If a thread in the parent process of the calling process is blocked in
wait()
,waitpid()
, orwaitid()
, and the parent process has no remaining child processes in the set of waited-for children, thewait()
,waitid()
, orwaitpid()
function shall fail and seterrno
to [ECHILD
].Otherwise:
Status information (see Status Information) shall be generated.
The calling process shall be transformed into a zombie process. Its status information shall be made available to the parent process until the process' lifetime ends.
...
In short, to prevent child processes from becoming zombie processes, the simplest way is to call sigignore( SIGCHLD );
UPDATE
That does impact the ability to wait for any child process, which may not be desired. The setsid()
library function allows a process to disassociate itself from its parent:
pid_t child = fork();
if ( ( pid_t ) 0 == child )
{
int rc = setsid();
rc = execv(...);
}
else ...
The disassociated child process doesn't create a zombie nor send SIGCHLD
to the parent process on my installed instance of Solaris 11.2.
This is an abbreviated daemonization of a "fire-and-forget" child process, only doing what is necessary to prevent creating a zombie or sending SIGCHLD
to the parent process. For a much fuller daemonization procedure, see Linux daemonize
Ignoring SIGCHLD
or installing a sighandler for SIGCHLD
with the SA_NOCLDWAIT
flag on prevents all children from becoming zombies (/ being wait
-able).
To do it for a single child, you can either use Linux's clone()
without the SIGCHLD
flag or you can double fork
(or vfork
if you know how to do that safely) when starting the child. The child can then immediately _exit(0)
and be wait
-ed upon by its parent and the grandchild can go on to do the actual work (reparented to init
as you say).
(A slight extension of the double fork would be full demonization where the child or the grandchild also calls setsid to create a new session, a new process group and to detach from the controlling terminal. Setsid alone won't prevent the child from becoming a zombie. It will just hide the zombie from ps
in its default settings where ps
only shows processes in the current terminal-controlling sesssion.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With