Saturday, November 1, 2014

Unix Prog: Threads and Signals

1. Signal Mask
1) Each thread has its own signal mask , but the signal disposition is shared by all threads in the process.

2) Signal is delivered to single thread in the process. If the signal is related to hardward fault, the signal is usually sent to the thread whose action caused the event. Other signals, on the other hand, are delivered to an arbitrary thread.

System Definition:
 ubuntu@ip-172-31-23-227:~$ less /usr/include/x86_64-linux-gnu/bits/sigthread.h  
 ......  
 /* Modify the signal mask for the calling thread. The arguments have  
   the same meaning as for sigprocmask(2). */  
 extern int pthread_sigmask (int __how,  
               const __sigset_t *__restrict __newmask,  
               __sigset_t *__restrict __oldmask)__THROW;  
   
 /* Send signal SIGNO to the given thread. */  
 extern int pthread_kill (pthread_t __threadid, int __signo) __THROW;  
 ......  

pthread_sigmask function is identical to sigprocmask, except that pthread_sigmask works with threads and returns an error code on failure instead of setting errno and returning -1.

To send a signal to a process we use "kill". To send a signal to a thread we use "pthread_kill". We can pass a signo 0 to check if the thread exists. If the disposition of the signal is termination of process, the entire process will be terminated.

Note: alarm is the process resource, and all threads share the same alarm.

 ubuntu@ip-172-31-23-227:~$ less /usr/include/signal.h  
 ......  
 /* Select any of pending signals from SET or wait for any to arrive.  
   
   This function is a cancellation point and therefore not marked with  
   __THROW. */  
 extern int sigwait (const sigset_t *__restrict __set, int *__restrict __sig)  
    __nonnull ((1, 2));  
 ......  

set specify the set of signals for which the thread is waiting, and delivered signal will be populated on second argument.

to avoid trouble, the thread normally block the signal before calling sigwait to make sure that the signal does not arrive before sigwait, in which case, the thread will be blocked forever.

With sigwait, we can prevent the signals from interrupting the threads by adding them to each thread's signal mask.

If multiple threads are blocked in calls to sigwait for the same signal, only one of the threads will return from sigwait when the signal is delivered. If the signal is being caught with one handler, it is up to OS to invoke signal handler or deliver it to one thread(but not both).

2. Example:
thsig.c:
 #include<stdio.h>  
 #include<stdlib.h>  
 #include<unistd.h>  
 #include<pthread.h>  
 #include<signal.h>  
   
 int quitflag;  
 sigset_t mask;  
   
 pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;  
 pthread_cond_t waitloc = PTHREAD_COND_INITIALIZER;  
   
 void * thr_fn(void *arg)  
 {  
  int err, signo;  
   
  for(;;) {  
   err = sigwait(&mask, &signo);  
   if(err != 0) {  
    printf("sigwait error!\n");  
    exit(1);  
   }  
   
   switch(signo) {  
   case SIGINT:  
    printf("\ninterrupt\n");  
    break;  
   
   case SIGQUIT:  
    pthread_mutex_lock(&lock);  
    quitflag = 1;  
    pthread_mutex_unlock(&lock);  
    pthread_cond_signal(&waitloc);  
    return 0;  
   
   default:  
    printf("unexpected signal %d\n", signo);  
    exit(1);  
   }  
  }  
 }  
   
 int main(int argc, char* argv[])  
 {  
  int err;  
  sigset_t oldmask;  
  pthread_t tid;  
   
  // Create the signal mask  
  sigemptyset(&mask);  
  sigaddset(&mask, SIGINT);  
  sigaddset(&mask, SIGQUIT);  
  if((err = pthread_sigmask(SIG_BLOCK, &mask, &oldmask)) != 0) {  
   printf("pthread_sigmask error!\n");  
   exit(2);  
  }  
   
  // Launch the thread  
  err = pthread_create(&tid, NULL, thr_fn, 0);  
  if(err != 0) {  
   printf("pthread_create error!\n");  
   exit(3);  
  }  
   
  pthread_mutex_lock(&lock);  
  while(quitflag == 0)  
   pthread_cond_wait(&waitloc, &lock);  
  pthread_mutex_unlock(&lock);  
   
  quitflag = 0;  
  if(sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0) {  
   printf("SIG_SETMASK error!\n");  
   exit(4);  
  }  
   
  exit(0);  
 }  

shell:
 ubuntu@ip-172-31-23-227:~$ ./thsig.out  
 ^C  
 interrupt  
 ^C  
 interrupt  
 ^\  

No comments:

Post a Comment