diff options
Diffstat (limited to '')
-rw-r--r-- | src/GlobalEvents.hxx | 5 | ||||
-rw-r--r-- | src/Main.cxx | 9 | ||||
-rw-r--r-- | src/SignalHandlers.cxx | 32 | ||||
-rw-r--r-- | src/SignalHandlers.hxx | 8 | ||||
-rw-r--r-- | src/event/SignalMonitor.cxx | 133 | ||||
-rw-r--r-- | src/event/SignalMonitor.hxx | 64 |
6 files changed, 233 insertions, 18 deletions
diff --git a/src/GlobalEvents.hxx b/src/GlobalEvents.hxx index fac116935..16de7e675 100644 --- a/src/GlobalEvents.hxx +++ b/src/GlobalEvents.hxx @@ -46,14 +46,13 @@ namespace GlobalEvents { /** the current song's tag has changed */ TAG, - /** SIGHUP received: reload configuration, roll log file */ - RELOAD, - /** a hardware mixer plugin has detected a change */ MIXER, +#ifdef WIN32 /** shutdown requested */ SHUTDOWN, +#endif MAX }; diff --git a/src/Main.cxx b/src/Main.cxx index cbf501267..a1a3fe976 100644 --- a/src/Main.cxx +++ b/src/Main.cxx @@ -351,6 +351,8 @@ idle_event_emitted(void) state_file->CheckModified(); } +#ifdef WIN32 + /** * Handler for GlobalEvents::SHUTDOWN. */ @@ -360,6 +362,8 @@ shutdown_event_emitted(void) main_loop->Break(); } +#endif + int main(int argc, char *argv[]) { #ifdef WIN32 @@ -436,7 +440,9 @@ int mpd_main(int argc, char *argv[]) GlobalEvents::Initialize(); GlobalEvents::Register(GlobalEvents::IDLE, idle_event_emitted); +#ifdef WIN32 GlobalEvents::Register(GlobalEvents::SHUTDOWN, shutdown_event_emitted); +#endif Path::GlobalInit(); @@ -486,7 +492,7 @@ int mpd_main(int argc, char *argv[]) setup_log_output(options.log_stderr); - initSigHandlers(); + SignalHandlersInit(*main_loop); if (!io_thread_start(&error)) { g_warning("%s", error->message); @@ -583,6 +589,7 @@ int mpd_main(int argc, char *argv[]) config_global_finish(); stats_global_finish(); io_thread_deinit(); + SignalHandlersFinish(); delete instance; delete main_loop; daemonize_finish(); diff --git a/src/SignalHandlers.cxx b/src/SignalHandlers.cxx index ef6be448b..9d43dbee1 100644 --- a/src/SignalHandlers.cxx +++ b/src/SignalHandlers.cxx @@ -19,6 +19,7 @@ #include "config.h" #include "SignalHandlers.hxx" +#include "event/SignalMonitor.hxx" #ifndef WIN32 @@ -32,14 +33,12 @@ #include <signal.h> -static void exit_signal_handler(gcc_unused int signum) -{ - GlobalEvents::Emit(GlobalEvents::SHUTDOWN); -} +static EventLoop *shutdown_loop; -static void reload_signal_handler(gcc_unused int signum) +static void +HandleShutdownSignal() { - GlobalEvents::Emit(GlobalEvents::RELOAD); + shutdown_loop->Break(); } static void @@ -58,8 +57,11 @@ handle_reload_event(void) #endif -void initSigHandlers(void) +void +SignalHandlersInit(EventLoop &loop) { + SignalMonitorInit(loop); + #ifndef WIN32 struct sigaction sa; @@ -68,12 +70,16 @@ void initSigHandlers(void) sa.sa_handler = SIG_IGN; x_sigaction(SIGPIPE, &sa); - sa.sa_handler = exit_signal_handler; - x_sigaction(SIGINT, &sa); - x_sigaction(SIGTERM, &sa); + shutdown_loop = &loop; + SignalMonitorRegister(SIGINT, HandleShutdownSignal); + SignalMonitorRegister(SIGTERM, HandleShutdownSignal); - GlobalEvents::Register(GlobalEvents::RELOAD, handle_reload_event); - sa.sa_handler = reload_signal_handler; - x_sigaction(SIGHUP, &sa); + SignalMonitorRegister(SIGHUP, handle_reload_event); #endif } + +void +SignalHandlersFinish() +{ + SignalMonitorFinish(); +} diff --git a/src/SignalHandlers.hxx b/src/SignalHandlers.hxx index 99f347fb0..90dab6dec 100644 --- a/src/SignalHandlers.hxx +++ b/src/SignalHandlers.hxx @@ -20,6 +20,12 @@ #ifndef MPD_SIGNAL_HANDLERS_HXX #define MPD_SIGNAL_HANDLERS_HXX -void initSigHandlers(void); +class EventLoop; + +void +SignalHandlersInit(EventLoop &loop); + +void +SignalHandlersFinish(); #endif diff --git a/src/event/SignalMonitor.cxx b/src/event/SignalMonitor.cxx new file mode 100644 index 000000000..172b47f55 --- /dev/null +++ b/src/event/SignalMonitor.cxx @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2003-2013 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" +#include "SignalMonitor.hxx" + +#ifndef WIN32 + +#include "WakeFD.hxx" +#include "SocketMonitor.hxx" +#include "util/Manual.hxx" +#include "system/FatalError.hxx" + +#include <atomic> +#include <algorithm> + +class SignalMonitor final : private SocketMonitor { + WakeFD fd; + +public: + SignalMonitor(EventLoop &_loop) + :SocketMonitor(_loop) { + SocketMonitor::Open(fd.Get()); + SocketMonitor::ScheduleRead(); + } + + ~SignalMonitor() { + /* prevent the descriptor to be closed twice */ + SocketMonitor::Steal(); + } + + void WakeUp() { + fd.Write(); + } + +private: + virtual bool OnSocketReady(unsigned flags) override; +}; + +/* this should be enough - is it? */ +static constexpr unsigned MAX_SIGNAL = 64; + +static SignalHandler signal_handlers[MAX_SIGNAL]; +static std::atomic_bool signal_pending[MAX_SIGNAL]; + +static Manual<SignalMonitor> monitor; + +static void +SignalCallback(int signo) +{ + assert(signal_handlers[signo] != nullptr); + + if (!signal_pending[signo].exchange(true)) + monitor->WakeUp(); +} + +void +SignalMonitorInit(EventLoop &loop) +{ + monitor.Construct(loop); +} + +static void +x_sigaction(int signum, const struct sigaction &act) +{ + if (sigaction(signum, &act, nullptr) < 0) + FatalSystemError("sigaction() failed"); +} + +void +SignalMonitorFinish() +{ + struct sigaction sa; + sa.sa_flags = 0; + sigemptyset(&sa.sa_mask); + sa.sa_handler = SIG_DFL; + + for (unsigned i = 0; i < MAX_SIGNAL; ++i) { + if (signal_handlers[i] != nullptr) { + x_sigaction(i, sa); + signal_handlers[i] = nullptr; + } + } + + std::fill_n(signal_pending, MAX_SIGNAL, false); + + monitor.Destruct(); +} + +void +SignalMonitorRegister(int signo, SignalHandler handler) +{ + assert(signal_handlers[signo] == nullptr); + assert(!signal_pending[signo]); + + signal_handlers[signo] = handler; + + struct sigaction sa; + sa.sa_flags = 0; + sigemptyset(&sa.sa_mask); + sa.sa_handler = SignalCallback; + x_sigaction(signo, sa); +} + +bool +SignalMonitor::OnSocketReady(unsigned) +{ + fd.Read(); + + for (unsigned i = 0; i < MAX_SIGNAL; ++i) + if (signal_pending[i].exchange(false)) + signal_handlers[i](); + + return true; +} + +#endif diff --git a/src/event/SignalMonitor.hxx b/src/event/SignalMonitor.hxx new file mode 100644 index 000000000..94ab0aa30 --- /dev/null +++ b/src/event/SignalMonitor.hxx @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2003-2013 The Music Player Daemon Project + * http://www.musicpd.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef MPD_SOCKET_SIGNAL_MONITOR_HXX +#define MPD_SOCKET_SIGNAL_MONITOR_HXX + +#include "check.h" + +class EventLoop; + +#ifndef WIN32 + +typedef void (*SignalHandler)(); + +/** + * Initialise the signal monitor subsystem. + */ +void +SignalMonitorInit(EventLoop &loop); + +/** + * Deinitialise the signal monitor subsystem. + */ +void +SignalMonitorFinish(); + +/** + * Register a handler for the specified signal. The handler will be + * invoked in a safe context. + */ +void +SignalMonitorRegister(int signo, SignalHandler handler); + +#else + +static inline void +SignalMonitorInit(EventLoop &) +{ +} + +static inline void +SignalMonitorFinish() +{ +} + +#endif + +#endif /* MAIN_NOTIFY_H */ |