0

I have the following question: can I use a signal handler for SIGCHLD and at specific places use waitpid(3) instead?

Here is my scenario: I start a daemon process that listens on a socket (at this point it's irrelevant if it's a TCP or a UNIX socket). Each time a client connects, the daemon forks a child to handle the request and the parent process keeps on accepting incoming connections. The child handling the request needs at some point to execute a command on the server; let's assume in our example that it needs to perform a copy like this:

cp -a /src/folder /dst/folder

In order to do so, the clild forks a new process that uses execl(3) (or execve(3), etc.) to execute the copy command.

In order to control my code better, I would ideally wish to catch the exit status of the child executing the copy with waitpid(3). Moreover, since my daemon process is forking children to handle requests, I need to have a signal handler for SIGCHLD so as to prevent zombie processes from being created.

In my code, I setup a signal handler for SIGCHLD using signal(3), I daemonize my program by forking twice, then I listen on my socket for incoming connections, I fork a process to handle each coming request and my child-process forks a grand-child-process to perform the copy, trying to catch its exit status via waitpid(3).

What happens is that SIGCHLD is caught by my handler when a grand-child-process dies, before waitpid(3) takes action and waitpid(3) returns -1 even though the grand-child-process exits with success.

My first thought was to add:

signal(SIGCHLD, SIG_DFL);

just before forking the child process to handle my connecting clients, without any success. Using SIG_IGN didn't work either.

Is there a suggestion on how to make my scenario work?

Thank you all for your help in advance!

PS. If you need code, I'll post it, but due to its size I decided to do so only if necessary.

PS2. My intention is to use my code in FreeBSD, but my checks are performed in Linux.

EDIT [SOLVED]:

The problem I was facing is solved. The "unexpected" behaviour was caused by my waitpid(3) handling code which was buggy at some point.

Hence, the above method can indeed be used to allow for signal(3) and waitpid(3) coexistence in daemon-like programs.

Thanx for your help and I hope that this method helps someone wishing to accomplish such a thing!

mamalos
  • 97
  • 10
  • Something else is happening. The grandparent will not get a SIGCHLD when the grandchild terminates. Only the immediate parent will. Perhaps it is the parent inheriting the signal disposition from the grand parent that is processing the SIGCHLD. Did you try setting SIG_IGN just after the fork? – William Pursell Oct 04 '13 at 16:22
  • William, thank you for your help! You are right in your statement. The grandparent was not catching its grandchild's SIG_CHLD rather its child's. I misread my output. As far as which behaviour should be set to singal(3) in order to allow waitpid(3) take the action, SIG_DFL is the answer, in general; if I used SIG_IGN instead, waitpid(3) would be unable to get the exit status because signal(3) would catch it first and since it would ignore it, waitpid(3) would return -1. Thanx again! – mamalos Oct 08 '13 at 10:08
  • If you ignore SIGCHLD, waitpid returns -1 because you have no children! The semantics are...a little weird. When you ignore SIGCHLD, any children that you fork are immediately adopted by init rather than remaining your own, so waitpid behaves as if you have no children. – William Pursell Oct 08 '13 at 11:00
  • My previous comment is not correct. The linux man page for sigaction states that "historical BSD and System V behaviors for ignoring SIGCHLD differ", and perhaps I am remembering BSD semantics. On my Linux box, the children are yours but do not become zombies if SIGCHLD is ignored when the child terminates. – William Pursell Oct 09 '13 at 16:26

0 Answers0