Search code examples
clinuxsignals

master error when multiple signal are sent


I got this issue:

I made a program in c, where the main process creates some child process, and these, after a while, are able to send a signal to the main process:

the signal is sent with this code:

kill(getppid(), SIGUSR1);

and the main process, in the while loop is waiting the SIGUSR1 message...

everything is fine, but if I increase the child number and automatically the possibility to have more signals in the same time, the program crash printing the message:

User defined signal 1

the main code is like this:

void signalHandler(int sig, siginfo_t* info, void* vp) {
    if (sig == SIGUSR1) {
        printf("SIGUSR1 has arrived\n");
    } else if (sig == SIGUSR2) {
        printf("SIGUSR2 has arrived\n");
    }
}

int main(int argc, char const *argv[]) {
    struct sigaction action, old_action;

    memset(&action, 0, sizeof(struct sigaction));
    action.sa_sigaction = signalHandler;
    sigemptyset(&action.sa_mask);
    action.sa_flags = SA_RESTART | SA_NODEFER;

    while (1) {
        sigaction(SIGUSR1, &action, &old_action);
        sigaction(SIGUSR2, &action, &old_action);
    }
}

I think the problem is that the signal is sent when the master is still working on the previous signal...but how can I do to fix this thing

thank you very much


Solution

  • It means that the child is sending the signal before the parent process was able to call sigaction() to configure the signal handler. When this happens, the default signal reaction to SIGUSR1 terminates the program:

    SIGUSR1      P1990      Term    User-defined signal 1
    

    https://man7.org/linux/man-pages/man7/signal.7.html

    However, there are many problems with your code. printf() is not safe to be called inside a signal handler (it's AS-Unsafe as defined by POSIX):

    https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/functions/V2_chap02.html#tag_15_04_03

    Also, using SA_NODEFER may create nested signals (another signal handler is called while some signal handler is running) but your program does not protect against a flood. Given enough children this will generate a stack overflow. Finally, the main program keeps running a non-stop infinite loop reconfiguring the signals, while it should have configured them only once outside the loop and blocked inside the loop (for example sigwait() or pselect()):

    https://man7.org/linux/man-pages/man2/select.2.html

    Finally, if you expect to run a large number of children that might flood the parent with signals, then it would be better to use the real time signal generation function (sigqueue()) rather than kill(). The difference is that with sigqueue(), all signals are queued and SA_NODEFER is not necessary to avoid discarding signals while some other signal handler is running:

    https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/functions/V2_chap02.html#tag_15_04_02

    Final conclusion: the code should be completely rewritten.