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