diff options
author | Stef Walter <stefw@gnome.org> | 2014-03-06 09:43:25 +0100 |
---|---|---|
committer | Stef Walter <stefw@gnome.org> | 2014-03-06 18:40:24 +0100 |
commit | 5a8275348a250824491ccf559f9192a1abb38fc3 (patch) | |
tree | 57df8b31ab816dced0f21c50cdade562dcd7f028 | |
parent | 636113849f970af6819ef599d207419c4881f8fb (diff) |
daemon: Use GLib unix signal handling
Rather than our own home rolled version.
-rw-r--r-- | daemon/control/gkd-control-server.c | 15 | ||||
-rw-r--r-- | daemon/gkd-main.c | 113 | ||||
-rw-r--r-- | daemon/test-shutdown.c | 32 |
3 files changed, 67 insertions, 93 deletions
diff --git a/daemon/control/gkd-control-server.c b/daemon/control/gkd-control-server.c index 9966e979..5a81eb49 100644 --- a/daemon/control/gkd-control-server.c +++ b/daemon/control/gkd-control-server.c @@ -241,8 +241,19 @@ control_process (EggBuffer *req, GIOChannel *channel) if (cdata) { g_return_if_fail (!egg_buffer_has_error (&cdata->buffer)); egg_buffer_set_uint32 (&cdata->buffer, 0, cdata->buffer.len); - g_io_add_watch_full (channel, G_PRIORITY_DEFAULT, G_IO_OUT | G_IO_HUP, - control_output, cdata, control_data_free); + + /* Can't send response in main loop, send here */ + if (op == GKD_CONTROL_OP_QUIT) { + if (write (g_io_channel_unix_get_fd (channel), + cdata->buffer.buf, cdata->buffer.len) != cdata->buffer.len) + g_message ("couldn't write response to close control request"); + control_data_free (cdata); + + /* Any other response, send in the main loop */ + } else { + g_io_add_watch_full (channel, G_PRIORITY_DEFAULT, G_IO_OUT | G_IO_HUP, + control_output, cdata, control_data_free); + } } } diff --git a/daemon/gkd-main.c b/daemon/gkd-main.c index 6664c289..15728a59 100644 --- a/daemon/gkd-main.c +++ b/daemon/gkd-main.c @@ -61,6 +61,7 @@ #include <glib.h> #include <glib/gi18n.h> #include <glib-object.h> +#include <glib-unix.h> #include <gcrypt.h> @@ -81,8 +82,6 @@ typedef int socklen_t; EGG_SECURE_DECLARE (daemon_main); -static GMainLoop *loop = NULL; - /* ----------------------------------------------------------------------------- * COMMAND LINE */ @@ -127,8 +126,7 @@ static gchar* login_password = NULL; static gchar* control_directory = NULL; static guint timeout_id = 0; static gboolean initialization_completed = FALSE; -static gboolean sig_thread_valid = FALSE; -static pthread_t sig_thread; +static GMainLoop *loop = NULL; static GOptionEntry option_entries[] = { { "start", 's', 0, G_OPTION_ARG_NONE, &run_for_start, @@ -396,96 +394,27 @@ dump_diagnostics (void) * SIGNALS */ -static sigset_t signal_set; -static gint signal_quitting = 0; - -static gpointer -signal_thread (gpointer user_data) -{ - GMainLoop *loop = user_data; - int sig, err; - - for (;;) { - err = sigwait (&signal_set, &sig); - if (err != EINTR && err != 0) { - g_warning ("couldn't wait for signals: %s", g_strerror (err)); - return NULL; - } - - switch (sig) { - case SIGUSR1: -#ifdef WITH_DEBUG - dump_diagnostics (); -#endif /* WITH_DEBUG */ - break; - case SIGPIPE: - /* Ignore */ - break; - case SIGHUP: - case SIGTERM: - g_atomic_int_set (&signal_quitting, 1); - g_main_loop_quit (loop); - return NULL; - default: - g_warning ("received unexpected signal when waiting for signals: %d", sig); - break; - } - } - - g_assert_not_reached (); - return NULL; -} - -static void -setup_signal_handling (GMainLoop *loop) -{ - int res; - - /* - * Block these signals for this thread, and any threads - * started up after this point (so essentially all threads). - * - * We also start a signal handling thread which uses signal_set - * to catch the various signals we're interested in. - */ - - sigemptyset (&signal_set); - sigaddset (&signal_set, SIGPIPE); - sigaddset (&signal_set, SIGHUP); - sigaddset (&signal_set, SIGTERM); - sigaddset (&signal_set, SIGUSR1); - pthread_sigmask (SIG_BLOCK, &signal_set, NULL); - - res = pthread_create (&sig_thread, NULL, signal_thread, loop); - if (res == 0) { - sig_thread_valid = TRUE; - } else { - g_warning ("couldn't startup thread for signal handling: %s", - g_strerror (res)); - } -} - void gkd_main_quit (void) { - /* - * Send a signal to terminate our signal thread, - * which in turn runs stops the main loop and that - * starts the shutdown process. - */ + g_main_loop_quit (loop); +} - if (sig_thread_valid) - pthread_kill (sig_thread, SIGTERM); - else - raise (SIGTERM); +static gboolean +on_signal_term (gpointer user_data) +{ + gkd_main_quit (); + g_debug ("received signal, terminating"); + return FALSE; } -static void -cleanup_signal_handling (void) +static gboolean +on_signal_usr1 (gpointer user_data) { - /* The thread is not joinable, so cleans itself up */ - if (!g_atomic_int_get (&signal_quitting)) - g_warning ("gkr_daemon_quit() was not used to shutdown the daemon"); +#ifdef WITH_DEBUG + dump_diagnostics (); +#endif + return TRUE; } /* ----------------------------------------------------------------------------- @@ -1018,10 +947,14 @@ main (int argc, char *argv[]) cleanup_and_exit (1); } + signal (SIGPIPE, SIG_IGN); + /* The whole forking and daemonizing dance starts here. */ fork_and_print_environment(); - setup_signal_handling (loop); + g_unix_signal_add (SIGTERM, on_signal_term, loop); + g_unix_signal_add (SIGHUP, on_signal_term, loop); + g_unix_signal_add (SIGUSR1, on_signal_usr1, loop); /* Prepare logging a second time, since we may be in a different process */ prepare_logging(); @@ -1035,10 +968,8 @@ main (int argc, char *argv[]) /* This wraps everything up in order */ egg_cleanup_perform (); - /* Wrap up signal handling here */ - cleanup_signal_handling (); - g_free (control_directory); + g_debug ("exiting cleanly"); return 0; } diff --git a/daemon/test-shutdown.c b/daemon/test-shutdown.c index b2fdb0cf..28f6a9e1 100644 --- a/daemon/test-shutdown.c +++ b/daemon/test-shutdown.c @@ -72,6 +72,36 @@ teardown (Test *test, } static void +test_sigterm (Test *test, + gconstpointer unused) +{ + const gchar *argv[] = { + BUILDDIR "/gnome-keyring-daemon", "--foreground", + "--components=secrets,pkcs11", NULL + }; + + const gchar *control; + gchar **output; + gint status; + GPid pid; + + output = gkd_test_launch_daemon (test->directory, argv, &pid, NULL); + + control = g_environ_getenv (output, "GNOME_KEYRING_CONTROL"); + g_assert_cmpstr (control, !=, NULL); + + g_assert (gkd_control_unlock (control, "booo")); + g_strfreev (output); + + /* Terminate the daemon */ + g_assert_cmpint (kill (pid, SIGTERM), ==, 0); + + /* Daemon should exit cleanly */ + g_assert_cmpint (waitpid (pid, &status, 0), ==, pid); + g_assert_cmpint (status, ==, 0); +} + +static void test_close_connection (Test *test, gconstpointer unused) { @@ -110,6 +140,8 @@ main (int argc, char **argv) g_test_add ("/daemon/shutdown/dbus-connection", Test, NULL, setup, test_close_connection, teardown); + g_test_add ("/daemon/shutdown/sigterm", Test, NULL, + setup, test_sigterm, teardown); return g_test_run (); } |