Sunday, October 12, 2014

Unix Prog: sigprocmask function

1. signal set

System Definition:
 ubuntu@ip-172-31-23-227:~$ less /usr/include/signal.h  
 ......  
 /* Clear all signals from SET. */  
 extern int sigemptyset (sigset_t *__set) __THROW __nonnull ((1));  
   
 /* Set all signals in SET. */  
 extern int sigfillset (sigset_t *__set) __THROW __nonnull ((1));  
   
 /* Add SIGNO to SET. */  
 extern int sigaddset (sigset_t *__set, int __signo) __THROW __nonnull ((1));  
   
 /* Remove SIGNO from SET. */  
 extern int sigdelset (sigset_t *__set, int __signo) __THROW __nonnull ((1));  
   
 /* Return 1 if SIGNO is in SET, 0 if not. */  
 extern int sigismember (const sigset_t *__set, int __signo)  
    __THROW __nonnull ((1));  
 ......  

sigset_t is one integer type, for which each bit represents one type of signal. If that bit is on, corresponding signal is masked off.
sigemptyset just zero out all bits in sigset_t integer.
sigfillset just turn on all bits in sigset_t integer.
sigaddset turn on one specific bit in sigset_t integer
sigdelset turn off one specific bit in sigset_t integer
sigismember test if one specific bit in sigset_t integer is on.

2. sigprocmask system call

System Definition:
 ubuntu@ip-172-31-23-227:~$ less /usr/include/signal.h  
 ......  
 /* Get the system-specific definitions of `struct sigaction'  
   and the `SA_*' and `SIG_*'. constants. */  
 # include <bits/sigaction.h>  
   
 /* Get and/or change the set of blocked signals. */  
 extern int sigprocmask (int __how, const sigset_t *__restrict __set,  
             sigset_t *__restrict __oset) __THROW;  
 ......  
 ubuntu@ip-172-31-23-227:~$ less /usr/include/x86_64-linux-gnu/bits/sigaction.h  
 ......  
 /* Values for the HOW argument to `sigprocmask'. */  
 #define SIG_BLOCK   0     /* Block signals. */  
 #define SIG_UNBLOCK  1     /* Unblock signals. */  
 #define SIG_SETMASK  2     /* Set the set of blocked signals. */  
 ......  

For system call sigprocmask, first argument should be one of following macros:
SIG_BLOCK: block the specific signals in 2nd argument
SIG_UNBLOCK: unblock the specific signals in 2nd argument
SIG_SETMASK: assign the specific signals in 2nd argument as current mask

second argument is the pointer pointing to the sigset_t type for which each bit represents one type of signal.

If third argument is not null, then the current mask will be returned in that variable.

If second argument is null, then first argument is ignored, and current signal mask doesn't change.

3. Example of sigprocmask:
sigmask.c:
 #include<stdio.h>  
 #include<stdlib.h>  
 #include<unistd.h>  
 #include<signal.h>  
 #include<errno.h>  
   
 void pr_mask(const char *str)  
 {  
  sigset_t sigset;  
  int errno_save;  
   
  // Back up the errno value since this function may change it  
  errno_save = errno;  
   
  // Get the current signal mask  
  if(sigprocmask(0, NULL, &sigset) < 0) {  
   printf("sigprocmask error!\n");  
   exit(1);  
  }  
   
  printf("%s", str);  
   
  // Output the signal mask  
  if(sigismember(&sigset, SIGINT)) printf("SIGINT ");  
  if(sigismember(&sigset, SIGQUIT)) printf("SIGQUIT ");  
  if(sigismember(&sigset, SIGUSR1)) printf("SIGUSR1 ");  
  if(sigismember(&sigset, SIGALRM)) printf("SIGALRM ");  
   
  printf("\n");  
   
  // Restore the errno value  
  errno = errno_save;  
 }  
   
 int main(int argc, char* argv[])  
 {  
  sigset_t sigset;  
  sigemptyset(&sigset);  
   
  // Block one empty signal mask set  
  if(sigprocmask(SIG_BLOCK, &sigset, NULL) < 0) {  
   printf("sigprocmask error!\n");  
   exit(1);  
  }  
  pr_mask("BLOCK Empty Set:");  
   
  // Block the SIGINT, SIGUSR1 signal  
  if(sigaddset(&sigset, SIGINT) < 0) {  
   printf("sigaddset error!\n");  
   exit(2);  
  }  
   
  if(sigaddset(&sigset, SIGUSR1) < 0) {  
   printf("sigaddset error!\n");  
   exit(2);  
  }  
   
  if(sigprocmask(SIG_BLOCK, &sigset, NULL) < 0) {  
   printf("sigprocmask error!\n");  
   exit(1);  
  }  
  pr_mask("BLOCK SIGINT, SIGUSR1: ");  
   
  // Unblock the SIGUSR1 signal:  
  if(sigdelset(&sigset, SIGINT) < 0) {  
   printf("sigdelset error!\n");  
   exit(2);  
  }  
   
  if(sigprocmask(SIG_UNBLOCK, &sigset, NULL) < 0) {  
   printf("sigprocmask error!\n");  
   exit(1);  
  }  
  pr_mask("UNBLOCK SIGUSR1: ");  
   
  exit(0);  
 }  

shell:
The program firstly setup the empty signal mask. And then add the SIGINT, SIGUSR1 to the signal set, use sigprocmask to block the signals.
After that, it removes SIGINT from signal set, only left the SIGUSR1 in the set, at this time, it use sigprocmask with SIG_UNBLOCK to unblock the specified SIGUSR1 signal.
 ubuntu@ip-172-31-23-227:~$ ./sigmask.out  
 BLOCK Empty Set:  
 BLOCK SIGINT, SIGUSR1: SIGINT SIGUSR1  
 UNBLOCK SIGUSR1: SIGINT  

No comments:

Post a Comment