3

If I send multiple subsequent Hangup signals to the following program, only two of them would be handled and the rest will be ignored:

#include <stdio.h>
#include <unistd.h>
#include <signal.h>

int id;
void handler(int s)
{
    id++;
    int i;
    for(i=0; i<3; i++)
    {
        printf("Sig %d\n", id);
        sleep(2);
    }
}

int main()
{
    int i;
    signal(SIGHUP, handler);
    for( i=0; ; i++ )
    {
        printf("%d\n", i);
        sleep(1);
    }
    return 0;
}

I use the following command to send signal to the process:

kill -l {#process}

If I run the above command three times consecutively, the 3rd signal will be ignored as in the following output:

0
1
2
3
4
5
6
7
Sig 1
Sig 1
Sig 1
Sig 2
Sig 2
Sig 2
8
9
10
11
12

Is there any way to catch the third signal too?

B Faley
  • 17,120
  • 43
  • 133
  • 223
  • 2
    Sleeping within a signal handler is questionable. Does it have to be there? – wallyk Dec 28 '11 at 08:40
  • @wallyk According to the manual page, POSIX.1-2004 requires `sleep` to safe within a signal handler. – Some programmer dude Dec 28 '11 at 08:45
  • normal signals are not queued, you'll miss some no matter what you do. – nos Dec 28 '11 at 09:03
  • 1
    note that printf inside async signal handler is not safe! – gby Dec 28 '11 at 09:40
  • Must understand what signals communicate: when the application's eventually interrupted, it knows - the first time - that >= 1 events have happened since it was configured, and afterwards, >= 0 events have happened since it last exited. The signal handling can generally be written in a way that will work. Signal handlers generally should set a flag for non-async threads to consult: more race conditions. Core concept: at least one signal will arrive soonish after there's related work to be done, regardless of how many "sub-events" created or reaffirmed that work requirement. – Tony Delroy Dec 28 '11 at 09:55

2 Answers2

3

Normally, you can't do it with standard signals. Unix kernel generally queues up only one pending signal. If Sig2 and Sig3 are sent while process sleeping in Sig1 handler, they are merged.

You can use sigaction(2) to set up your signal handler and supply SA_NODEFER flag to it. It will allow to deliver new signal while still in signal handler. Make sure your handler is reenterant, it's error-prone solution.

Also there is POSIX.1b (POSIX.1-2001) extension called "real-time signals". Such signals can be queued multiple times, but SIGHUP isn't one of them. signal(7) on Linux states that real-time signals are numbered 33 (SIGRTMIN) to 64 (SIGRTMAX).

blaze
  • 4,326
  • 18
  • 23
2

On Linux, pending signals are represented with only one bit. This means that if multiple signals are generated while the handler is already running, then it will only be called once more.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • when I enter `ulimit -a` on my linux, I can see that `pending signals` has a default value of 16383. I tested it also with `getrlimit` and resource name `RLIMIT_SIGPENDING` (it is again 16383). So how linux handles this number of pending signals with only one bit? – saeedn Dec 28 '11 at 09:43
  • @saeedn That's the total number of signals that can be pending per user (actually per "real user ID") per process. For a single signal, per process, only one signal of each type can be pending. – Some programmer dude Dec 28 '11 at 09:50