Handling Multiple Sigchld

Handling multiple SIGCHLD

On Linux, multiple children terminating before you read a SIGCHLD with signalfd() will be compressed into a single SIGCHLD. This means that when you read the SIGCHLD signal, you have to clean up after all children that have terminated:

// Do this after you've read() a SIGCHLD from the signalfd file descriptor:
while (1) {
int status;
pid_t pid = waitpid(-1, &status, WNOHANG);
if (pid <= 0) {
break;
}
// something happened with child 'pid', do something about it...
// Details are in 'status', see waitpid() manpage
}

I should note that I have in fact seen this signal compression when two child processed terminated at the same time. If I did only a single waitpid(), one of the children that terminated was not handled; and the above loop fixed it.

Corresponding documentation:

  • http://man7.org/linux/man-pages/man7/signal.7.html "By contrast, if multiple instances of a standard signal are delivered while that signal is currently blocked, then only one instance is queued"
  • http://man7.org/linux/man-pages/man3/sigwait.3p.html "If prior to the call to sigwait() there are multiple pending instances of a single signal number, it is implementation-defined whether upon successful return there are any remaining pending signals for that signal number."

Handling multiple SIGCHLD

On Linux, multiple children terminating before you read a SIGCHLD with signalfd() will be compressed into a single SIGCHLD. This means that when you read the SIGCHLD signal, you have to clean up after all children that have terminated:

// Do this after you've read() a SIGCHLD from the signalfd file descriptor:
while (1) {
int status;
pid_t pid = waitpid(-1, &status, WNOHANG);
if (pid <= 0) {
break;
}
// something happened with child 'pid', do something about it...
// Details are in 'status', see waitpid() manpage
}

I should note that I have in fact seen this signal compression when two child processed terminated at the same time. If I did only a single waitpid(), one of the children that terminated was not handled; and the above loop fixed it.

Corresponding documentation:

  • http://man7.org/linux/man-pages/man7/signal.7.html "By contrast, if multiple instances of a standard signal are delivered while that signal is currently blocked, then only one instance is queued"
  • http://man7.org/linux/man-pages/man3/sigwait.3p.html "If prior to the call to sigwait() there are multiple pending instances of a single signal number, it is implementation-defined whether upon successful return there are any remaining pending signals for that signal number."

how to handle multiple signals by order of arrival in C

As long as you use sigaction and not the problematic signal function to setup your signal handler, you can be sure (unless you specify otherwise) that your signal handler will not be interrupted by another occurrence of the signal it's handling. However it's possible if many child processes all die at once that you might not receive a signal for each. On each SIGCHLD, the normal procedure is to attempt to wait for children until your wait-family function says there are no children left to wait for. At this point, you can be sure that any further child termination will give you a new SIGCHLD.

Also, since you're very restricted as to what functions you can use from a signal handler, you'd probably be better off just setting some sort of flag or otherwise notifying your main program loop that it should check for terminated children via one of the wait interfaces.

And finally, yes, a SIGCHLD is delivered regardless of the reason the child terminated - including if it was killed by the parent.



Related Topics



Leave a reply



Submit