I'm writing a debugging utility, and I want to fork
a child while preventing that child's termination from triggering a SIGCHLD
to its parent. I still want other children to normally cause a SIGCHLD
upon termination.
I want to do this because I don't want the fork
to trigger an existing $SIG{CHLD}
handler, but I still want other children to trigger it. That is, I want to isolate my new child and I don't want it to interfere with management of existing children.
I'm wary of locally installing a custom $SIG{CHLD}
handler since I don't think I can properly detect when I should call the original handler. For instance, if I install a local $SIG{CHLD}
handler, then I'm guaranteed to receive a SIGCHLD
signal once I spawn a child and have the parent waitpid
for it to terminate. However, that SIGCHLD
won't indicate whether or not other children have terminated as well, so I can't be sure whether to call the original handler.
I researched that a process cannot change its parent pid. I'm not sure if changing the child's process group id or session id would be useful.
Is it even possible to prevent a specific child from triggering the SIGCHLD
on the parent? Am I forced to rely on the existing $SIG{CHLD}
handler to Do The Right Thing when it receives the SIGCHLD
signal for a child that it did not expect?
Although there may be a better way to implement that debugging utility (let me know if there is), I'm still wondering whether POSIX offers such fine-grained control over children, and am looking for a Perl solution to my dilemma.
You can't portably prevent the SIGCHLD
entirely, but if the signal handler is written properly you can prevent the waitpid from returning your debugging tool's pid by orphaning it.
use Signal::Mask;
sub start_background_child {
local $Signal::Mask{CHLD} = 1;
my $first = fork;
croak "fork failed: $!" if not defined $first;
if ($first) {
waitpid $first, 0;
return;
}
my $second = fork;
croak "fork failed: $!" if not defined $second;
exit if $second;
your_stuff_here();
}