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.
|