Beefy Boxes and Bandwidth Generously Provided by pair Networks
Clear questions and runnable code
get the best and fastest answer

Protection from zombies

by nomis80 (Sexton)
on May 16, 2005 at 18:52 UTC ( #457523=perlquestion: print w/ replies, xml ) Need Help??
nomis80 has asked for the wisdom of the Perl Monks concerning the following question:

Hi, I'm trying to read the STDOUT and STDERR of a program using this code:
defined( my $pid = open( FROM_CHILD, "-|" ) ) or die "can't fork: $!"; if ($pid) { my @output = <FROM_CHILD>; close FROM_CHILD; } else { open STDERR, ">&STDOUT" or die "Can't dup STDOUT"; exec @command or die "can't exec: $!"; }
Problem is: sometimes, with a particular @command, the parent just idles while the child has become a zombie. I want to know if the above is safe from zombies, ie. it will *never* under any circumstance idle while the child is a zombie. The documentation of close says:
Closing a pipe also waits for the process executing on the pipe to complete, in case you want to look at the output of the pipe afterwards, and implicitly puts the exit status value of that command into $?.
It seems to me that the close should reap the zombie. So I guess the parent is idling while reading the child's output. How can it not idle? Why does it idle? Thanks!

Comment on Protection from zombies
Download Code
Re: Protection from zombies
by tlm (Prior) on May 16, 2005 at 20:37 UTC

    Update:What I wrote originally (below) is quite incorrect; the child process morphs into the exec'd process, retaining its PID and PPID. I had misconstrued some statements about exec in IPC::Open3. Many thanks++ to sgifford for the correction.

    Why do you say the "child has become a zombie"? You've exec'd that process; it is not a child of the parent anymore. The actual child presumably dies peacefully after the exec (assuming the call to exec succeeds, which says nothing about the fate of the exec'd process) and gets reaped automatically when FROM_CHILD is closed.

    If by "becoming a zombie" you mean that the exec'd process terminates abnormally, then all you need to do to avoid the idling is to time out the parent.

    the lowliest monk

      The new process does remain a child of the parent process across exec, since the open(FROM_CHILD,'-|') does an implicit fork. Here's an example:

      Below, notice that 20474 is the parent process, and its child 20476 is a zombie.

      freenet{swgsh}~ $ perl tmp/t3 & [2] 20474 freenet{swgsh}~ $ PARENT: PID is 20474 CHILD: PID is 20476, PPID is 20474 freenet{swgsh}~ $ ps PID TTY TIME CMD 12912 pts/0 00:00:00 bash 13286 pts/0 00:00:39 emacs 20474 pts/0 00:00:00 perl 20476 pts/0 00:00:00 bash <defunct> 20487 pts/0 00:00:00 ps
        Change your code, adding this single sequence:
        $SIG{CHLD} = sub { my $pid = waitpid(-1, 0); print ">> eof PID $pid -> $?\n"; };
        The new result is:
        PARENT: PID is 3433 CHILD: PID is 3434, PPID is 3433 >> eof pid 3434 -> 0
        Other samples and techniques at perlipc (find REAPER ;)

        Marco Antonio

Re: Protection from zombies
by mda2 (Hermit) on May 16, 2005 at 20:46 UTC
    Is a good pratice defines a signal handling when using fork, make a real waitpid or only 'IGNORE'...

    More details on fork.

      If you fork without ever waiting on your children, you will accumulate zombies. On some systems, you can avoid this by setting $SIG{CHLD} to "IGNORE" . See also perlipc for more examples of forking and reaping moribund children.

    Marco Antonio

Re: Protection from zombies
by sgifford (Prior) on May 16, 2005 at 22:01 UTC
    The code looks OK to me. Are you sure the child is a zombie? It shows up in the "defunct" process state? If it's not a zombie but just hung, see the advice elsewhere in this thread.
      Yes I'm sure it's a zombie. ps shows its state as Z and there is <defunct> after the command name.
Re: Protection from zombies
by kscaldef (Pilgrim) on May 16, 2005 at 23:07 UTC

    Can you strace the parent process and figure out if it's stuck in read() or wait()?

    Also, what is the particular command? Perhaps it fails to close STDOUT or STDERR under some circumstances?

      Not really. I can't reproduce the behavior unless I'm running as a CGI. The particular command is a shell script living in /etc/init.d.
        You can attach to an existing process with "strace -p ###".

        Can you give us more information about the init.d script?

        Try replacing the perl script with a shell script that runs strace on the original script, saving the output somewhere where you can look at it later.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://457523]
Approved by Corion
Front-paged by cazz
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others chanting in the Monastery: (13)
As of 2014-10-01 16:53 GMT
Find Nodes?
    Voting Booth?

    What is your favourite meta-syntactic variable name?

    Results (29 votes), past polls