In this article I will present to you a mechanism written in C for handling efficiently software signals in POSIX operating systems. The first thing you have to do is to create the configuration of the signals you want to support. After you decide the appropriate configuration you have to setup the signals support and register the configuration. Later on, when the various software signals occur a generic signal dispatcher will handle the signals according to the specified configuration.
Let’s start with the type of a single signal configuration:
/* * Copyright (C) 2014 Efstathios Chatzikyriakidis (stathis.chatzikyriakidis@gmail.com). * * 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef _SIGNAL_CONFIGURATION_TYPES_H_ #define _SIGNAL_CONFIGURATION_TYPES_H_ #include "shared-types.h" /* * type definitions. */ // signal configuration type definition. typedef struct signal_configuration_t { // the signal identifier. int signal; // flag indicating if the signal will be ignored. bool_t ignore; // signal action flags that will be used for the signal. int flags; // the handler of the signal. void (* handler) (void); } signal_configuration_t; #endif // _SIGNAL_CONFIGURATION_TYPES_H_
For the configuration of a signal we store information related to the signal number, a boolean indicating if the signal is ignored or not, a bit field for setting various options when registering the signal, and a possible signal handler in case the signal is not ignored. Now, suppose that we want to create a configuration for various signals in an application. We can create a source code unit for creating the configuration we want.
Here, follows the header of the source code unit:
/* * Copyright (C) 2014 Efstathios Chatzikyriakidis (stathis.chatzikyriakidis@gmail.com). * * 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef _SIGNALS_SUPPORT_UTILITY_H_ #define _SIGNALS_SUPPORT_UTILITY_H_ #include "shared-types.h" /* * function prototypes. */ bool_t setup_signals_support (void); #endif // _SIGNALS_SUPPORT_UTILITY_H_
Next, follows the implementation of an example setting a configuration:
/* * Copyright (C) 2014 Efstathios Chatzikyriakidis (stathis.chatzikyriakidis@gmail.com). * * 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see <http://www.gnu.org/licenses/>. */ #include <signal.h> #include "signals-support-utility.h" #include "signal-handlers-utility.h" #include "signal-dispatcher-utility.h" /* * variables. */ static const signal_configuration_t signals_table [] = { // ignored signals. { SIGTSTP, true, SA_RESTART, NULL }, { SIGINT, true, SA_RESTART, NULL }, { SIGTTOU, true, SA_RESTART, NULL }, { SIGTTIN, true, SA_RESTART, NULL }, { SIGHUP, true, SA_RESTART, NULL }, { SIGQUIT, true, SA_RESTART, NULL }, { SIGPIPE, true, SA_RESTART, NULL }, // non-ignored signals. { SIGTERM, false, SA_RESTART, signal_term_handler }, // end of signals configuration. { -1, true, 0, NULL } }; /* * functions. */ bool_t setup_signals_support (void) { set_signals_configuration (signals_table); return setup_registered_signals (); }
As you can see, in the above configuration we have ignored some signals and specified the signal handler ‘signal_term_handler’ for the signal SIGTERM. Also, all the signal configurations have the ‘SA_RESTART’ bit option set in the bit field of flags. A client can include the ‘signals-support-utility.h’ header file and call the ‘setup_signals_support’ function to register the configuration of the signals. The last missing part is the generic signal dispatcher which is used for dispatching the appropriate signal handler when signals occur.
So, next follows the header of the source code unit of the signal dispatcher:
/* * Copyright (C) 2014 Efstathios Chatzikyriakidis (stathis.chatzikyriakidis@gmail.com). * * 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef _SIGNAL_DISPATCHER_UTILITY_H_ #define _SIGNAL_DISPATCHER_UTILITY_H_ #include "signal-configuration-types.h" /* * function prototypes. */ void set_signals_configuration (const signal_configuration_t * const signals_table); bool_t setup_registered_signals (void); #endif // _SIGNAL_DISPATCHER_UTILITY_H_
Let’s end this article by presenting the implementation of the source code unit of the signal dispatcher:
/* * Copyright (C) 2014 Efstathios Chatzikyriakidis (stathis.chatzikyriakidis@gmail.com). * * 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 3 of the License, or * (at your option) any later version. * * This program 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 program. If not, see <http://www.gnu.org/licenses/>. */ #include <string.h> #include <signal.h> #include <errno.h> #include "signal-dispatcher-utility.h" #include "logging-utility.h" #include "i18n-macros.h" /* * messages. */ static const string_t const failed_to_initialize_all_signals_set_message = N_("Failed to initialize the set of all signals."); static const string_t const failed_to_change_action_of_signal_message = N_("Failed to change the action of the signal:"); /* * variables. */ static const signal_configuration_t * internal_signals_table = NULL; /* * function prototypes. */ static void signal_handler_dispatcher (const int signal); /* * functions. */ bool_t setup_registered_signals (void) { struct sigaction signal_action; memset (&signal_action, 0, sizeof (signal_action)); if (sigfillset (&signal_action.sa_mask) < 0) { log_error (_(failed_to_initialize_all_signals_set_message)); return false; } for (int i = 0; internal_signals_table[i].signal != -1; i++) { const signal_configuration_t configuration = internal_signals_table[i]; signal_action.sa_flags = configuration.flags; signal_action.sa_handler = configuration.ignore ? SIG_IGN : signal_handler_dispatcher; if (sigaction (configuration.signal, &signal_action, NULL) < 0) { log_error ("%s '%s'.", _(failed_to_change_action_of_signal_message), strsignal (configuration.signal)); return false; } } return true; } void set_signals_configuration (const signal_configuration_t * const signals_table) { internal_signals_table = signals_table; } static void signal_handler_dispatcher (const int signal) { const int preserve_errno = errno; for (int i = 0; internal_signals_table[i].signal != -1; i++) { const signal_configuration_t configuration = internal_signals_table[i]; if (configuration.signal == signal) { if (configuration.handler) { configuration.handler (); } break; } } errno = preserve_errno; }
Happy Hacking!