about summary refs log tree commit diff
path: root/src/main.c
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2012-06-29 20:12:44 +0200
committerMichael Biebl <biebl@debian.org>2012-06-29 20:12:44 +0200
commit867254ea7c2b193fecf8cd36cc6e5dc53c290d92 (patch)
tree7c698b403882736ab70c3efd524c3460f08c391c /src/main.c
parentde06e5715e780baade318f3490ac7a4c9ce84e32 (diff)
Imported Upstream version 0.9.5.95 upstream/0.9.5.95
Diffstat (limited to 'src/main.c')
-rw-r--r--src/main.c193
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);