From 45e83de0ac116b5b1c2e3c23a40c6cde3be1f844 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Tue, 2 Jul 2013 13:10:14 +0200 Subject: [PATCH] main: Use signalfd instead of raw signals Copied from ConnMan's commit 6ad51830 where Daniel Wagner was explaining: "It's unsafe to call syslog in the terminated signal handler because syslog takes a lock. So when the signal handler kicks in and we were already in syslog, we have a nice deadlock." --- src/main.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 68 insertions(+), 12 deletions(-) diff --git a/src/main.c b/src/main.c index 1a0f297..9765b19 100644 --- a/src/main.c +++ b/src/main.c @@ -28,6 +28,7 @@ #include #include #include +#include #include @@ -91,16 +92,72 @@ static GMainLoop *main_loop = NULL; static volatile sig_atomic_t __terminated = 0; -static void sig_term(int sig) +static gboolean signal_handler(GIOChannel *channel, GIOCondition cond, + gpointer user_data) { - if (__terminated > 0) - return; + struct signalfd_siginfo si; + ssize_t result; + int fd; - __terminated = 1; + if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) + return FALSE; - near_info("Terminating"); + fd = g_io_channel_unix_get_fd(channel); - g_main_loop_quit(main_loop); + result = read(fd, &si, sizeof(si)); + if (result != sizeof(si)) + return FALSE; + + switch (si.ssi_signo) { + case SIGINT: + case SIGTERM: + if (__terminated == 0) { + near_info("Terminating"); + g_main_loop_quit(main_loop); + } + + __terminated = 1; + break; + } + + return TRUE; +} + +static guint setup_signalfd(void) +{ + GIOChannel *channel; + guint source; + sigset_t mask; + int fd; + + sigemptyset(&mask); + sigaddset(&mask, SIGINT); + sigaddset(&mask, SIGTERM); + + if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) { + perror("Failed to set signal mask"); + return 0; + } + + fd = signalfd(-1, &mask, 0); + if (fd < 0) { + perror("Failed to create signal descriptor"); + return 0; + } + + channel = g_io_channel_unix_new(fd); + + g_io_channel_set_close_on_unref(channel, TRUE); + g_io_channel_set_encoding(channel, NULL, NULL); + g_io_channel_set_buffered(channel, FALSE); + + source = g_io_add_watch(channel, + G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, + signal_handler, NULL); + + g_io_channel_unref(channel); + + return source; } static void disconnect_callback(DBusConnection *conn, void *user_data) @@ -161,7 +218,7 @@ int main(int argc, char *argv[]) DBusConnection *conn; DBusError err; GKeyFile *config; - struct sigaction sa; + guint signal; context = g_option_context_new(NULL); g_option_context_add_main_entries(context, options, NULL); @@ -184,6 +241,8 @@ int main(int argc, char *argv[]) main_loop = g_main_loop_new(NULL, FALSE); + signal = setup_signalfd(); + dbus_error_init(&err); conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NFC_SERVICE, &err); @@ -228,13 +287,10 @@ int main(int argc, char *argv[]) } } - memset(&sa, 0, sizeof(sa)); - sa.sa_handler = sig_term; - sigaction(SIGINT, &sa, NULL); - sigaction(SIGTERM, &sa, NULL); - g_main_loop_run(main_loop); + g_source_remove(signal); + __near_plugin_cleanup(); __near_agent_cleanup(); -- 2.7.4