# HG changeset patch # User Sebastien Decugis # Date 1267783308 -32400 # Node ID 8773740401a5e2c3a3e402b16014fcf03b6d1d08 # Parent f91fe0b859289421d98cc7f2ed0ae7a145976e1d Centralized signal handlers management in the library diff -r f91fe0b85928 -r 8773740401a5 contrib/signalent.h.sh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/contrib/signalent.h.sh Fri Mar 05 19:01:48 2010 +0900 @@ -0,0 +1,9 @@ +#!/bin/bash + +# The goal here is to regenerate a file signalent.h if it is missing. This file contains only a list of the signals abbreviations. + +# This script needs to be improved... +cpp -dM /usr/include/signal.h \ + | tr -s '\t ' ' ' \ + | sed 's:#define \(SIG[A-Z]\+[0-9]*\) \([0-9]\+\):\2 \1:p;d' \ + | sort -n --unique diff -r f91fe0b85928 -r 8773740401a5 extensions/test_app/CMakeLists.txt --- a/extensions/test_app/CMakeLists.txt Thu Mar 04 17:32:00 2010 +0900 +++ b/extensions/test_app/CMakeLists.txt Fri Mar 05 19:01:48 2010 +0900 @@ -13,7 +13,6 @@ lex.ta_conf.c ta_conf.tab.c ta_conf.tab.h - ta_sig.c ta_dict.c ta_cli.c ta_serv.c diff -r f91fe0b85928 -r 8773740401a5 extensions/test_app/ta_cli.c --- a/extensions/test_app/ta_cli.c Thu Mar 04 17:32:00 2010 +0900 +++ b/extensions/test_app/ta_cli.c Fri Mar 05 19:01:48 2010 +0900 @@ -135,7 +135,7 @@ } /* Create a test message */ -static void ta_cli_test_message(void) +static void ta_cli_test_message(int sig) { struct msg * req = NULL; struct avp * avp; @@ -235,16 +235,16 @@ { CHECK_FCT( fd_sess_handler_create(&ta_cli_reg, free) ); - CHECK_FCT( ta_sig_init(ta_cli_test_message) ); + CHECK_FCT( fd_sig_register(ta_conf->signal, "test_app.cli", ta_cli_test_message ) ); return 0; } void ta_cli_fini(void) { - ta_sig_fini(); + CHECK_FCT_DO( fd_sig_unregister(ta_conf->signal), /* continue */ ); - (void) fd_sess_handler_destroy(&ta_cli_reg); + CHECK_FCT_DO( fd_sess_handler_destroy(&ta_cli_reg), /* continue */ ); return; }; diff -r f91fe0b85928 -r 8773740401a5 extensions/test_app/ta_sig.c --- a/extensions/test_app/ta_sig.c Thu Mar 04 17:32:00 2010 +0900 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,86 +0,0 @@ -/********************************************************************************************************* -* Software License Agreement (BSD License) * -* Author: Sebastien Decugis * -* * -* 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. * -*********************************************************************************************************/ - -/* Install the signal handler */ - -#include "test_app.h" - -static pthread_t th = (pthread_t) NULL; - -static void * ta_sig_th(void * arg) -{ - int sig; - int ret; - sigset_t ss; - void (*cb)(void) = arg; - - fd_log_threadname ( "app_test signal handler" ); - - sigemptyset(&ss); - sigaddset(&ss, ta_conf->signal); - - while (1) { - ret = sigwait(&ss, &sig); - if (ret != 0) { - fd_log_debug("sigwait failed in the app_test extension: %s", strerror(errno)); - break; - } - - TRACE_DEBUG(FULL, "Signal caught, calling function..."); - - /* Call the cb function */ - (*cb)(); - - } - - return NULL; -} - -int ta_sig_init(void (*cb)(void)) -{ - return pthread_create( &th, NULL, ta_sig_th, (void *)cb ); -} - -void ta_sig_fini(void) -{ - void * th_ret = NULL; - - if (th != (pthread_t) NULL) { - (void) pthread_cancel(th); - (void) pthread_join(th, &th_ret); - } - - return; -} diff -r f91fe0b85928 -r 8773740401a5 extensions/test_app/test_app.c --- a/extensions/test_app/test_app.c Thu Mar 04 17:32:00 2010 +0900 +++ b/extensions/test_app/test_app.c Fri Mar 05 19:01:48 2010 +0900 @@ -38,7 +38,6 @@ */ #include "test_app.h" -#include /* Initialize the configuration */ struct ta_conf * ta_conf = NULL; diff -r f91fe0b85928 -r 8773740401a5 extensions/test_app/test_app.h --- a/extensions/test_app/test_app.h Thu Mar 04 17:32:00 2010 +0900 +++ b/extensions/test_app/test_app.h Fri Mar 05 19:01:48 2010 +0900 @@ -41,6 +41,7 @@ */ #include +#include #ifndef TEST_APP_DEFAULT_SIGNAL #define TEST_APP_DEFAULT_SIGNAL SIGUSR1 @@ -68,10 +69,6 @@ /* Parse the configuration file */ int ta_conf_handle(char * conffile); -/* Start or stop the signal handler */ -int ta_sig_init(void (*cb)(void)); -void ta_sig_fini(void); - /* Handle incoming messages (server) */ int ta_serv_init(void); void ta_serv_fini(void); diff -r f91fe0b85928 -r 8773740401a5 freeDiameter/main.c --- a/freeDiameter/main.c Thu Mar 04 17:32:00 2010 +0900 +++ b/freeDiameter/main.c Fri Mar 05 19:01:48 2010 +0900 @@ -41,7 +41,7 @@ #include /* forward declarations */ -static void * sig_hdl(void * arg); +static void fd_shutdown(int signal); static int main_cmdline(int argc, char *argv[]); static void main_version(void); static void main_help( void ); @@ -57,17 +57,11 @@ int main(int argc, char * argv[]) { int ret; - pthread_t sig_th; - sigset_t sig_all; memset(fd_g_config, 0, sizeof(struct fd_config)); - /* Block all signals */ - sigfillset(&sig_all); - CHECK_POSIX( pthread_sigmask(SIG_BLOCK, &sig_all, NULL) ); - /* Initialize the library -- must come first since it initializes the debug facility */ - CHECK_FCT( fd_lib_init() ); + CHECK_FCT( fd_lib_init(1) ); TRACE_DEBUG(INFO, "libfreeDiameter initialized."); /* Name this thread */ @@ -90,8 +84,9 @@ /* Parse the command-line */ CHECK_FCT( main_cmdline(argc, argv) ); - /* Allow SIGINT and SIGTERM from this point */ - CHECK_POSIX( pthread_create(&sig_th, NULL, sig_hdl, NULL) ); + /* Allow SIGINT and SIGTERM from this point to terminate the application */ + CHECK_FCT( fd_sig_register(SIGINT, "freeDiameter.main", fd_shutdown) ); + CHECK_FCT( fd_sig_register(SIGTERM, "freeDiameter.main", fd_shutdown) ); /* Add definitions of the base protocol */ CHECK_FCT( fd_dict_base_protocol(fd_g_config->cnf_dict) ); @@ -109,6 +104,7 @@ CHECK_FCT( fd_ext_load() ); fd_conf_dump(); + fd_sig_dump(FULL, 1); /* Start the servers */ CHECK_FCT( fd_servers_start() ); @@ -169,11 +165,12 @@ CHECK_FCT_DO( fd_ext_fini(), /* Cleanup all extensions */ ); CHECK_FCT_DO( fd_rtdisp_cleanup(), /* destroy remaining handlers */ ); - CHECK_FCT_DO( fd_thr_term(&sig_th), /* reclaim resources of the signal thread */ ); - GNUTLS_TRACE( gnutls_global_deinit() ); fd_log_debug(FD_PROJECT_BINARY " daemon is terminated.\n"); + + fd_lib_fini(); + return ret; } @@ -318,33 +315,14 @@ " -q, --quiet Decrease verbosity then remove debug messages\n"); } -#ifdef HAVE_SIGNALENT_H -const char *const signalstr[] = { -# include "signalent.h" -}; -const int nsignalstr = sizeof signalstr / sizeof signalstr[0]; -# define SIGNALSTR(sig) (((sig) < nsignalstr) ? signalstr[(sig)] : "unknown") -#else /* HAVE_SIGNALENT_H */ -# define SIGNALSTR(sig) ("") -#endif /* HAVE_SIGNALENT_H */ - -/* signal handler */ -static void * sig_hdl(void * arg) +/* Terminate the application */ +static void fd_shutdown(int signal) { - sigset_t sig_main; - int sig = 0; - - TRACE_ENTRY(); - fd_log_threadname("Main signal handler"); + TRACE_ENTRY("%d", signal); - sigemptyset(&sig_main); - sigaddset(&sig_main, SIGINT); - sigaddset(&sig_main, SIGTERM); - - CHECK_SYS_DO( sigwait(&sig_main, &sig), TRACE_DEBUG(INFO, "Error in sigwait function") ); + TRACE_DEBUG(INFO, "Received signal %s (%d), exiting", SIGNALSTR(signal), signal); + + CHECK_FCT_DO( fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL), exit(2) ); - TRACE_DEBUG(INFO, "Received signal %s (%d), exiting", SIGNALSTR(sig), sig); - CHECK_FCT_DO( fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL), exit(2) ); - return NULL; + return; } - diff -r f91fe0b85928 -r 8773740401a5 freeDiameter/tests/tests.h --- a/freeDiameter/tests/tests.h Thu Mar 04 17:32:00 2010 +0900 +++ b/freeDiameter/tests/tests.h Fri Mar 05 19:01:48 2010 +0900 @@ -105,7 +105,7 @@ /* Minimum inits */ #define INIT_FD() { \ memset(fd_g_config, 0, sizeof(struct fd_config)); \ - CHECK( 0, fd_lib_init() ); \ + CHECK( 0, fd_lib_init(1) ); \ fd_log_threadname(basename(__FILE__)); \ (void) gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread); \ (void) gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0); \ diff -r f91fe0b85928 -r 8773740401a5 include/freeDiameter/libfreeDiameter.h --- a/include/freeDiameter/libfreeDiameter.h Thu Mar 04 17:32:00 2010 +0900 +++ b/include/freeDiameter/libfreeDiameter.h Fri Mar 05 19:01:48 2010 +0900 @@ -75,6 +75,22 @@ #include /* for basename if --dbg_file is specified */ #endif /* DEBUG */ + +/*============================================================*/ +/* INIT */ +/*============================================================*/ + +/* This function must be called first, before any call to another library function */ +/* If the parameter is not 0, the support for signals (fd_sig_register) is enabled, otherwise it is disabled */ +/* The function must be called while the application is single-threaded to enable support for signals */ +int fd_lib_init(int support_signals); + +/* Call this one when the application terminates, to destroy internal threads */ +void fd_lib_fini(void); + + + + /*============================================================*/ /* DEBUG */ /*============================================================*/ @@ -558,6 +574,31 @@ /*============================================================*/ +/* SIGNALS */ +/*============================================================*/ + +/* 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 (*callback)(int signal)); + +/* Remove the handler for a given signal */ +int fd_sig_unregister(int signal); + +/* Dump list of handlers */ +void fd_sig_dump(int level, int indent); + +/* Name of signals */ +#ifdef HAVE_SIGNALENT_H +extern const char *const fd_sig_str[]; +extern const int fd_sig_nstr; +# define SIGNALSTR(sig) (((sig) < fd_sig_nstr) ? fd_sig_str[(sig)] : "[unknown signal]") +#else /* HAVE_SIGNALENT_H */ +# define SIGNALSTR(sig) ("[no sig names]") +#endif /* HAVE_SIGNALENT_H */ + + +/*============================================================*/ /* LISTS */ /*============================================================*/ diff -r f91fe0b85928 -r 8773740401a5 libfreeDiameter/CMakeLists.txt --- a/libfreeDiameter/CMakeLists.txt Thu Mar 04 17:32:00 2010 +0900 +++ b/libfreeDiameter/CMakeLists.txt Fri Mar 05 19:01:48 2010 +0900 @@ -13,6 +13,7 @@ messages.c rt_data.c sessions.c + signal.c ) # Build as a shared library diff -r f91fe0b85928 -r 8773740401a5 libfreeDiameter/init.c --- a/libfreeDiameter/init.c Thu Mar 04 17:32:00 2010 +0900 +++ b/libfreeDiameter/init.c Fri Mar 05 19:01:48 2010 +0900 @@ -35,7 +35,8 @@ #include "libfD.h" -int fd_lib_init(void) +/* Initialize library variables and threads */ +int fd_lib_init(int support_signals) { int ret = 0; @@ -46,9 +47,21 @@ return ret; } + /* Initialize signals if requested */ + if (support_signals) { + CHECK_FCT( fd_sig_init() ); + } + /* Initialize the modules that need it */ fd_msg_eteid_init(); CHECK_FCT( fd_sess_init() ); return 0; } + +/* Stop all threads created in the library */ +void fd_lib_fini(void) +{ + fd_sess_fini(); + fd_sig_fini(); +} diff -r f91fe0b85928 -r 8773740401a5 libfreeDiameter/libfD.h --- a/libfreeDiameter/libfD.h Thu Mar 04 17:32:00 2010 +0900 +++ b/libfreeDiameter/libfD.h Fri Mar 05 19:01:48 2010 +0900 @@ -45,6 +45,9 @@ extern const char * type_base_name[]; void fd_msg_eteid_init(void); int fd_sess_init(void); +void fd_sess_fini(void); +int fd_sig_init(void); +void fd_sig_fini(void); /* Iterator on the rules of a parent object */ int fd_dict_iterate_rules ( struct dict_object *parent, void * data, int (*cb)(void *, struct dict_rule_data *) ); diff -r f91fe0b85928 -r 8773740401a5 libfreeDiameter/sessions.c --- a/libfreeDiameter/sessions.c Thu Mar 04 17:32:00 2010 +0900 +++ b/libfreeDiameter/sessions.c Fri Mar 05 19:01:48 2010 +0900 @@ -237,6 +237,14 @@ return 0; } +/* Terminate */ +void fd_sess_fini(void) +{ + TRACE_ENTRY(""); + CHECK_FCT_DO( fd_thr_term(&exp_thr), /* continue */ ); + return; +} + /* Create a new handler */ int fd_sess_handler_create_internal ( struct session_handler ** handler, void (*cleanup)(char * sid, session_state * state) ) { diff -r f91fe0b85928 -r 8773740401a5 libfreeDiameter/signal.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libfreeDiameter/signal.c Fri Mar 05 19:01:48 2010 +0900 @@ -0,0 +1,290 @@ +/********************************************************************************************************* +* Software License Agreement (BSD License) * +* Author: Sebastien Decugis * +* * +* 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 + +/* List of signal names */ +#ifdef HAVE_SIGNALENT_H +const char *const fd_sig_str[] = { +# include "signalent.h" +}; +const int fd_sig_nstr = sizeof fd_sig_str / sizeof fd_sig_str[0]; +#endif /* HAVE_SIGNALENT_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; + +/* Initialize the support for signals */ +int fd_sig_init(void) +{ + sigset_t sig_all; + + TRACE_ENTRY(""); + + if (sig_initialized) + return 0; + + /* 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, SIGNALSTR(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, SIGNALSTR(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, SIGNALSTR(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, SIGNALSTR(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, SIGNALSTR(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; +}