Search code examples
c++linuxsignalssignal-handling

How to have more than two consecutive signals caught?


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?


Solution

  • 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).