Strangeness with signals

Simon Kirby
2005-09-27T23:20:35Z

[-- Attachment #1: Type: text/plain, Size: 1805 bytes --]

Hi folks,

I'm not sure if this is buggy, strange or just perfectly normal
behaviour. I was trying to write an application that does some simple
network performance polling with setitimer() and also keeps a look out
for SIGWINCH to see if the window size changes. I was interested to
find out that when I resized the window, the signal was never noticed.
Even more interesting is the fact that if I run it in strace or even
GDB to figure out what's going on, it works!

I've simplified the program to this simple test case which will show
clearly that (both on 2.4 and 2.6), SIGALRM and SIGHUP are received as
expected but that without setting a special sa_sigaction handler,
SIGWINCH and SIGCHLD don't appear to wake up sigwaitinfo(). Also,
applying a sigaction() to all signals won't change the situation unless
an sa_sigaction is set; sa_handler does not appear to change anything.

Some people mentioned blocked and ignored signals, but as can be seen in
this example, differing behaviour can be seen across signals even with
all signals blocked and ignored.

Usage:

gcc -o sigweird sigweird.c && ./sigweird

In another window, "killall -WINCH sigweird" and "killall -HUP sigweird".
Note the differing behaviour. :)

Try running "strace sigweird" or "strace -p `pidof sigweird`". Note
how the behaviour changes.

Try changing the second "#if 0" to "#if 1" to enable setting the same
signal handlers exactly for all of the signals. Note that the behaviour
does not change.

Try changing the first "#if 0" to "#if 1". Note how all signals now
appear to behave similarly, with or without strace/GDB.

CHLD and WINCH seemed to be dropped without an sa_sigaction while HUP and
ALRM seem to work as expected. This might have something to do with
their default behaviour.

Broken? Bizarre?

Simon-

[-- Attachment #2: sigweird.c --]
[-- Type: text/x-csrc, Size: 1563 bytes --]

#include <sys/types.h>
#include <sys/time.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <string.h>

void some_signal_handler(int si_number, siginfo_t *siginfo, void *bits)
{
}

int main(int argc,char *argv[])
{
int r;
struct itimerval it;
sigset_t sigset;
siginfo_t siginfo;

#if 0
#define THE_SIGACTION some_signal_handler
#else
#define THE_SIGACTION NULL
#endif

#if 0
struct sigaction sa;

memset(&sa,0,sizeof(sa));
sa.sa_handler = SIG_IGN;
sa.sa_sigaction = THE_SIGACTION;
sigaction(SIGALRM,&sa,NULL);

memset(&sa,0,sizeof(sa));
sa.sa_handler = SIG_IGN;
sa.sa_sigaction = THE_SIGACTION;
sigaction(SIGWINCH,&sa,NULL);

memset(&sa,0,sizeof(sa));
sa.sa_handler = SIG_IGN;
sa.sa_sigaction = THE_SIGACTION;
sigaction(SIGCHLD,&sa,NULL);

memset(&sa,0,sizeof(sa));
sa.sa_handler = SIG_IGN;
sa.sa_sigaction = THE_SIGACTION;
sigaction(SIGHUP,&sa,NULL);
#endif

sigemptyset(&sigset);
sigaddset(&sigset,SIGALRM);
sigaddset(&sigset,SIGWINCH);
sigaddset(&sigset,SIGCHLD);
sigaddset(&sigset,SIGHUP);
sigprocmask(SIG_BLOCK,&sigset,NULL);

memset(&it,0,sizeof(it));
it.it_interval.tv_sec = 2;
it.it_interval.tv_usec = 0;
it.it_value.tv_sec = it.it_interval.tv_sec;
it.it_value.tv_usec = it.it_interval.tv_usec;
setitimer(ITIMER_REAL,&it,NULL);

sigemptyset(&sigset);
sigaddset(&sigset,SIGALRM);
sigaddset(&sigset,SIGWINCH);
sigaddset(&sigset,SIGCHLD);
sigaddset(&sigset,SIGHUP);

for (;;) {
r = sigwaitinfo(&sigset,&siginfo);
if (r > 0)
printf("Received signal %u.\n",siginfo.si_signo);
}

exit(0);
}