I have a fairly big application under care. As part of its job it spawns some child processes and needs to monitor their state (running, crashed).
Child process deaths were detected by setting signal handler for SIGCHLD
using signal(2)
. Some time ago I migrated it to signalfd(2)
. What I did was simple:
- removed the signal handler for
SIGCHLD
- blocked
SIGCHLD
and created asignalfd(2)
to captureSIGCHLD
My problem is that the file descriptor I created does not seem to capture SIGCHLD
. However, if I ignore the return value of read(2)
call on that descriptor and call waitpid(-1, &status, WNOHANG)
I can obtain the information about exited child processes. So it looks like the notification is delivered but my signalfd(2)
descriptor just ignores it.
I made sure to have exactly one place in the program where read(2)
is called on the signalfd(2)
descriptor, exactly one place where waitpid(2)
is called, and exactly one place were the signal handling is set up.
The setup code looks like this:
sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask, SIGCHLD);
sigprocmask(SIG_BLOCK, &mask, nullptr);
int signal_fd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC);
if (signal_fd == -1) {
/* log failure and exit */
} else {
/* log success */
}
The reading code looks like this:
signalfd_siginfo info;
memset(&info, 0, sizeof(info));
if (read(signal_fd, &info, sizeof(info)) == -1) {
/*
* Log failure and return.
* The file descriptor *always* returns EAGAIN, even in
* presence of dead child processes.
*/
return;
}
if (info.ssi_signo == SIGCHLD) {
int status = 0;
int child = waitpid(-1, &status, WNOHANG);
/*
* Process result of waitpid(2). The call is successful even if
* the read of signalfd above returned an error.
*/
}
What am I doing wrong?
Edit: The problem is that read(2)
fails with EAGAIN
even if there are dead child processes ready to be waitpid(2)
-ed, which means that a SIGCHLD
must have been delivered to my master process. I know that read(2)
may return EAGAIN
for non-blocking file descriptors and the code accounts for that.
select
orpoll
.