Bug 9347

Summary: SIGCHLD not waking up sigwait
Product: Process Management Reporter: R (rdenis)
Component: OtherAssignee: Roland McGrath (roland)
Status: CLOSED CODE_FIX    
Severity: normal CC: oleg, roland
Priority: P1    
Hardware: All   
OS: Linux   
Kernel Version: 2.6.23.1 Subsystem:
Regression: --- Bisected commit-id:

Description R 2007-11-11 10:44:26 UTC
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;
}
Comment 1 Oleg Nesterov 2007-11-12 07:28:06 UTC
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().
Comment 2 Roland McGrath 2007-11-12 13:59:34 UTC
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.
Comment 3 Oleg Nesterov 2007-11-13 07:18:09 UTC
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?
Comment 4 Chuck Ebbert 2007-11-13 08:10:09 UTC
Fixed by commit 325d22df7b19e0116aff3391d3a03f73d0634ded

I can't close the bug without taking ownership.
Comment 5 Roland McGrath 2007-11-13 15:16:40 UTC
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.