Most recent kernel where this bug did not occur: ? Distribution: Debian unstable Hardware Environment: i686 SMP (single HyperThreaded CPU) Software Environment: glibc 2.6.1 Problem Description: sigwait() does not wake up upon delivery of SIGCHLD (or perhaps drops SIGCHLD silently??), even though SIGCHLD is properly blocked beforehand. Steps to reproduce: Compile and run the snippet below. It should terminate after a sec, but does not. Note that the problem only seem to occur when NOT debugging; the problem is not reproducible under strace/gdb/ltrace. ----8<--------8<--------8<--------8<---- #include <unistd.h> #include <sys/wait.h> #include <pthread.h> #include <signal.h> #include <stdlib.h> int main (void) { sigset_t set; pid_t pid; int signum; sigemptyset (&set); sigaddset (&set, SIGCHLD); pthread_sigmask (SIG_BLOCK, &set, NULL); if (fork () == 0) { sleep (1); exit (0); } sigwait (&set, &signum); return 0; }
Roland (cc'ed) can answer authoritatively, but I don't think we have a bug. Please install a signal handler for SIGCHLD, and the program will work. The reason is that the kernel doesn't really send a signal if it is ignored, or it is SIG_DFL and the default action is "do nothing". This means that such a signal can't be recieved by sys_rt_sigtimedwait().
I think is a bona fide bug. When a signal is set to SIG_IGN, it's true that the signal may be dropped at generation time and never recorded. But POSIX does not allow this for signals set to SIG_DFL, even when the default action for the signal is to ignore it. In this case, the rule when the signal is blocked is that it must become pending--this allows a sigaction call before unblocking the signal to change its action. Linux does this correctly for blocked signals in normal cases, but not while a sigwait is in progress. I'll post a fix.
On 11/12, bugme-daemon@bugzilla.kernel.org wrote: > > http://bugzilla.kernel.org/show_bug.cgi?id=9347 > > > > > > ------- Comment #2 from roland@redhat.com 2007-11-12 13:59 ------- > I think is a bona fide bug. When a signal is set to SIG_IGN, it's true that > the signal may be dropped at generation time and never recorded. But POSIX > does not allow this for signals set to SIG_DFL, even when the default action > for the signal is to ignore it. In this case, the rule when the signal is > blocked is that it must become pending--this allows a sigaction call before > unblocking the signal to change its action. Linux does this correctly for > blocked signals in normal cases, but not while a sigwait is in progress. OK, I have to agree. Yes, sigwait() unblocks the signal, but this is just the detail of implementation. Also, I missed the fact we don't discard the signals which were sent before sigwait(), this of course means it is strange to drop them when sigwait() started. Thanks for correcting me. > I'll post a fix. Yes, I believe testing blocked|real_blocked will do the trick. Can we close this bug?
Fixed by commit 325d22df7b19e0116aff3391d3a03f73d0634ded I can't close the bug without taking ownership.
I did test the program supplied above and it reproduces the bug before my fix, and no longer does after, and Linus has put the change in. So time to close it.