Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

Re: open(KID, "-|") and wait()?

by robartes (Priest)
on Apr 10, 2003 at 13:38 UTC ( [id://249608]=note: print w/replies, xml ) Need Help??


in reply to open(KID, "-|") and wait()?

The answer is 'yes'. Zombies are created when a child has exited, but the parent has not wait()ed for it yet. Zombies are no good (they tend to eat nice friendly old ladies, for example). One way of ensuring that the parent always acts correctly upon the death of a child is installing a signal handler for SIGCHLD:
$SIG{'CHLD'}=sub { my $pid=wait(); if ($pid == -1 ) { print "SIGCHLD handler called without dead child.\n"; return; } print "Child $pid exited with $?\n"; }
That way, whatever else the parent is doing, it will normally always catch a SIGCHLD. The only exception to this is if the parent is in uninterruptible sleep (e.g. when it's waiting on an NFS op on a filesystem whose server has gone away) - then it becomes night of the living dead :).

Update: In the case of an open()ed child, as apparently the OP is using (bad robartes, I had parsed the snippet as a standard fork and exec), see Improv's remark. However, installing a SIGCHLD handler can never hurt, for example in the case where the child process abnormally (or even normally) terminates before the parent closes the filehandle.

CU
Robartes-

Replies are listed 'Best First'.
•Re: Re: open(KID, "-|") and wait()?
by merlyn (Sage) on Apr 11, 2003 at 14:15 UTC
    Your SIGCHLD handler leaves much to be desired.
    • You are interfering with the normal return of exit status, so a program checking for that for a particular child might not get what they need.
    • There's no guarantee (that I'm aware of) that promises one CHLD per dead child. Because of the way signals can be suspended or delivered, the CHLD signal really means "at some time in the recent past, one or more children went belly up". So you have failed to loop to grab multiple kids, and failed to ignore the possibility that the kid has already been reaped between the time the CHLD signal is initiated and your program runs to your handler.
    So, this is a bad general example, and a bad specific example. Sorry.

    -- Randal L. Schwartz, Perl hacker
    Be sure to read my standard disclaimer if this is a reply.

Re: Re: open(KID, "-|") and wait()?
by pemungkah (Priest) on Apr 11, 2003 at 15:22 UTC
    May I make another suggestion? This is originally from the Perl 4 Camel, but it actually works very well to prevent zombies:
     unless (fork) { # this is the child
        unless (fork) { # this is the grandchild
           exec "yourprogram";  # the detached process
                                # can also be perl code and exit(0)
        }   # exits when done
        # Back in the child
        exit 0;  # immediately terminates
     }
     wait; # gets rid of the terminated child immediately
    
    This works because the child process exits immediately and is wait()ed on immediately, so no zombie. The grandchild ends up as a child of init because its parent has exited, and init will take care of reaping the grandchild for you.
Re: Re: open(KID, "-|") and wait()?
by pg (Canon) on Apr 11, 2003 at 03:41 UTC
    "Zombies are created when a child has exited, but the parent has not wait()ed for it yet."

    We have a little bit misunderstanding of "zombie" here ;-) Zombie is actually a process still running, but we lost track of it. In other words, in the fork case, if the parent created a child that cannot exit on its own, say it has some sort of dead loop, whatever the dead loop is created by mistake or purposely, as a good practice, the parent process should kill the child process. Otherwise, the child becomes a zombie, as it will run forever, and it will have that seat in the process table forever.

    If a process exited, it will be removed from the process table, doesn't matter whether it is created by a parent process, or it runs on its own, as it is a process any way.

    Other than the zombie situation, there are also other cases you may want to waitpid on your child process. For example, a parent process keeps creating child processes, and delegating tasks to them at a high speed. If you don't waitpid() to control the number of child processes you created and still alive, you would soon see an error message saying that, you cannot create child process, as resource used up.

    In this case, you would keep a counter of running child processes, and when it reaches a predefined max, stop creating child process, and start waitpid(), until the number of running child processes drop below a safe line.

    Also a little comment about SIGCHLD. You cannot capture SIGCHLD on win32, so the approach is not fully portable.
      Q. How do you kill a zombie?
      A. You can't, it's already dead.

      Zombies are not running. They have terminated, but they have a living parent who either hasn't waited for them, or hasn't told the kernel that it doesn't want to do that.

      Zombies are created because child processes run asynchronously from their parents, and often terminate long before the parent has had a chance to call wait/waitpid on them. The kernel has to keep some minimal information about such child processes in the table so that the parent can have a chance to collect its status, but releases the memory & other resources they might be holding

      Zombie is actually a process still running, but we lost track of it. In other words, in the fork case, if the parent created a child that cannot exit on its own, say it has some sort of dead loop, whatever the dead loop is created by mistake or purposely, as a good practice, the parent process should kill the child process. Otherwise, the child becomes a zombie, as it will run forever, and it will have that seat in the process table forever.
      Ehm, I beg to differ. A zombie process is not what you describe here. A zombie process is one that is no longer running (it has exited), but its parent has not yet collected its exit status, so the kernel keeps it around in the process table. What you describe is a runaway process, or even a perfectly normal daemon. Something like inetd or sendmail fits your description, and I do not think many people will call those zombies.
      If a process exited, it will be removed from the process table, doesn't matter whether it is created by a parent process, or it runs on its own, as it is a process any way.
      Except when its a child process - it exits but stays in the process table unless its parent collects its status.

      Update: Added point about daemons.

      YAU: After a chatterbox conversation with pg, we've decided that we're both right - different sources mean different things with 'zombie process'. YMMV.

      CU
      Robartes-

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://249608]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others romping around the Monastery: (1)
As of 2024-04-25 19:43 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found