tags:

views:

207

answers:

4

I got the PID of a process and I need to check if it is a zombie using POSIX system calls in C. How should I do that?

The problem I'm having is that I have a process and it forks into many children, the children all do execs and sometimes I want to do the exec in background so I can't really wait() the children that go in background. I could wait() periodically (once in my main loop) but I need to know which processes are zombie so my father process doesn't hang while waiting for children that are not going to end soon.

If you are curious, I'm building a unix shell and it is in the shell nature to have the children processes behaving asynchronously.

+3  A: 

But .. but .. the zombie is a child (at some level) and the process that's checking is a parent, right? So if you are concerned that a specific pid is a zombie why not just do a waitpid(2) with WNOHANG and get rid of it? Now, this will consume the exit status, so it may be a bad idea if some other process might want to really wait in the future.

DigitalRoss
Thanks, I didn't know that wait could return immediately with that option (btw, it's WNOHANG).
Hoffmann
+4  A: 

You can't check whether a process is a zombie with pure POSIX calls - except where you're the parent process, and reaping it with a wait family call. So you'll have to find a good place to wait for the child.

One option is to set a SIGCHLD handler and do a waitpid(0, &status, WNOHANG) there. Be sure to loop until it no longer finds any processes - if two children die within a short interval, you may only get one SIGCHLD.

Another option is to double fork - that is, fork(), have the child (call it child A) fork again, have the second child (child B) exec. Then child A immediately exits. Meanwhile the parent is wait()ing for child A. Once child A is gone, the system's init process will take care of reaping child B when it eventually dies. This method is simpler, but your shell will have no way of knowing when child B dies, so if you need that information, use the former method.

bdonlan
Thanks, I'm using your first suggestion. Your second suggestion is also interesting but it would be too much a hassle to implement and probably have performance hit due to double forking.
Hoffmann
Forking is very fast on many (most?) modern Unix-like systems and many tricks are employed (this is bread and butter for a kernel). Please don't judge it as "being slow" without a performance analysis.
pst
+1  A: 

You mention that you are building a Unix shell; you should read this: Proper handling of SIGINT/SIGQUIT

Teddy
Interesting paper. I question whether emacs runs in the half-cooked mode where key strokes still generate signals; most curses-based programs run with raw-mode terminal settings, in which case the terminal driver generates no signals to the program for SIGINT or SIGQUIT; the program just gets the keystrokes like any other control character.
Jonathan Leffler
Emacs does indeed get signals from keystrokes. It also reassigns C-g (^G) as the key for SIGINT, and last I checked it does some really nasty non-portable longjumping-out-of-signal-handlers stuff...
R..
+1  A: 

Normally, the shell checks for defunct children shortly before printing its prompt - using the waitpid(2) system call and the WNOHANG option as already discussed. You might also want a SIGCHLD handler - but you'd have to decide what you're going to do with the information if you're busy waiting for some foreground process to terminate and it is actually a background process that terminates.

This is only a minor variation on the currently selected answer.

Jonathan Leffler