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

Re: Defect in XSH pthread_sigmask (revised 1)

To: yyyyyyyyyyyyyyy@xxxxxxxxxxxxx
Subject: Re: Defect in XSH pthread_sigmask (revised 1)
From: Loic Domaigne <yyyyyyyy@xxxxxxx>
Date: Tue, 15 Jul 2003 19:52:27 +0200 (MEST)
References: <28723.1058275008@www62.gmx.net>
Hello everybody,


As promised, the revised version for the pthread_sigmask() example. 
Hope that's OK now.


Change Log:

- fix error handling for pthread_sigmask(), pthread_create(), 
  sigwait() and sigaddset().

- transform the DIE macro to a function. Error code is passed
  as an extra argument to the function. 

- introduce strerror_r() to get the error message string.


XSH used: 

  pthread_sigmask(),
  pthread_create(),
  sigwait(),
  sigemptyset(),
  sigaddset(),
  sigdelset(),
  errno,
  strerror_r(),
  fprintf(),
  exit() 


Have a nice day,
Loic. 


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

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <signal.h>
#include <string.h>
#include <errno.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, error_code) \
die(text, error_code, __func__, __LINE__)


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


/*===== Forward declaration ====================================*/
/*==============================================================*/
void signal_thread(void);
void create_sigmask(sigset_t*, const int[], const int);
void die(const char*, const int, const char*, 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()", rc); /* 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()", rc); /* 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 (initialize, 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()", rc);  /* 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[].                                  */
/*                                                              */
/****************************************************************/

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 trap"
   */
  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 == -1) 
    {
      DIE("sigaddset()", errno); /* die on error */
    }
  }

  /*-------------------------------------------------------------*/
  /*  remove "hardware trap" 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]
               );
  } 
}


/****************************************************************/
/* die                                                          */
/****************************************************************/
/*                                                              */
/* this functions prints the error message string corresponding */
/* to error_code and terminates the process.                    */
/*                                                              */
/****************************************************************/

void die(const char* text,        /* user text      */
         const int   error_code,  /* error code     */
         const char* where,       /* error location */
         const int   line         /* error location */
         )
{
  char error_string[80]; /* error message string for error_code  */
  int  rc;               /* code returned by strerror_r          */

  /*-------------------------------------------------------------*/
  /*  print error description                                    */
  /*-------------------------------------------------------------*/
  fprintf (stderr, 
           "%s at %s:%d.\n|___ error %d: ",
           text,
           where,
           line,
           error_code
           );
  /*
   *  Get an human readable description of error_code.
   *  strerror_r is used for thread-safety reason.
   */
  rc = strerror_r (error_code, 
                   error_string,
                   sizeof (error_string)
                   );
  if (rc == -1) 
  {                  /* strerror_r has failed */
    fprintf (stderr, 
             " < strerror_r failed with errno = %d >\n",
             errno
             );
  }
  else
  {                 /* print error message string */
    fprintf (stderr,
             "%s.\n",
             error_string
             );
  }

  /*-------------------------------------------------------------*/
  /* Terminate the process                                       */
  /*-------------------------------------------------------------*/
  exit (EXIT_FAILURE);
}

-- 
+++ GMX - Mail, Messaging & more  http://www.gmx.net +++

Jetzt ein- oder umsteigen und USB-Speicheruhr als Prämie sichern!

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