Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is sigaddset used for?

I have this code where I use sigaddset and sigaction. However if I comment segaddset the result is the same

   struct sigaction act; 

   act.sa_handler = process_alarm; 
   act.sa_flags = 0;           
   sigemptyset(&act.sa_mask); 
   //sigaddset(&act.sa_mask, SIGINT); 

   sigaction(SIGALRM, &act, NULL);

   for(;;) 
   { 
      alarm(3); 
      pause();  
   } 

Why do I need to use it?

like image 594
NeDark Avatar asked Dec 01 '14 11:12

NeDark


2 Answers

You are doing 2 things here:

  1. Populating a sigset_t. A sigset_t is just a collection of values for signals, and are used in various system calls. You can:

    • Create an empty sigset_t (sigemptyset()
    • Add a signal to the set (sigaddset())
    • Remove a signal to the set (sigdelset())
    • etc...
  2. Setting the signal mask for the signal handler. You do that by manipulating the sigset_t sa_mask member of the struct sigaction when you set up a signal handler in with a call to sigaction().

The signal mask of a signal handler means that while the signal handler is executing, the signals that are in the mask will be blocked - i.e. those signals will not be handled as long as they are blocked. When the signal handler are finished, the signals in will be unblocked. A signal that is blocked isn't "lost", it will be handled when that particular signal is unblocked again.

The sigaddset(&act.sa_mask, SIGINT); means the the SIGINT signal cannot occur while the code for the SIGALRM handler is running.

On the other hand, if you comment out sigaddset(&act.sa_mask, SIGINT);, you're left with just an empty list of signals created with sigemptyset(&act.sa_mask);. So any signals that occur while the SIGALRM handler function is running might preempt that handler and execute the signal handler for that other signal.

For a SIGINT, you would normally not notice any difference with manual testing - it's unlikely you manage to hit CTRL-C exactly when your handler for SIGALRM is running, and your SIGALRM handler probably runs quickly enough that you would not notice if the SIGINT was slightly delayed.

like image 180
nos Avatar answered Dec 30 '22 07:12

nos


Signals sets are manipulated via sigset_t type. Several operations are available for signals sets:

  • create an empty set S via sigemptyset, S=∅
  • add a signal s to a set S via sigaddset, S=S∪{s}
  • remove a signal s from a set via sigdelset, S=S\{s}
  • create the set of all possible signals via sigfillset.
  • test is a signal s is in a given set S via sigismember, s∈S?

Such a set is used at different places: setting a new process signal mask, blocking set during signal handling, requesting the set of pending signals, etc.

If you want to catch different signals, it may appears that some catching functions must not be interrupted with others, so you can add a set of signals to be blocked during the delivery of a given signal. You actually decided (when uncommented) to block SIGINT during SIGALRM delivery. So you can only observe this by sending a SIGINT during the execution of the handler; which is difficult to realize.

A example where it can be important ?

Suppose that the handler of SIGUSR1 modify a given data structure and that the handler for SIGUSR2 uses that same data structure. It is very important to make both handlers not concurrent, one can be run after the other but you probably don't want to be interrupted by one during the delivery of the other. Your code is self-concurrent, say that even in the case of only one thread, signals can lead you to concurrency.

like image 43
Jean-Baptiste Yunès Avatar answered Dec 30 '22 07:12

Jean-Baptiste Yunès