diff --git a/lib/common/mainloop.c b/lib/common/mainloop.c old mode 100644 new mode 100755 index b02ba1ff0e..6afd407296 --- a/lib/common/mainloop.c +++ b/lib/common/mainloop.c @@ -1,232 +1,240 @@ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #ifndef _GNU_SOURCE # define _GNU_SOURCE #endif #include #include #include #include #include static gboolean crm_trigger_prepare(GSource* source, gint *timeout) { crm_trigger_t *trig = (crm_trigger_t*)source; return trig->trigger; } static gboolean crm_trigger_check(GSource* source) { crm_trigger_t *trig = (crm_trigger_t*)source; return trig->trigger; } static gboolean crm_trigger_dispatch(GSource *source, GSourceFunc callback, gpointer userdata) { crm_trigger_t *trig = (crm_trigger_t*)source; trig->trigger = FALSE; if(callback) { return callback(trig->user_data); } return TRUE; } static GSourceFuncs crm_trigger_funcs = { crm_trigger_prepare, crm_trigger_check, crm_trigger_dispatch, NULL }; static crm_trigger_t * mainloop_setup_trigger( GSource *source, int priority, gboolean (*dispatch)(gpointer user_data), gpointer userdata) { crm_trigger_t *trigger = NULL; trigger = (crm_trigger_t*) source; trigger->id = 0; trigger->trigger = FALSE; trigger->user_data = userdata; if(dispatch) { g_source_set_callback(source, dispatch, trigger, NULL); } g_source_set_priority(source, priority); g_source_set_can_recurse(source, FALSE); trigger->id = g_source_attach(source, NULL); return trigger; } crm_trigger_t * mainloop_add_trigger( int priority, gboolean (*dispatch)(gpointer user_data), gpointer userdata) { GSource *source = NULL; CRM_ASSERT(sizeof(crm_trigger_t) > sizeof(GSource)); source = g_source_new(&crm_trigger_funcs, sizeof(crm_trigger_t)); CRM_ASSERT(source != NULL); return mainloop_setup_trigger(source, priority, dispatch, userdata); } void mainloop_set_trigger(crm_trigger_t* source) { source->trigger = TRUE; } gboolean mainloop_destroy_trigger(crm_trigger_t* source) { source->trigger = FALSE; if (source->id > 0) { g_source_remove(source->id); } return TRUE; } typedef struct signal_s { crm_trigger_t trigger; /* must be first */ void (*handler)(int sig); int signal; } crm_signal_t; static crm_signal_t *crm_signals[NSIG]; static gboolean crm_signal_dispatch(GSource *source, GSourceFunc callback, gpointer userdata) { crm_signal_t *sig = (crm_signal_t*)source; crm_info("Invoking handler for signal %d: %s", sig->signal, strsignal(sig->signal)); sig->trigger.trigger = FALSE; if(sig->handler) { sig->handler(sig->signal); } return TRUE; } static void mainloop_signal_handler(int sig) { if(sig > 0 && sig < NSIG && crm_signals[sig] != NULL) { mainloop_set_trigger((crm_trigger_t*)crm_signals[sig]); } } static GSourceFuncs crm_signal_funcs = { crm_trigger_prepare, crm_trigger_check, crm_signal_dispatch, NULL }; gboolean crm_signal(int sig, void (*dispatch)(int sig)) { sigset_t mask; struct sigaction sa; struct sigaction old; if(sigemptyset(&mask) < 0) { crm_perror(LOG_ERR, "Call to sigemptyset failed"); return FALSE; } sa.sa_handler = dispatch; sa.sa_flags = SA_RESTART; sa.sa_mask = mask; if(sigaction(sig, &sa, &old) < 0) { crm_perror(LOG_ERR, "Could not install signal handler for signal %d", sig); return FALSE; } return TRUE; } gboolean mainloop_add_signal(int sig, void (*dispatch)(int sig)) { GSource *source = NULL; + int priority = G_PRIORITY_HIGH - 1; + if(sig == SIGTERM) { + /* TERM is higher priority than other signals, + * signals are higher priority than other ipc. + * Yes, minus: smaller is "higher" + */ + priority--; + } if(sig >= NSIG || sig < 0) { crm_err("Signal %d is out of range", sig); return FALSE; } else if(crm_signals[sig] != NULL) { crm_err("Signal handler for %d is already installed", sig); return FALSE; } CRM_ASSERT(sizeof(crm_signal_t) > sizeof(GSource)); source = g_source_new(&crm_signal_funcs, sizeof(crm_signal_t)); - crm_signals[sig] = (crm_signal_t*)mainloop_setup_trigger(source, G_PRIORITY_HIGH, NULL, NULL); + crm_signals[sig] = (crm_signal_t*)mainloop_setup_trigger(source, priority, NULL, NULL); CRM_ASSERT(crm_signals[sig] != NULL); crm_signals[sig]->handler = dispatch; crm_signals[sig]->signal = sig; if(crm_signal(sig, mainloop_signal_handler) == FALSE) { crm_signal_t *tmp = crm_signals[sig]; crm_signals[sig] = NULL; mainloop_destroy_trigger((crm_trigger_t*)tmp); return FALSE; } return TRUE; } gboolean mainloop_destroy_signal(int sig) { crm_signal_t *tmp = NULL; if(sig >= NSIG || sig < 0) { crm_err("Signal %d is out of range", sig); return FALSE; } else if(crm_signal(sig, NULL) == FALSE) { crm_perror(LOG_ERR, "Could not uninstall signal handler for signal %d", sig); return FALSE; } else if(crm_signals[sig] == NULL) { return TRUE; } tmp = crm_signals[sig]; crm_signals[sig] = NULL; mainloop_destroy_trigger((crm_trigger_t*)tmp); return TRUE; }