core: use GUnixSignalWatchSource to simplify signal handling

Replace the pthread_sigwait()-based signal handling with
g_unix_signal_add()-based handling, and get rid of all the
now-unnecessary calls to nm_unblock_posix_signals() when spawning
subprocesses.

As a bonus, this also fixes the "^C in gdb kills NM too" bug.
This commit is contained in:
Dan Winship
2015-01-12 11:31:10 -05:00
parent 1c435dc874
commit c5b3e93792
20 changed files with 43 additions and 271 deletions

View File

@@ -31,101 +31,59 @@
#include <glib.h>
#include <glib/gi18n.h>
#include <glib-unix.h>
#include <gmodule.h>
#include "main-utils.h"
#include "nm-posix-signals.h"
#include "nm-logging.h"
static sigset_t signal_set;
static gboolean *quit_early = NULL;
/*
* 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.
*/
static void *
signal_handling_thread (void *arg)
static gboolean
sighup_handler (gpointer user_data)
{
GMainLoop *main_loop = arg;
int signo;
/* Reread config stuff like system config files, VPN service files, etc */
nm_log_info (LOGD_CORE, "caught SIGHUP, not supported yet.");
while (1) {
sigwait (&signal_set, &signo);
return G_SOURCE_CONTINUE;
}
switch (signo) {
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 SIGPIPE:
/* silently ignore signal */
break;
default:
nm_log_err (LOGD_CORE, "caught unexpected signal %d", signo);
break;
}
}
return NULL;
static gboolean
sigint_handler (gpointer user_data)
{
GMainLoop *main_loop = user_data;
nm_log_info (LOGD_CORE, "caught SIGINT, shutting down normally.");
g_main_loop_quit (main_loop);
return G_SOURCE_REMOVE;
}
static gboolean
sigterm_handler (gpointer user_data)
{
GMainLoop *main_loop = user_data;
nm_log_info (LOGD_CORE, "caught SIGTERM, shutting down normally.");
g_main_loop_quit (main_loop);
return G_SOURCE_REMOVE;
}
/**
* nm_main_utils_setup_signals:
* @main_loop: the #GMainLoop to quit when SIGINT or SIGTERM is received
* @quit_early: location of a variable that will be set to TRUE when
* SIGINT or SIGTERM is received
*
* 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.
*
* Returns: %TRUE on success
* Sets up signal handling for NetworkManager.
*/
gboolean
nm_main_utils_setup_signals (GMainLoop *main_loop, gboolean *quit_early_ptr)
void
nm_main_utils_setup_signals (GMainLoop *main_loop)
{
pthread_t signal_thread_id;
sigset_t old_sig_mask;
int status;
g_return_if_fail (main_loop != NULL);
g_return_val_if_fail (main_loop != NULL, FALSE);
g_return_val_if_fail (quit_early_ptr != NULL, FALSE);
signal (SIGPIPE, SIG_IGN);
quit_early = quit_early_ptr;
sigemptyset (&signal_set);
sigaddset (&signal_set, SIGHUP);
sigaddset (&signal_set, SIGINT);
sigaddset (&signal_set, SIGTERM);
sigaddset (&signal_set, SIGPIPE);
/* 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);
/* Create the signal handling thread. */
status = pthread_create (&signal_thread_id, NULL, signal_handling_thread, main_loop);
if (status != 0) {
fprintf (stderr, _("Failed to create signal handling thread: %d"), status);
return FALSE;
}
return TRUE;
g_unix_signal_add (SIGHUP, sighup_handler, NULL);
g_unix_signal_add (SIGINT, sigint_handler, main_loop);
g_unix_signal_add (SIGTERM, sigterm_handler, main_loop);
}
gboolean