http://www.perlmonks.org?node_id=927139


in reply to Best way to kill a child process

When a child dies, the O/S sends a CHLD signal to the parent to let it know that one of its kids has died. There will be an entry in the process table with the exit status of the child or children. This entry in the process table is called a "zombie". This entry takes up system resources and should be removed by the parent. You get rid of the entry by reading the status - most of the time nobody cares what this status is and it is thrown away. This is called "reaping" the child.

Anyway, the following line of code installs a signal handler for the CHLD signal. When that signal happens, the while loop runs which will read and discard the status of any children who have died (in general case might be more than one). It is ok to put this at the beginning of the code (which means that the child will get one of these too) - but it won't be getting CHLD signals itself.

$SIG{CHLD} = sub {while (waitpid(-1, WNOHANG) > 0){} };

Replies are listed 'Best First'.
Re^2: Best way to kill a child process
by Eliya (Vicar) on Sep 21, 2011 at 13:58 UTC
    $SIG{CHLD} = sub {while (waitpid(-1, WNOHANG) > 0){} };

    AFAIK, on most platforms (where reaping children is of concern), setting

    $SIG{CHLD} = 'IGNORE';

    should have the same effect, as it will make Perl autoreap terminated child processes.  And it's less clutter (you don't need to load/import WNOHANG from POSIX ...).

    See also perlipc.

      Good point about POSIX. My Perl servers usually have:
      use IO::Socket; use POSIX ":sys_wait_h";
      Yes, on some platforms, setting up the sigaction stuff to a NULL handler will cause an "auto reap", but AFAIK that is not universal - I'm thinking about the low level C calls that Perl would use. In this case, this is an issue of how the OS deals with sigaction() handlers, not how Perl itself works. Perl cannot do what C cannot do.

      I guess where I'm at is that the code I suggested is going to work on all platforms all the time (AFIK). I agree that 'IGNORE' will work on almost all platforms. I'm just not sure about the difference between "almost all" and "all". This detail probably doesn't matter for this app - it doesn't sound like a "general purpose" application as far as the OP is concerned.

      So YMMV. Setting "IGNORE" is not "wrong" and it is "easier".

      We both agree on the main issue here:
      that the right way to deal with this is to explicitly do something with the CHLD signal: either a) explicitly ignore it which hopefully will cause the OS to "autoreap" the child or b)set a simple subroutine like I suggested. As long as one of these options "works", then it will work in all cases of child death: a) if the child kills itself (maybe a via a die statement) or b)I kill my own child or c)somebody else kills it.

        We both agree on the main issue here: ...

        I think we also do agree on the potential side issues related to portability :)

        Just for the record: a quick peek into the sources turned up this (in util.c):

        #if defined(SA_NOCLDWAIT) && !defined(BSDish) /* See [perl #18849] */ if (signo == SIGCHLD && handler == (Sighandler_t) SIG_IGN) act.sa_flags |= SA_NOCLDWAIT; #endif

        and the referenced #18849 is an interesting read.  Essentially, the issue seems to revolve around if and how the sigaction() flag SA_NOCLDWAIT is implemented, i.e. its interactions with the varieties of the wait calls (wait(), wait4(), waitpid() ). And - as I read it - the upshot of it is that if SA_NOCLDWAIT could lead to problems, it isn't needed anyway — which is why the current implemention "mostly" works...

        Anyhow, I've used $SIG{CHLD} = 'IGNORE' on quite a few versions and brands of Unix-ish systems (AIX, HP-UX, IRIX, Linux, Solaris) and haven't had any issues with it yet (which is not to say there might not be potential problems on some other platform, of course).