diff options
| author | Michael Biebl <biebl@debian.org> | 2012-06-29 20:12:44 +0200 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2012-06-29 20:12:44 +0200 |
| commit | 867254ea7c2b193fecf8cd36cc6e5dc53c290d92 (patch) | |
| tree | 7c698b403882736ab70c3efd524c3460f08c391c /src/main.c | |
| parent | de06e5715e780baade318f3490ac7a4c9ce84e32 (diff) | |
Imported Upstream version 0.9.5.95 upstream/0.9.5.95
Diffstat (limited to 'src/main.c')
| -rw-r--r-- | src/main.c | 193 |
1 files changed, 105 insertions, 88 deletions
diff --git a/src/main.c b/src/main.c index 4a21959f..e8ff2e4c 100644 --- a/src/main.c +++ b/src/main.c @@ -29,6 +29,7 @@ #include <errno.h> #include <stdlib.h> #include <signal.h> +#include <pthread.h> #include <unistd.h> #include <fcntl.h> #include <sys/stat.h> @@ -53,6 +54,7 @@ #include "nm-logging.h" #include "nm-policy-hosts.h" #include "nm-config.h" +#include "nm-posix-signals.h" #if !defined(NM_DIST_VERSION) # define NM_DIST_VERSION VERSION @@ -66,101 +68,107 @@ */ static NMManager *manager = NULL; static GMainLoop *main_loop = NULL; -static int quit_pipe[2] = { -1, -1 }; - static gboolean quit_early = FALSE; +static sigset_t signal_set; -static void -nm_signal_handler (int signo) +void *signal_handling_thread (void *arg); +/* + * Thread function waiting for signals and processing them. + * Wait for signals in signal set. The semantics of sigwait() require that all + * threads (including the thread calling sigwait()) have the signal masked, for + * reliable operation. Otherwise, a signal that arrives while this thread is + * not blocked in sigwait() might be delivered to another thread. + */ +void * +signal_handling_thread (void *arg) { - static int in_fatal = 0, x; - - /* avoid loops */ - if (in_fatal > 0) - return; - ++in_fatal; - - switch (signo) { - case SIGSEGV: - case SIGBUS: - case SIGILL: - case SIGABRT: - nm_log_warn (LOGD_CORE, "caught signal %d. Generating backtrace...", signo); - nm_logging_backtrace (); - exit (1); - break; - case SIGFPE: - case SIGPIPE: - /* let the fatal signals interrupt us */ - --in_fatal; - nm_log_warn (LOGD_CORE, "caught signal %d, shutting down abnormally. Generating backtrace...", signo); - nm_logging_backtrace (); - x = write (quit_pipe[1], "X", 1); - break; - case SIGINT: - case SIGTERM: - /* let the fatal signals interrupt us */ - --in_fatal; - nm_log_info (LOGD_CORE, "caught signal %d, shutting down normally.", signo); - quit_early = TRUE; - x = write (quit_pipe[1], "X", 1); - break; - case SIGHUP: - --in_fatal; - /* Reread config stuff like system config files, VPN service files, etc */ - break; - case SIGUSR1: - --in_fatal; - /* Play with log levels or something */ - break; - default: - signal (signo, nm_signal_handler); - break; - } + int signo; + + while (1) { + sigwait (&signal_set, &signo); + + switch (signo) { + case SIGSEGV: + case SIGBUS: + case SIGILL: + case SIGABRT: + case SIGQUIT: + nm_log_warn (LOGD_CORE, "caught signal %d. Generating backtrace...", signo); + nm_logging_backtrace (); + exit (1); + break; + case SIGFPE: + case SIGPIPE: + nm_log_warn (LOGD_CORE, "caught signal %d, shutting down abnormally. Generating backtrace...", signo); + nm_logging_backtrace (); + quit_early = TRUE; /* for quitting before entering the main loop */ + g_main_loop_quit (main_loop); + break; + case SIGINT: + case SIGTERM: + nm_log_info (LOGD_CORE, "caught signal %d, shutting down normally.", signo); + quit_early = TRUE; /* for quitting before entering the main loop */ + g_main_loop_quit (main_loop); + break; + case SIGHUP: + /* Reread config stuff like system config files, VPN service files, etc */ + nm_log_info (LOGD_CORE, "caught signal %d, not supported yet.", signo); + break; + case SIGUSR1: + /* Play with log levels or something */ + nm_log_info (LOGD_CORE, "caught signal %d, not supported yet.", signo); + break; + default: + nm_log_err (LOGD_CORE, "caught unexpected signal %d", signo); + break; + } + } + return NULL; } +/* + * Mask the signals we are interested in and create a signal handling thread. + * Because all threads inherit the signal mask from their creator, all threads + * in the process will have the signals masked. That's why setup_signals() has + * to be called before creating other threads. + */ static gboolean -quit_watch (GIOChannel *src, GIOCondition condition, gpointer user_data) -{ - - if (condition & G_IO_IN) { - nm_log_warn (LOGD_CORE, "quit request received, terminating..."); - g_main_loop_quit (main_loop); - } - - return FALSE; -} - -static void setup_signals (void) { - struct sigaction action; - sigset_t mask; - GIOChannel *quit_channel; + pthread_t signal_thread_id; + sigset_t old_sig_mask; + int status; + + sigemptyset (&signal_set); + sigaddset (&signal_set, SIGHUP); + sigaddset (&signal_set, SIGINT); + sigaddset (&signal_set, SIGQUIT); + sigaddset (&signal_set, SIGILL); + sigaddset (&signal_set, SIGABRT); + sigaddset (&signal_set, SIGFPE); + sigaddset (&signal_set, SIGBUS); + sigaddset (&signal_set, SIGSEGV); + sigaddset (&signal_set, SIGPIPE); + sigaddset (&signal_set, SIGTERM); + sigaddset (&signal_set, SIGUSR1); + + /* Block all signals of interest. */ + status = pthread_sigmask (SIG_BLOCK, &signal_set, &old_sig_mask); + if (status != 0) { + fprintf (stderr, _("Failed to set signal mask: %d"), status); + return FALSE; + } + /* Save original mask so that we could use it for child processes. */ + nm_save_original_signal_mask (old_sig_mask); - /* Set up our quit pipe */ - if (pipe (quit_pipe) < 0) { - fprintf (stderr, _("Failed to initialize SIGTERM pipe: %d"), errno); - exit (1); + /* Create the signal handling thread. */ + status = pthread_create (&signal_thread_id, NULL, signal_handling_thread, NULL); + if (status != 0) { + fprintf (stderr, _("Failed to create signal handling thread: %d"), status); + return FALSE; } - fcntl (quit_pipe[1], F_SETFL, O_NONBLOCK | fcntl (quit_pipe[1], F_GETFL)); - - quit_channel = g_io_channel_unix_new (quit_pipe[0]); - g_io_add_watch_full (quit_channel, G_PRIORITY_HIGH, G_IO_IN | G_IO_ERR, quit_watch, NULL, NULL); - - sigemptyset (&mask); - action.sa_handler = nm_signal_handler; - action.sa_mask = mask; - action.sa_flags = 0; - sigaction (SIGTERM, &action, NULL); - sigaction (SIGINT, &action, NULL); - sigaction (SIGILL, &action, NULL); - sigaction (SIGBUS, &action, NULL); - sigaction (SIGFPE, &action, NULL); - sigaction (SIGHUP, &action, NULL); - sigaction (SIGSEGV, &action, NULL); - sigaction (SIGABRT, &action, NULL); - sigaction (SIGUSR1, &action, NULL); + + return TRUE; } static gboolean @@ -380,7 +388,7 @@ main (int argc, char *argv[]) " [NONE,HW,RFKILL,ETHER,WIFI,BT,MB,DHCP4,DHCP6,PPP,\n" " WIFI_SCAN,IP4,IP6,AUTOIP4,DNS,VPN,SHARING,SUPPLICANT,\n" " AGENTS,SETTINGS,SUSPEND,CORE,DEVICE,OLPC,WIMAX,\n" - " INFINIBAND,FIREWALL]"), + " INFINIBAND,FIREWALL,ADSL]"), "HW,RFKILL,WIFI" }, { "connectivity-uri", 0, 0, G_OPTION_ARG_STRING, &connectivity_uri, "A http(s) address to check internet connectivity" }, { "connectivity-interval", 0, 0, G_OPTION_ARG_INT, &connectivity_interval, "the interval in seconds how often a connectivity check will be done" }, @@ -393,6 +401,10 @@ main (int argc, char *argv[]) exit (1); } + /* Set up unix signal handling */ + if (!setup_signals ()) + exit (1); + /* Set locale to be able to use environment variables */ setlocale (LC_ALL, ""); @@ -529,14 +541,19 @@ main (int argc, char *argv[]) dbus_glib_global_set_disable_legacy_property_access (); #endif - setup_signals (); - nm_logging_start (become_daemon); nm_log_info (LOGD_CORE, "NetworkManager (version " NM_DIST_VERSION ") is starting..."); success = FALSE; nm_log_info (LOGD_CORE, "Read config file %s", nm_config_get_path (config)); + nm_log_info (LOGD_CORE, "WEXT support is %s", +#if HAVE_WEXT + "enabled" +#else + "disabled" +#endif + ); main_loop = g_main_loop_new (NULL, FALSE); |