Email List: Xaustin-review-lX
[All Lists]

Defect in XSH pthread_sigmask

To: yyyyyyyyyyyyyyy@xxxxxxxxxxxxx
Subject: Defect in XSH pthread_sigmask
From: yyyyyyyy@xxxxxxx
Date: Fri, 11 Jul 2003 14:33:16 +0100 (BST)
        Defect report from : Domaigne , (personal interest)

(Please direct followup comments direct to yyyyyyyyyyyyyy@xxxxxxxxxxxxx)

@ page 0 line 0 section pthread_sigmask comment {pthread_sigmask}

Problem:

Edition of Specification (Year): 2003

Defect code :  2. Omission

Missing example

Action:

Signalling in multi-threaded process.

This example shows the use of pthread_sigmask() in order to deal with signals 
in a multi-threaded process. It provides a fairly general framework that could 
be easily adapted/extended by the reader.


/*===== Include part ===========================================*/
/*==============================================================*/

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

/*===== Signal's list to be managed  ===========================*/
/*==============================================================*/
/*
 *  in this example, we want to handle SIGINT, SIGQUIT and SIGTERM
 */
static int psig_list[] = {SIGINT, SIGQUIT, SIGTERM};


/*===== Usefull macros =========================================*/
/*==============================================================*/

#define NELEMS_ARRAY(array) ( sizeof(array)/sizeof(array[0]) )

#define DIE(text) \
do { \
    perror ("Error description: "); \
    fprintf (stderr, \
             "|___ At %s():%d, error caused by %s\n", \
             __func__, \
             __LINE__, \
             text \
             ); \
    exit (EXIT_FAILURE); \
} while(0)


/*===== Struct, typedefs etc. ==================================*/
/*==============================================================*/
typedef void* (*pthread_routine_t)(void *);


/*===== Forward declaration ====================================*/
/*==============================================================*/
void signal_thread(void);
void create_sigmask(sigset_t*, const int[], const int);


/****************************************************************/
/* main()                                                       */
/****************************************************************/

int main(int    argc,
         char **argv
         )
{
  pthread_t  sig_thr_id;   /* signal handler thread ID */
  sigset_t   sig_to_block; /* signals to block         */
  int        rc;           /* return code              */

  /*------------------------------------------------------------*/
  /*  Install the mechanism to deal with the "process-oriented" */
  /*  signals listed in psig_list[].                            */
  /*------------------------------------------------------------*/
  /*  
   *  Set the initial thread's signal mask to block 
   *  the signals listed in psig_list
   */
  create_sigmask (&sig_to_block, 
                  psig_list, 
                  NELEMS_ARRAY(psig_list)
                  );
  rc = pthread_sigmask (SIG_BLOCK,
                        &sig_to_block,
                        (sigset_t*) NULL
                        );
  if (rc < 0) 
    DIE("pthread_sigmask()"); /* die on error */

  /*
   *  Start a dedicated thread to handle signalling
   */ 
  rc = pthread_create (&sig_thr_id,
                       (pthread_attr_t*) NULL,
                       (pthread_routine_t) signal_thread,
                       (void*) NULL
                       );
  if (rc < 0) 
    DIE("pthread_create()"); /* die on error */
  /*
   *  At this point, any newly created thread will inherit 
   *  the signal mask from the initial thread. Thus these 
   *  threads shall not need to block again these signals. 
   */

  /*------------------------------------------------------------*/
  /*  Do whatever the program has to do (initialization, create */
  /*  threads an so on).                                        */
  /*------------------------------------------------------------*/
  ...
  
}


/****************************************************************/
/* signal_thread                                                */
/****************************************************************/
/*                                                              */
/* the signal thread waits for a signal listed in psig_list[]   */
/* to be queued. Upon reception of a targeted signal, it does   */
/* the corresponding processing.                                */
/*                                                              */
/****************************************************************/

void signal_thread(void)
{
  sigset_t  sig_to_wait4;  /* signals to wait for */
  int       sig_caught;    /* signal caught       */
  int       rc;            /* returned code       */

  /*------------------------------------------------------------*/  
  /*  wait for one signal in psig_list[] to become pending      */
  /*------------------------------------------------------------*/
  create_sigmask (&sig_to_wait4, 
                  psig_list, 
                  NELEMS_ARRAY(psig_list)
                  );
  rc = sigwait (&sig_to_wait4, 
                &sig_caught
                );
  if (rc < 0) 
    DIE("sigwait()");  /* die on error */
  
  /*------------------------------------------------------------*/
  /*  react accordingly to the signal caught                    */
  /*------------------------------------------------------------*/
  switch (sig_caught)
  {
  case SIGINT:     /* process SIGINT  */
    ... 
    break;
  case SIGQUIT:    /* process SIGQUIT */ 
    ... 
    break;
  case SIGTERM:    /* process SIGTERM */
    ...
    break;    
  default:         /* should normally not happen */
    fprintf (stderr, 
             "\nOups BUG! Forgot to deal with signal %d\n", 
             sig_caught
             );
    break;
  }
  
  ...
}


/****************************************************************/
/* create_sigmask                                               */
/****************************************************************/
/*                                                              */
/* This functions creates the signal mask corresponding to the  */
/* n signals listed in list[], the "hardware traps" excluded.   */ 
/*                                                              */
/****************************************************************/

void create_sigmask(sigset_t  *ptr_sigmask, /* returned sigmask */
                    const int  list[],      /* list of signals  */
                    const int  n            /* number of signals*/
                    )
{ 
  /* 
   *  Define the list of "hardware traps"
   */
  static int        hwtraps[] = {SIGFPE, SIGILL, SIGSEGV, SIGBUS};
  int               i; 
  int               rc;
 
  /*------------------------------------------------------------*/ 
  /*  Set sigmask to be the union of signal listed list[]       */
  /*------------------------------------------------------------*/
  rc = sigemptyset (ptr_sigmask);
  for (i=0; i<n; i++)
  {
    rc = sigaddset (ptr_sigmask, 
                    list[i]
                    );
    if (rc < 0) 
      DIE("sigaddset()"); /* die on error */
  }

  /*-------------------------------------------------------------*/
  /*  remove "hardware traps" from sigmask                       */
  /*-------------------------------------------------------------*/
  /* in the case that some "hardware trap" are defined in list[],
   * remove them from sigmask. Indeed, blocking those would  
   * result an undefined behavior. 
   */
  for (i=0; i<NELEMS_ARRAY(hwtraps); i++)
  {
    sigdelset (ptr_sigmask, 
               hwtraps[i]
               );
  } 
}

---

This example is quite long, but has the advantage to explain in large extend 
the standard mechanism to handle signalling in a multi-threaded process. 
Furthermore, it provides also example for exit(), pthread_create(), sigwait(), 
sigemptyset(), sigaddset(), and sigdelset(). If this example is too long, we 
might break it on several interfaces. 

I hope that Aardvark will be pleased with the current formatting. In case of 
problems, let me know!    

Feedbacks about this example are definitively appreciated!! 

Thanks, 
Loic.

<Prev in Thread] Current Thread [Next in Thread>