From 54c01d3b57b4482ea4ffe4e552c50e4f4f9694b5 Mon Sep 17 00:00:00 2001 From: Julien BLACHE Date: Wed, 8 Apr 2009 13:45:57 +0200 Subject: [PATCH] Move signal processing to the main loop using signalfd --- src/main.c | 96 +++++++++++++++++++++++++++++++++++++++++++------ src/os-unix.c | 98 --------------------------------------------------- src/os.h | 1 - 3 files changed, 86 insertions(+), 109 deletions(-) diff --git a/src/main.c b/src/main.c index df737ae4..ffc80bd9 100644 --- a/src/main.c +++ b/src/main.c @@ -1,6 +1,7 @@ /* - * Driver for multi-threaded daap server + * Copyright (C) 2009 Julien BLACHE * + * Pieces from mt-daapd: * Copyright (C) 2003 Ron Pedde (ron@pedde.com) * * This program is free software; you can redistribute it and/or modify @@ -74,6 +75,7 @@ #ifdef HAVE_SYS_WAIT_H #include #endif +#include #include "daapd.h" @@ -275,15 +277,6 @@ mainloop_cb(int fd, short event, void *arg) rescan_counter += MAIN_SLEEP_INTERVAL; - /* Handle signals */ /* JB: FIXME */ - os_wait(0); - - if (config.stop) - { - event_loopbreak(); - return; - } - main_timer = (struct event *)arg; evutil_timerclear(&tv); tv.tv_sec = MAIN_SLEEP_INTERVAL; @@ -331,6 +324,58 @@ mainloop_cb(int fd, short event, void *arg) } } +static void +signal_cb(int fd, short event, void *arg) +{ + struct sigaction sa_ign; + struct sigaction sa_dfl; + struct signalfd_siginfo info; + int status; + + sa_ign.sa_handler=SIG_IGN; + sa_ign.sa_flags=0; + sigemptyset(&sa_ign.sa_mask); + + sa_dfl.sa_handler=SIG_DFL; + sa_dfl.sa_flags=0; + sigemptyset(&sa_dfl.sa_mask); + + while (read(fd, &info, sizeof(struct signalfd_siginfo)) > 0) + { + switch (info.ssi_signo) + { + case SIGCHLD: + DPRINTF(E_LOG, L_MAIN, "Got SIGCHLD, reaping children\n"); + + while (wait3(&status, WNOHANG, NULL) > 0) + /* Nothing. */ ; + break; + + case SIGINT: + case SIGTERM: + DPRINTF(E_LOG, L_MAIN, "Got SIGTERM or SIGINT\n"); + + config.stop = 1; + break; + + case SIGHUP: + DPRINTF(E_LOG, L_MAIN, "Got SIGHUP\n"); + + if (!config.stop) + { + conf_reload(); + err_reopen(); + + config.reload = 1; + } + break; + } + } + + if (config.stop) + event_base_loopbreak(evbase_main); +} + /** * Kick off the daap server and wait for events. * @@ -372,6 +417,9 @@ int main(int argc, char *argv[]) { char *plugindir; struct event *main_timer; struct timeval tv; + sigset_t sigs; + int sigfd; + struct event sig_event; int ret; int err; @@ -539,6 +587,20 @@ int main(int argc, char *argv[]) { DPRINTF(E_LOG,L_MAIN,"Plugin loaded: %s\n",plugin_get_description(phandle)); } + /* Block signals for all threads except the main one */ + sigemptyset(&sigs); + sigaddset(&sigs, SIGINT); + sigaddset(&sigs, SIGHUP); + sigaddset(&sigs, SIGCHLD); + sigaddset(&sigs, SIGTERM); + sigaddset(&sigs, SIGPIPE); + ret = pthread_sigmask(SIG_BLOCK, &sigs, NULL); + if (ret != 0) + { + DPRINTF(E_LOG, L_MAIN, "Error setting signal set\n"); + exit(EXIT_FAILURE); + } + runas = conf_alloc_string("general","runas","nobody"); if(!os_init(config.foreground,runas)) { @@ -691,6 +753,20 @@ int main(int argc, char *argv[]) { (!conf_get_int("scanning","skip_first",0))) config.reload = 1; /* force a reload on start */ + /* Set up signal fd */ + sigfd = signalfd(-1, &sigs, SFD_NONBLOCK | SFD_CLOEXEC); + if (sigfd < 0) + { + DPRINTF(E_FATAL, L_MAIN, "Could not setup signalfd: %s\n", strerror(errno)); + + mdns_deinit(); + exit(EXIT_FAILURE); + } + + event_set(&sig_event, sigfd, EV_READ, signal_cb, NULL); + event_base_set(evbase_main, &sig_event); + event_add(&sig_event, NULL); + /* Set up main timer */ evtimer_set(main_timer, mainloop_cb, main_timer); event_base_set(evbase_main, main_timer); diff --git a/src/os-unix.c b/src/os-unix.c index 67a12335..9d1e6675 100644 --- a/src/os-unix.c +++ b/src/os-unix.c @@ -64,7 +64,6 @@ /* Forwards */ static int _os_daemon_start(void); -static int _os_start_signal_handler(void); /* Globals */ char *_os_pidfile = PIDFILE; @@ -80,12 +79,6 @@ int os_init(int foreground, char *runas) { int pid_fd; FILE *pid_fp=NULL; - /* block signals and set up the signal handling thread */ - DPRINTF(E_LOG,L_MAIN,"Starting signal handler\n"); - if(_os_start_signal_handler()) { - DPRINTF(E_FATAL,L_MAIN,"Error starting signal handler %s\n",strerror(errno)); - } - /* open the pidfile, so it can be written once we detach */ if(!foreground) { if(-1 == (pid_fd = open(_os_pidfile,O_CREAT | O_WRONLY | O_TRUNC, 0644))) { @@ -349,97 +342,6 @@ int os_drop_privs(char *user) { return 0; } -/** - * wait for specified time, while setting signal flags - * (if necessary) - */ -void os_wait(int seconds) { - sigset_t intmask; - int status; - struct sigaction sa_ign; - struct sigaction sa_dfl; - - if (seconds > 0) - sleep(seconds); - - sigpending(&intmask); - - sa_ign.sa_handler=SIG_IGN; - sa_ign.sa_flags=0; - sigemptyset(&sa_ign.sa_mask); - - sa_dfl.sa_handler=SIG_DFL; - sa_dfl.sa_flags=0; - sigemptyset(&sa_dfl.sa_mask); - - - if(sigismember(&intmask, SIGCLD)) { - DPRINTF(E_LOG,L_MAIN,"Got CLD signal. Reaping\n"); - while (wait3(&status, WNOHANG, NULL) > 0) {}; - - sigaction(SIGCLD,&sa_ign,NULL); - sigaction(SIGCLD,&sa_dfl,NULL); - } - - if((sigismember(&intmask, SIGTERM)) || - (sigismember(&intmask, SIGINT))) { - DPRINTF(E_LOG,L_MAIN,"Got shutdown signal.\n"); - config.stop=1; - - sigaction(SIGTERM,&sa_ign,NULL); - sigaction(SIGTERM,&sa_dfl,NULL); - - sigaction(SIGINT,&sa_ign,NULL); - sigaction(SIGINT,&sa_dfl,NULL); - } - - if(sigismember(&intmask, SIGHUP)) { - DPRINTF(E_LOG,L_MAIN,"Got HUP signal.\n"); - /* if we can't reload, it keeps the old config file, - * so no real damage */ - conf_reload(); - err_reopen(); - - config.reload=1; - - sigaction(SIGHUP,&sa_ign,NULL); - sigaction(SIGHUP,&sa_dfl,NULL); - } -} - -/** - * Wait for signals and flag the main process. This is - * a thread handler for the signal processing thread. It - * does absolutely nothing except wait for signals. The rest - * of the threads are running with signals blocked, so this thread - * is guaranteed to catch all the signals. It sets flags in - * the config structure that the main thread looks for. Specifically, - * the stop flag (from an INT signal), and the reload flag (from HUP). - * \param arg NULL, but required of a thread procedure - */ -/** - * Block signals, then start the signal handler. The - * signal handler started by spawning a new thread on - * signal_handler(). - * - * \returns 0 on success, -1 on failure with errno set - */ -int _os_start_signal_handler(void) { - sigset_t set; - - if((sigemptyset(&set) == -1) || - (sigaddset(&set,SIGINT) == -1) || - (sigaddset(&set,SIGHUP) == -1) || - (sigaddset(&set,SIGCLD) == -1) || - (sigaddset(&set,SIGTERM) == -1) || - (sigaddset(&set,SIGPIPE) == -1) || - (pthread_sigmask(SIG_BLOCK, &set, NULL) == -1)) { - DPRINTF(E_LOG,L_MAIN,"Error setting signal set\n"); - return -1; - } - - return 0; -} /** * set the pidfile to a non-default value diff --git a/src/os.h b/src/os.h index 9b0ae66f..fbb2cc7f 100644 --- a/src/os.h +++ b/src/os.h @@ -28,7 +28,6 @@ /* backgrounding, signal handling, etc */ extern int os_init(int foreground, char *runas); extern void os_deinit(void); -extern void os_wait(int seconds); /* system native logging functions */ extern int os_opensyslog(void);