What is the difference between these settings?
$SIG{CHLD} = \'IGNORE\'
$SIG{CHLD} = \'DEFAULT\'
$SIG{CHLD} = \'\'
$SIG{CHLD} = undef
There are two ways to avoid creating zombie processes:
$SIG{CHLD}='IGNORE'wait or waitpid calls (this could be done inside a SIGCHLD handler, but it need not be)Setting $SIG{CHLD}='IGNORE' traps the SIGCHLD at the operating system level, cleaning up the child process without even signalling 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 reaped automatically.
By reaping the process yourself with wait and waitpid, you can get additional information like the exit status of the child process, and (more-or-less) the order in which the child processes finished. If $SIG{CHLD} is set to 'IGNORE', wait and waitpid always return -1 and don't set $?.
The SIGCHLD, if any, is always delivered to the process that spawned the child process, so I don't think you are correct to say that a SIGCHLD from a grandchild process (from a system call in a child process) is caught in the parent process. Probably what is going on is that your child process inherits the signal handler from its parent process.
system and backticks will (on most systems) generate a SIGCHLD on completion and will set the $? value with the command's exit status. But Perl will reap these subprocesses itself, and you won't be able to capture the process id of a system or backticks call with wait or waitpid.