Mercurial > hg > freeDiameter
view libfreeDiameter/signal.c @ 236:60f34df3e025
Remove dependency on signalent.h
author | Sebastien Decugis <sdecugis@nict.go.jp> |
---|---|
date | Mon, 08 Mar 2010 14:10:30 +0900 |
parents | 8773740401a5 |
children | 5df55136361b |
line wrap: on
line source
/********************************************************************************************************* * Software License Agreement (BSD License) * * Author: Sebastien Decugis <sdecugis@nict.go.jp> * * * * Copyright (c) 2009, WIDE Project and NICT * * All rights reserved. * * * * Redistribution and use of this software in source and binary forms, with or without modification, are * * permitted provided that the following conditions are met: * * * * * Redistributions of source code must retain the above * * copyright notice, this list of conditions and the * * following disclaimer. * * * * * Redistributions in binary form must reproduce the above * * copyright notice, this list of conditions and the * * following disclaimer in the documentation and/or other * * materials provided with the distribution. * * * * * Neither the name of the WIDE Project or NICT nor the * * names of its contributors may be used to endorse or * * promote products derived from this software without * * specific prior written permission of WIDE Project and * * NICT. * * * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED * * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * *********************************************************************************************************/ #include "libfD.h" #include <signal.h> /* A structure to hold the registered signal handlers */ struct sig_hdl { struct fd_list chain; /* Link in the sig_hdl_list ordered by signal */ int signal; /* The signal this handler is registered for */ void (*sig_hdl)(int);/* The callback to call when the signal is caught */ pthread_t sig_thr; /* The thread that receives the signal */ char *modname; /* The name of the module who registered the signal (for debug) */ }; /* The list of sig_hdl, and the mutex to protect it */ static struct fd_list sig_hdl_list = FD_LIST_INITIALIZER(sig_hdl_list); static pthread_mutex_t sig_hdl_lock = PTHREAD_MUTEX_INITIALIZER; /* Detached thread attribute */ static pthread_attr_t detached; /* Note if the module was initialized */ static int sig_initialized = 0; /* signals short names list */ static int abbrevs_init(void); /* Initialize the support for signals */ int fd_sig_init(void) { sigset_t sig_all; TRACE_ENTRY(""); if (sig_initialized) return 0; /* Initialize the list of abbreviations */ CHECK_FCT(abbrevs_init()); /* Block all signals from the current thread and all its future children, so that signals are delivered only to our sig_hdl->sig_thr */ sigfillset(&sig_all); CHECK_POSIX( pthread_sigmask(SIG_BLOCK, &sig_all, NULL) ); /* Initialize the detached attribute */ CHECK_POSIX( pthread_attr_init(&detached) ); CHECK_POSIX( pthread_attr_setdetachstate(&detached, PTHREAD_CREATE_DETACHED) ); sig_initialized++; /* That's all we have to do here ... */ return 0; } /* This thread (created detached) does call the signal handler */ static void * signal_caller(void * arg) { struct sig_hdl * me = arg; char buf[40]; /* Name this thread */ snprintf(buf, sizeof(buf), "cb %d:%s:%s", me->signal, fd_sig_abbrev(me->signal), me->modname); fd_log_threadname ( buf ); TRACE_ENTRY("%p", me); /* Call the signal handler */ (*me->sig_hdl)(me->signal); TRACE_DEBUG(CALL, "Callback completed"); /* Done! */ return NULL; } /* This thread "really" receives the signal and starts the signal_caller thread */ static void * signal_catcher(void * arg) { struct sig_hdl * me = arg; sigset_t ss; char buf[40]; ASSERT(arg); /* Name this thread */ snprintf(buf, sizeof(buf), "catch %d:%s:%s", me->signal, fd_sig_abbrev(me->signal), me->modname); fd_log_threadname ( buf ); TRACE_ENTRY("%p", me); sigemptyset(&ss); sigaddset(&ss, me->signal); /* Now loop on the reception of the signal */ while (1) { int sig; pthread_t th; /* Wait to receive the next signal */ CHECK_POSIX_DO( sigwait(&ss, &sig), break ); TRACE_DEBUG(FULL, "Signal %d caught", sig); /* Create the thread that will call the handler */ CHECK_POSIX_DO( pthread_create( &th, &detached, signal_caller, arg ), break ); } /* An error occurred... What should we do ? */ TRACE_DEBUG(INFO, "!!! ERROR !!! The signal catcher for %d:%s:%s is terminating!", me->signal, fd_sig_abbrev(me->signal), me->modname); /* Better way to handle this ? */ ASSERT(0); return NULL; } /* Register a new callback to be called on reception of a given signal (it receives the signal as parameter) */ /* EALREADY will be returned if there is already a callback registered on this signal */ /* NOTE: the signal handler will be called from a new detached thread */ int fd_sig_register(int signal, char * modname, void (*handler)(int signal)) { struct sig_hdl * new; struct fd_list * next = NULL; int matched = 0; TRACE_ENTRY("%d %p %p", signal, modname, handler); CHECK_PARAMS( signal && modname && handler && sig_initialized ); /* Alloc all memory before taking the lock */ CHECK_MALLOC( new = malloc(sizeof(struct sig_hdl)) ); memset(new, 0, sizeof(struct sig_hdl)); fd_list_init(&new->chain, new); new->signal = signal; new->sig_hdl = handler; CHECK_MALLOC_DO( new->modname = strdup(modname), { free(new); return ENOMEM; } ); /* Search in the list if we already have a handler for this signal */ CHECK_POSIX(pthread_mutex_lock(&sig_hdl_lock)); for (next = sig_hdl_list.next; next != &sig_hdl_list; next = next->next) { struct sig_hdl * nh = (struct sig_hdl *)next; if (nh->signal < signal) continue; if (nh->signal == signal) { matched = 1; TRACE_DEBUG(INFO, "Signal %d (%s) is already registered by module '%s'", signal, fd_sig_abbrev(signal), nh->modname); } break; } if (!matched) /* Insert the new element before the next handle */ fd_list_insert_before(next, &new->chain); CHECK_POSIX(pthread_mutex_unlock(&sig_hdl_lock)); if (matched) return EALREADY; /* Already registered... */ /* OK, now start the thread */ CHECK_POSIX( pthread_create( &new->sig_thr, NULL, signal_catcher, new ) ); /* All good */ return 0; } /* Dump list of handlers */ void fd_sig_dump(int level, int indent) { struct fd_list * li = NULL; if (!TRACE_BOOL(level)) return; CHECK_POSIX_DO(pthread_mutex_lock(&sig_hdl_lock), /* continue */); if (!FD_IS_LIST_EMPTY(&sig_hdl_list)) fd_log_debug("%*sList of registered signal handlers:\n", indent, ""); for (li = sig_hdl_list.next; li != &sig_hdl_list; li = li->next) { struct sig_hdl * h = (struct sig_hdl *)li; fd_log_debug("%*s - sig %*d (%s) => %p in module %s\n", indent, "", 2, h->signal, fd_sig_abbrev(h->signal), h->sig_hdl, h->modname); } CHECK_POSIX_DO(pthread_mutex_unlock(&sig_hdl_lock), /* continue */); return; } /* Remove a callback */ int fd_sig_unregister(int signal) { struct fd_list * li = NULL; struct sig_hdl * h = NULL; TRACE_ENTRY("%d", signal); CHECK_PARAMS( signal && sig_initialized ); /* Search in the list if we already have a handler for this signal */ CHECK_POSIX(pthread_mutex_lock(&sig_hdl_lock)); for (li = sig_hdl_list.next; li != &sig_hdl_list; li = li->next) { struct sig_hdl * nh = (struct sig_hdl *)li; if (nh->signal < signal) continue; if (nh->signal == signal) { h = nh; fd_list_unlink(&h->chain); } break; } CHECK_POSIX(pthread_mutex_unlock(&sig_hdl_lock)); if (!h) return ENOENT; /* Stop the catcher thread */ CHECK_FCT( fd_thr_term(&h->sig_thr) ); /* Free */ free(h->modname); free(h); /* All good */ return 0; } /* Terminate the signal handler thread -- must be called if fd_sig_init was called */ void fd_sig_fini(void) { if (!sig_initialized) return; /* For each registered handler, stop the thread, free the associated memory */ CHECK_POSIX_DO(pthread_mutex_lock(&sig_hdl_lock), /* continue */); while (!FD_IS_LIST_EMPTY(&sig_hdl_list)) { struct sig_hdl * h = (struct sig_hdl *)sig_hdl_list.next; /* Unlink */ fd_list_unlink(&h->chain); /* Stop the catcher thread */ CHECK_FCT_DO( fd_thr_term(&h->sig_thr), /* continue */ ); /* Free */ free(h->modname); free(h); } CHECK_POSIX_DO(pthread_mutex_unlock(&sig_hdl_lock), /* continue */); /* Destroy the thread attribute */ CHECK_POSIX_DO( pthread_attr_destroy(&detached), /* continue */ ); return; } /**************************************************************************************/ static char **abbrevs; static size_t abbrevs_nr = 0; /* Initialize the array of signals */ static int abbrevs_init(void) { int i; #define SIGNAL_MAX_LIMIT 100 /* Do not save signals with value > this */ /* The raw list of signals in the system -- might be incomplete, add any signal you need */ struct sig_abb_raw { int sig; char *name; } abbrevs_raw[] = { { 0, "[unknown signal]" } #define RAW_SIGNAL( _sig ) ,{ _sig, #_sig } #ifdef SIGBUS RAW_SIGNAL( SIGBUS ) #endif /* SIGBUS */ #ifdef SIGTTIN RAW_SIGNAL( SIGTTIN ) #endif /* SIGTTIN */ #ifdef SIGTTOU RAW_SIGNAL( SIGTTOU ) #endif /* SIGTTOU */ #ifdef SIGPROF RAW_SIGNAL( SIGPROF ) #endif /* SIGPROF */ #ifdef SIGALRM RAW_SIGNAL( SIGALRM ) #endif /* SIGALRM */ #ifdef SIGFPE RAW_SIGNAL( SIGFPE ) #endif /* SIGFPE */ #ifdef SIGSTKFLT RAW_SIGNAL( SIGSTKFLT ) #endif /* SIGSTKFLT */ #ifdef SIGSTKSZ RAW_SIGNAL( SIGSTKSZ ) #endif /* SIGSTKSZ */ #ifdef SIGUSR1 RAW_SIGNAL( SIGUSR1 ) #endif /* SIGUSR1 */ #ifdef SIGURG RAW_SIGNAL( SIGURG ) #endif /* SIGURG */ #ifdef SIGIO RAW_SIGNAL( SIGIO ) #endif /* SIGIO */ #ifdef SIGQUIT RAW_SIGNAL( SIGQUIT ) #endif /* SIGQUIT */ #ifdef SIGABRT RAW_SIGNAL( SIGABRT ) #endif /* SIGABRT */ #ifdef SIGTRAP RAW_SIGNAL( SIGTRAP ) #endif /* SIGTRAP */ #ifdef SIGVTALRM RAW_SIGNAL( SIGVTALRM ) #endif /* SIGVTALRM */ #ifdef SIGSEGV RAW_SIGNAL( SIGSEGV ) #endif /* SIGSEGV */ #ifdef SIGCONT RAW_SIGNAL( SIGCONT ) #endif /* SIGCONT */ #ifdef SIGPIPE RAW_SIGNAL( SIGPIPE ) #endif /* SIGPIPE */ #ifdef SIGWINCH RAW_SIGNAL( SIGWINCH ) #endif /* SIGWINCH */ #ifdef SIGXFSZ RAW_SIGNAL( SIGXFSZ ) #endif /* SIGXFSZ */ #ifdef SIGHUP RAW_SIGNAL( SIGHUP ) #endif /* SIGHUP */ #ifdef SIGCHLD RAW_SIGNAL( SIGCHLD ) #endif /* SIGCHLD */ #ifdef SIGSYS RAW_SIGNAL( SIGSYS ) #endif /* SIGSYS */ #ifdef SIGSTOP RAW_SIGNAL( SIGSTOP ) #endif /* SIGSTOP */ #ifdef SIGUSR2 RAW_SIGNAL( SIGUSR2 ) #endif /* SIGUSR2 */ #ifdef SIGTSTP RAW_SIGNAL( SIGTSTP ) #endif /* SIGTSTP */ #ifdef SIGKILL RAW_SIGNAL( SIGKILL ) #endif /* SIGKILL */ #ifdef SIGXCPU RAW_SIGNAL( SIGXCPU ) #endif /* SIGXCPU */ #ifdef SIGUNUSED RAW_SIGNAL( SIGUNUSED ) #endif /* SIGUNUSED */ #ifdef SIGPWR RAW_SIGNAL( SIGPWR ) #endif /* SIGPWR */ #ifdef SIGILL RAW_SIGNAL( SIGILL ) #endif /* SIGILL */ #ifdef SIGINT RAW_SIGNAL( SIGINT ) #endif /* SIGINT */ #ifdef SIGIOT RAW_SIGNAL( SIGIOT ) #endif /* SIGIOT */ #ifdef SIGTERM RAW_SIGNAL( SIGTERM ) #endif /* SIGTERM */ }; TRACE_ENTRY(""); /* First pass: find the highest signal number */ for (i=0; i < sizeof(abbrevs_raw)/sizeof(abbrevs_raw[0]); i++) { if (abbrevs_raw[i].sig > SIGNAL_MAX_LIMIT) { TRACE_DEBUG(ANNOYING, "Ignoring signal %s (%d), increase SIGNAL_MAX_LIMIT if you want it included", abbrevs_raw[i].name, abbrevs_raw[i].sig); continue; } if (abbrevs_raw[i].sig > abbrevs_nr) abbrevs_nr = abbrevs_raw[i].sig; } /* Now, alloc the array */ abbrevs_nr++; /* 0-based */ CHECK_MALLOC( abbrevs = calloc( abbrevs_nr, sizeof(char *) ) ); /* Second pass: add all the signals in the array */ for (i=0; i < sizeof(abbrevs_raw)/sizeof(abbrevs_raw[0]); i++) { if (abbrevs_raw[i].sig > SIGNAL_MAX_LIMIT) continue; if (abbrevs[abbrevs_raw[i].sig] == NULL) abbrevs[abbrevs_raw[i].sig] = abbrevs_raw[i].name; } /* Third pass: Set all missing signals to the undef value */ for (i=0; i < abbrevs_nr; i++) { if (abbrevs[i] == NULL) abbrevs[i] = abbrevs_raw[0].name; } /* Done! */ return 0; } /* Names of signals */ const char * fd_sig_abbrev(int signal) { if (signal < abbrevs_nr) return abbrevs[signal]; return abbrevs[0]; }