Delfer has asked for the wisdom of the Perl Monks concerning the following question:

Another question is about the signal CHLD. I writed a script.It uses signal CHLD to trap the death of child then do something on it.BUT if two children end simultaneously(It's possible to take place for my script), the script is broken by some unknown reason.That's not my purpose. How do I successfully solve this problem.Thank you.

Replies are listed 'Best First'.
Re: CHLD signal?
by perlmonkey (Hermit) on May 07, 2000 at 23:57 UTC
    lhoward is right, and I think this is mentioned in Advanced Perl Programming. Try to keep all SIG handlers as small as possible, or else you will start getting weird core dumps. Here is the sig function I commonly use. You should be able to do very simple stuff in the while loop, and it should handle mutiple children dying at the same time.
    use POSIX; %SIG{'CHLD'} = \&REAPER; #signal routine to wait for all children (prevents zombies) sub REAPER { #WNOHANG means to return immediately if no child has exited. while ((waitpid(-1, WNOHANG)) >0 ) { } #reset the sig for the next child to die; $SIG{CHLD} = \&REAPER; }
    Perhaps if you can share a bit of your code we can give you some ideas.
Re: CHLD signal?
by lhoward (Vicar) on May 07, 2000 at 17:56 UTC
    There could be a few things going on. But If I had to guess I'd say that your SIGCHLD signal-handler is non-re-entrant (see this earlier discussions on non-reentrance Malloc is not reentrant?).

    Your best bet may be to trim down your SIGCHLD handler as much as possible. If there's no-way getting around doing a bunch of work when your child process ends, you may want to consider doing something like queing the info you need from the deceased child process and do the work a little later on (once you're out of the signal-handler).

    Seeing the code for your SIGCHLD handler (or giving us an idea of what it is doing) may help the Monestary assist you in your quest.

Re: CHLD signal?
by chromatic (Archbishop) on May 08, 2000 at 04:32 UTC
    I would do one thing differently from perlmonkey, in that I'd reinstall the signal handler as the first order of business in the REAPER function:
    $SIG{CHLD} = \&REAPER; # waitpid code goes here
    merlyn will correct me if I'm wrong, but I do it this way just in case another SIGCHLD comes in -- if there's nothing in place *within* my signal handler to catch the signal, it could kill the program altogether. Just a little paranoia.
      The Perl Cookbook advises being paranoid and always reinstalling your SIG handler as the first step of your signal handler except in the case of SIGCHLD for the following reason:

      If you re-install the SIGCHLD handler before wait or waitpid gets its information from the OS's process table you risk the child becoming a zombie. Recomended is the following: Loop in the SIGCHLD handler and only re-install the SIGCHLD handler after the loop is complete (code below taken from Perl Cookbook).

      $SIG{CHLD}=\&REAPER; sub REAPER{ my $stiff; while(($stiff = waitpid(-1,&WNOHANG))>0){ # do something with $stiff if you want } $SIG{CHLD}=\&REAPER; }
      This is necessary because most OSes will not queue up signals so if 2 are sent to your process at aprox the same time your process may behave as if it has received only 1.

      This may point to a possible solution to the original problem:

      $SIG{CHLD}=\&REAPER; sub REAPER{ $SIG{CHLD}='IGNORE'; my $stiff; while(($stiff = waitpid(-1,&WNOHANG))>0){ # do something with $stiff if you want } $SIG{CHLD}=\&REAPER; }

      For a detailed discussion see sections 6.17 thru 6.19 (espscially 6.19) of the Perl Cookbook.