Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using waitpid or sigaction?

I have understood that: 1) waitpid is used to wait for a child's death and then collect the SIGCHLD and the exit status of the child etc. 2) When we have a signal handler for SIGCHLD, we do some more things related to cleanup of child or other stuff (upto the programmer) and then do a waitpid so that the child will not go zombie and then return.

Now, do we need to have both 1 and 2 in our programs when we do a fork/exec and the child returns ? If we have both, the SIGCHLD is obtained first, so the signal handler is called first and thus its waitpid is called successfully and not the waitpid in the parent process code as follows:

my_signal_handler_for_sigchld
{
do something
tmp = waitpid(-1,NULL,0);
print tmp (which is the correct value of the child pid)
}

int main ()
{
  sigaction(SIGCHLD, my_signal_handler_for_sigchld)
  fork()
  if (child) //do something, return
  if parent // waitpid(child_pid, NULL,0); print value returned from this waitpid - it is -1
}

Appreciate if someone helps me understand this.

like image 598
Vin Avatar asked Jan 23 '12 17:01

Vin


2 Answers

You really don't need to handle SIGCHLD if your intent is to run a child process, do some stuff, then wait for it to finish. In that case, you just call waitpid when you're ready to synchronize. The only thing SIGCHLD is useful for is asynchronous notification of child termination, for example if you've got an interactive (or long-running daemon) application that's spawning various children and needs to know when they finish. However, SIGCHLD is really bad/ugly for this purpose too, since if you're using library code that creates child processes, you might catch the events for the library's children terminating and interfere with its handling of them. Signal handlers are inherently process-global and deal with global state, which is usually A Bad Thing(tm).

Here are two better approaches for when you have child processes that will be terminating asynchronously:

Approach 1 (select/poll event-based): Make sure you have a pipe to/from each child process you create. It can be either their stdin/stdout/stderr or just an extra dummy fd. When the child process terminates, its end of the pipe will be closed, and your main event loop will detect the activity on that file descriptor. From the fact that it closed, you recognize that the child process died, and call waitpid to reap the zombie.

Approach 2 (thread based): For each child process you create, also create a thread that will immediately call waitpid on the child process's pid. When waitpid returns successfully, use your favorite thread synchronization primitives to let the rest of the program know that the child terminated, or simply take care of everything you need to do in this waiter thread before it terminates.

Both of these approaches are modular and library-friendly (they avoid interfering with any other parts of your code or library code which might be making use of child processes).

like image 83
R.. GitHub STOP HELPING ICE Avatar answered Oct 13 '22 23:10

R.. GitHub STOP HELPING ICE


You need to call the waiting syscalls like waitpid or friends -eg wait4 etc- othewise you could have zombie processes.

You could handle SIGCHLD to be notified that some child ended (or stopped, etc...) but you'll need to wait for it later.

Signal handlers are restricted to call a small set of async-signal-safe-functions (see signal(7) for more). Good advice is to just set a volatile sig_atomic_t flag inside, and test it at later and safer places.

like image 23
Basile Starynkevitch Avatar answered Oct 13 '22 22:10

Basile Starynkevitch