I wanted to understand the behavior of signals on fork. I wrote a small program to catch SIGCHLD with epoll_wait but when I do a "kill -9" on the forked child, I am not getting any signal and the child is in defunct state (I have a handler that does a wait()).
Here is the code.
//....
sigemptyset(&mask);
sigaddset(&mask, SIGCHLD);
pthread_sigmask(SIG_BLOCK, &mask, NULL);
signal_fd = signalfd(-1, &mask, 0);
memset(&tev, 0, sizeof(tev));
tev.events = EPOLLIN | EPOLLONESHOT;
tev.data.fd = signal_fd;
epoll_ctl(efd_, EPOLL_CTL_MOD, signal_fd, &tev);
while (1) {
child_pid_ = fork();
if (child_pid_ == 0) {
close(signal_fd);
close(efd_);
make_grand_child(); //just sleeps in while(1) and never returns.
} else {
memset(&event, 0, sizeof(event));
while (1) {
epoll_wait(efd_, &event, 1, -1);
deliver_events = (event.events & EPOLLERR|EPOLLHUP|EPOLLIN|EPOLLONESHOT);
if (deliver_events) {
parent_sig_handler(SIGCHLD);
break;
}
}
}
}
UPDATE:
Used a EPOLL_CTL_MOD without first doing an add (EPOLL_CTL_ADD). After I changed that, it worked like a charm.
The default disposition of SIGCHLD is to be ignored. Blocking the signal won't change the disposition it just gives
signalfd
the opportunity to process it synchronously.Add a signal handler for SIGCHLD with
signal
orsigaction
. It doesn't have to do anything since it won't be executed. Because SIGCHLD is blocked,signalfd
will consume and process it before the handler.