cunixsignalssigprocmask

sigprocmask( ) blocking signals in UNIX


i have written a small piece of code. This code first blocks the {SIGSEGV}, then adds SIGRTMIN to the same set. So, my final signal set is, {SIGSEGV,SIGRTMIN}. Thus, if i use SIG_UNBLOCK, as per my understanding, first SIGRTMIN should be unblocked, and then again if i invoke SIG_UNBLOCK, SIGSEGV should be unblocked.

That is, 1) {SIGSEGV,SIGRTMIN} 2) SIG_UNBLOCK = unblock SIGRTMIN, 3) Again invoke SIG_UNBLOCK = unblock SIGSEGV. I am giving the process a SIGRTMIN only, thus my second unblock should halt the process with SIGRTMIN. But it is not. Please help. N.B: Please don't give links to answers of other questions on sigprocmask( ), i have seen them and they don't clarify my question.

enter code here
#include <signal.h>
#include <unistd.h>
#include <stdio.h>

int main()
{
 sigset_t old_set,new_set;
 sigemptyset(&old_set);
 sigemptyset(&new_set);

 if(sigaddset(&old_set,SIGSEGV)==0)
 {
   printf("sigaddset successfully added for SIGSEGV\n");
 }
 sigprocmask(SIG_BLOCK,&old_set,NULL); // SIGSEGV signal is masked
 kill(0,SIGSEGV);


 //*****************************************************************

 if(sigaddset(&new_set,SIGRTMIN)==0)
 {
  printf("sigaddset successfully added for SIGRTMIN\n");
 }
  sigprocmask(SIG_BLOCK,&new_set,&old_set); // SIGRTMIN signal is masked
 kill(0,SIGSEGV);

 //****************** Unblock one signal at a time ******************

 sigprocmask(SIG_UNBLOCK,&new_set,&old_set); // SIGRTMIN signal is unmasked
 sigprocmask(SIG_UNBLOCK,&new_set,&old_set); // SIGSEGV signal is unmasked

}

Output:
 [root@dhcppc0 signals]# ./a.out
  sigaddset successfully added for SIGSEGV
  sigaddset successfully added for SIGRTMIN
  (Note:SIGSEGV is not received even after sigprocmask(SIG_UNBLOCK,&new_set,&old_set); a second time)

Solution

  • Your premise is wrong. The whole set gets blocked and unblocked with a single call of sigprocmask.

    Also, normally you would create a set containing every signal you want to block, then you would attempt to block them all with sigprocmask(SIG_BLOCK, pointer_to_sigset);.

    Your code doesn't really unblock SIGSEGV though. Here's what i would write WITHOUT error handling, because it would make the snippet unnecessarily long. Check every function for errors though, the lists of possible errors are provided by man pages:

    /* ... */
    sigset_t signal_set; /* We don't need oldset in this program. You can add it,
                            but it's best to use different sigsets for the second
                            and third argument of sigprocmask. */
    sigemptyset(&signal_set);
    
    sigaddset(&signal_set, SIGSEGV);
    sigaddset(&signal_set, SIGRTMIN);
    
    /* now signal_set == {SIGSEGV, SIGRTMIN} */
    
    sigprocmask(SIG_BLOCK, &signal_set, NULL): /* As i said, we don't bother with the 
                                                  oldset argument. */
    
    kill(0,SIGSEGV);  
    kill(0,SIGSEGV);  /* SIGSEGV is not a realtime signal, so we can send it twice, but
                         it will be recieved just once */
    
    sigprocmask(SIG_UNBLOCK, &signal_set, NULL); /* Again, don't bother with oldset */
    
    /* SIGSEGV will be received here */
    

    Of course, you might want to split blocking the signals into two operations on separate sets. The mechanism works like this: there is some set of blocked signals, which would replace oldset if you provided an oldset argument. You can add to that set with SIG_BLOCK, remove from that set with SIG_UNBLOCK, and change the whole set to your liking with SIG_SETMASK arguments of the sigprocmask function.