Search code examples
csignalsinterrupt-handling

C Language: how do I evaluate the return value of a signal handler?


In the code I'm writing it would be very useful to check the return value of a signal handler to make sure the signal was received or not. So, for example, if I have something of this kind:

Message m;
sig_t s = signal(SIGALRM, sigalrm);
alarm(DURATION);
int status = msgrcv(msg_id, &m, sizeof(m.appointment), destination_mailbox, 0);

what is going to happen is the program will block as soon as it reaches the msgrcv command, because it will be waiting for a message. However, if it does not recieve a message after the DURATION seconds, the alarm signal will wake it up, and status will equals -1.

Now, ideally, let's say I would like to make sure that the program woke up due to the alarm and nothing else. Say, for example, there was an error in msgrcv,and thus the program woke up, but the status is still -1 and m is empty.

The man entry for the return value of signal states

signal() returns the previous value of the signal handler, or SIG_ERR on error. In the event of an error, errno is set to indicate the cause.

If I try to print the value of sig_t s, after the signal handler had been called, how would I do it? This prints "signal (nil)".

 printf("signal %p\n", s);

So, how do I take care of this return value if I want to so something like

if(s == a state where the handler was never called)
      do A;
else
      do B;

Solution

  • If msgrcv is interrupted by a signal, it should return -1 and errno should be set to EINTR (unless the behavior has been changed using sigaction).

    So to check that case :

    int status = msgrcv(/*...*/);
    if (status == -1) {
        if (errno == EINTR)) {
            /* interrupted by signal */
        }
        else {
            /* other error */
        }
    }
    

    If you need to check specifically for a SIGALRM interrupt, you can have your signal handler set a global sig_atomic_t variable, and then check that after msgrcv returns.