What is the difference between the different values ​​of $ SIG {CHLD}?

What is the difference between these settings?

$SIG{CHLD} = 'IGNORE' $SIG{CHLD} = 'DEFAULT' $SIG{CHLD} = '' $SIG{CHLD} = undef 

According to the "Advanced Programming on UNIX, Second Edition" in Figure 10.1, the default value of SIGCHLD is "ignored."

If "ignore" means "SIG_IGN", then no child will ever become a zombie, and it is not.

From there it does not become clearer:

If a process specifically sets its location to SIG_IGN, the children of the calling process will not generate zombie processes. Note that this is different from the default action (SIG_DFL), which should be ignored from Figure 10.1. Instead, upon completion, the status of these child processes is discarded.

I find it difficult to understand how various values ​​(or undefined non-value) affect. So far, the solution has been to rotate these options until I get the desired behavior, and I would better understand how each value determines the behavior of the signal.

Behavior: the child process calls the "system" or uses inverse elements that create another child, and the signal usually falls on the wrong (parent) handler. Installing a local handler may work, but I don’t understand which value is most appropriate if I want the signal from grand-child to do nothing.

Can someone please light me up?

UPDATE: Based on ikegami feedback, I did some specific tests. The behavior, at least in part, is platform dependent.

Consider the following snippet:

 $SIG{CHLD} = sub { while( ( my $child = waitpid( -1, &WNOHANG ) ) > 0 ) { print "SIGNAL CHLD $child\n"; } }; my $pid = fork(); if( ! $pid ) { system( 'echo Grandchild PID = $$' ); sleep 2; exit; } print "Child PID = $pid\n"; sleep 5; 

Perl 5.8.6 on Solaris 10 will display "SIGNAL CHLD" messages for the PID call to system (). Doing everything, even as trivial as

local $ SIG {CHLD};

in the child will suppress these messages.

On every other taste that I tried, the reaper never sees a child.

+7
source share
4 answers

See %SIG .

$SIG{CHLD} = 'IGNORE'; causes your process to ignore SIGCHLD signals.

$SIG{CHLD} = 'DEFAULT'; forces your process to process SIGCHLD signals, as this might not spoil your $SIG{CHLD} or equivalent. According to kill (1), a process on my system ignores SIGCHLD by default

$SIG{CHLD} = ''; and $SIG{CHLD} = undef; are not valid.

As for reaping, the children of the parent whose SIGCHLD handler is explicitly set to IGNORE will be automatically retrieved by the system.

 $ perl -e' my $pid = fork; if (!$pid) { sleep(1); exit; } sleep(2); system "ps -o pid,stat,command $pid"; ' PID STAT COMMAND 14667 ZN+ [perl] <defunct> $ perl -e' $SIG{CHLD}="IGNORE"; my $pid = fork; if (!$pid) { sleep(1); exit; } sleep(2); system "ps -o pid,stat,command $pid"; ' PID STAT COMMAND $ 
+9
source

There are two ways to avoid creating zombie processes:

  • explicitly set $SIG{CHLD}='IGNORE'
  • explicitly wash dead children with wait or waitpid calls (this can be done inside the SIGCHLD handler, but this is not necessary)

Setting $SIG{CHLD}='IGNORE' the SIGCHLD trap at the operating system level, clearing the child process, not even signaling your Perl program.

Any other setting, including 'DEFAULT' , undef , "" , sub {} , 'some_function_name_that_doesnt_even_exist' , will cause the signal to be delivered to Perl and the child will not be automatically extracted.

Having assembled the process yourself using wait and waitpid , you can get additional information, such as the exit status of the child process, and (more or less) the order in which the child processes ended. If $SIG{CHLD} set to 'IGNORE' , wait and waitpid always return -1 and do not set $? .

SIGCHLD , if any, is always delivered to the process that spawns the child process, so I don’t think you correctly said that SIGCHLD from the grandson process (from the system call in the child process) gets into the parent process. What probably happens is that your child process inherits a signal handler from its parent process.

system and backticks (on most systems) will generate SIGCHLD upon completion and set the value to $? with the exit status of the team. But Perl will use these subprocesses itself, and you will not be able to capture the process id of the system call or callback with wait or waitpid .

+12
source

There are two different meanings for "ignore", and they occur at two different points in the evaluation.

The first use is whether to transmit a signal at all. When a child process processes outputs, it is usually held by the operating system, and the CHLD signal is sent to its parent element. When setting $ SIG {CHLD} to 'IGNORE', it tells the system not to generate a signal at all, but simply allows the child process to exit. The parent has no way to get information about the child process, and no zombies will receive it.

But if $ SIG {CHLD} is something other than "IGNORE", it means that the signal is passed to the parent process, at this moment there is either a custom signal handler or the default signal handler, and the default handler will differ in different systems or even versions of the same operating system. The manual page of the book and signal (7) says what happens by default if the signal is delivered to the parent process (ie, the Handler is not set to "IGNORE"). So, the second use of ignoring is related to what action needs to be taken for the delivered signal . For example, SIGINT will cause your process to terminate, and SIGSTOP will cause your process to β€œpause,” although custom signal handlers change these actions by default.

For the SIGCHLD signal, the default is to β€œignore” it, but in this use it simply means that the process (parent) simply continues to execute normally while the child process is waiting (i.e. without interrupting or interrupting the parent process). Then you can wait () to get information and avoid the zombies.

+2
source

$ SIG {CHLD} = 'IGNORE'

This is passed to the OS as SIG_IGN, which, according to the OS documents, causes the child processes to end, becoming a zombie (or telling their exit code to the parent).

$ SIG {CHLD} = 'DEFAULT'
$ SIG {CHLD} = ''
$ SIG {CHLD} = undef

They are all the same at the OS level (they will trigger a signal () using SIG_DFL). However, some perl packages, especially AnyEvent :: child, will not work if $ SIG {CHLD} is set to "DEFAULT".

+1
source

All Articles