Using sigaction(), c

12,552

Let's try to understand what's happening with a modified version of your code :

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

void termination_handler(int signum)
{
    printf("Hello from handler\n");
    sleep(1);
}

int main (void)
{
    //Structs that will describe the old action and the new action
    //associated to the SIGINT signal (Ctrl+c from keyboard).
    struct sigaction new_action, old_action;

    //Set the handler in the new_action struct
    new_action.sa_handler = termination_handler;
    //Set to empty the sa_mask. It means that no signal is blocked
    // while the handler run.
    sigemptyset(&new_action.sa_mask);
    //Block the SEGTERM signal.
    // It means that while the handler run, the SIGTERM signal is ignored
    sigaddset(&new_action.sa_mask, SIGTERM);
    //Remove any flag from sa_flag. See documentation for flags allowed
    new_action.sa_flags = 0;

    //Read the old signal associated to SIGINT (keyboard, see signal(7))
    sigaction(SIGINT, NULL, &old_action);

    //If the old handler wasn't SIG_IGN (it's a handler that just
    // "ignore" the signal)
    if (old_action.sa_handler != SIG_IGN)
    {
        //Replace the signal handler of SIGINT with the one described by new_action
        sigaction(SIGINT,&new_action,NULL);
    }

    while(1)
    {
        printf("In the loop\n");
        sleep(100);
    }
    return 0;
}

So, if you compile it and launch it, and press Ctrl+C, then you'll have the handler message executed, and then you get back immediately out of the main's sleep. You can do it as many time as you want, and the handler message and the inloop message are still displayed.

So, you give a function, and sigaction does everything needed to hook the signal with your handler.


Now, what about sigterm? If you increase the sleep time in termination_handler, you can type something like "pkill --signal SIGTERM ./a.out" after pressing Ctrl+C. Then, what happens? Nothing! The SIGTERM signal is blocked while termination_handler is running. But once you are back in the main, now the SIGTERM will kill the application.

(Remember, while you are testing this code, you can still kill applications by sending a SIGKILL signal.)


If you want to know more, and have more fun with signals, you have the signal manual and the sigaction manual which tell a lot more. Notice that you also have the detailed description of the sigaction structure.

Share:
12,552
yotamoo
Author by

yotamoo

Updated on August 07, 2022

Comments

  • yotamoo
    yotamoo over 1 year

    I was doing a little reading about sigaction() (sources are from my course notes) and I'm not sure I understand this text:

    The signal mask is calculated and installed only for the duration of the signal handler.

    By default, the signal “sig” is also blocked when the signal occurs.

    Once an action is installed for a specific signal using sigaction, it remains installed until another action is explicitly requested.

    Does this mean that the default signal mask is restored after returning form the signal handler? Also, do I have to re-install the handler after using it, as if I was using signal()?

    Also, there's this piece of code:

    #include <signal.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    
    void termination_handler(int signum) {
        exit(7);
    }
    
    int main (void) {
      struct sigaction new_action,old_action;
      new_action.sa_handler = termination_handler;
      sigemptyset(&new_action.sa_mask);
      sigaddset(&new_action.sa_mask, SIGTERM);
      new_action.sa_flags = 0;
      sigaction(SIGINT, NULL, &old_action);
      if (old_action.sa_handler != SIG_IGN) {
             sigaction(SIGINT,&new_action,NULL);
      }
      sleep(10);
      return 0;
    }
    

    So - how exactly will SIGTERM be handled? I can see that the installed handler is termination handler(), but then SIGTERM was added to the signal mask with no use of sigprocmask(). What does this mean? Thanks!

    P.s. one last question: why the if statement in main()?