diff --git a/CMakeLists.txt b/CMakeLists.txt index 4c5b25b3e..0ec58ebd1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -539,6 +539,7 @@ endif() include(LargeFileSupport) set(NEEDED_HEADERS + sys/signalfd.h sys/statvfs.h xfs/xfs.h xlocale.h) diff --git a/daemon/daemon-posix.cc b/daemon/daemon-posix.cc index e8b289613..7b4aeacfb 100644 --- a/daemon/daemon-posix.cc +++ b/daemon/daemon-posix.cc @@ -6,6 +6,10 @@ #include #include #include +#ifdef HAVE_SYS_SIGNALFD_H +#include +#include +#endif /* signalfd API */ #include #include /* abort(), daemon(), exit() */ #include /* open() */ @@ -30,7 +34,11 @@ using namespace std::literals; static dtr_callbacks const* callbacks = nullptr; static void* callback_arg = nullptr; +#ifdef HAVE_SYS_SIGNALFD_H +static int sigfd = -1; +#else static int signal_pipe[2]; +#endif /* signalfd API */ /*** **** @@ -63,6 +71,55 @@ static void handle_signal(int sig) } } +#ifdef HAVE_SYS_SIGNALFD_H + +static void handle_signals(evutil_socket_t fd, short /*what*/, void* /*arg*/) +{ + struct signalfd_siginfo fdsi; + + if (read(fd, &fdsi, sizeof(fdsi)) != sizeof(fdsi)) + assert("Error reading signal descriptor" && 0); + else + handle_signal(fdsi.ssi_signo); +} + +static bool setup_signals(void* arg) +{ + sigset_t mask = {}; + struct event* sigev = nullptr; + struct event_base* base = static_cast(arg); + + sigemptyset(&mask); + sigaddset(&mask, SIGINT); + sigaddset(&mask, SIGTERM); + sigaddset(&mask, SIGHUP); + + if (sigprocmask(SIG_BLOCK, &mask, nullptr) < 0) + return false; + + sigfd = signalfd(-1, &mask, 0); + if (sigfd < 0) + return false; + + sigev = event_new(base, sigfd, EV_READ | EV_PERSIST, handle_signals, nullptr); + if (sigev == nullptr) + { + close(sigfd); + return false; + } + + if (event_add(sigev, nullptr) < 0) + { + event_del(sigev); + close(sigfd); + return false; + } + + return true; +} + +#else /* no signalfd API */ + static void send_signal_to_pipe(int sig) { int const old_errno = errno; @@ -142,6 +199,8 @@ static bool setup_signal_handler(int sig, tr_error** error) return true; } +#endif /* signalfd API */ + /*** **** ***/ @@ -207,6 +266,7 @@ bool dtr_daemon(dtr_callbacks const* cb, void* cb_arg, bool foreground, int* exi #endif } +#ifndef HAVE_SYS_SIGNALFD_H pthread_t signal_thread; if (!create_signal_handler_thread(&signal_thread, error)) @@ -220,9 +280,14 @@ bool dtr_daemon(dtr_callbacks const* cb, void* cb_arg, bool foreground, int* exi return false; } - *exit_code = cb->on_start(cb_arg, foreground); + *exit_code = cb->on_start(cb_arg, nullptr, foreground); +#else + *exit_code = cb->on_start(cb_arg, setup_signals, foreground); +#endif /* signalfd API */ +#ifndef HAVE_SYS_SIGNALFD_H destroy_signal_handler_thread(signal_thread); +#endif /* no signalfd API */ return true; } diff --git a/daemon/daemon-win32.cc b/daemon/daemon-win32.cc index d60f8f7c3..7392b0e46 100644 --- a/daemon/daemon-win32.cc +++ b/daemon/daemon-win32.cc @@ -171,7 +171,7 @@ static DWORD WINAPI handle_service_ctrl(DWORD control_code, DWORD /*event_type*/ static unsigned int __stdcall service_thread_main(void* /*context*/) { - return callbacks->on_start(callback_arg, false); + return callbacks->on_start(callback_arg, nullptr, false); } static VOID WINAPI service_main(DWORD /*argc*/, LPWSTR* /*argv*/) @@ -238,7 +238,7 @@ bool dtr_daemon(dtr_callbacks const* cb, void* cb_arg, bool foreground, int* exi return false; } - *exit_code = cb->on_start(cb_arg, true); + *exit_code = cb->on_start(cb_arg, nullptr, true); } else { diff --git a/daemon/daemon.cc b/daemon/daemon.cc index a82daf4cc..7c164b2f6 100644 --- a/daemon/daemon.cc +++ b/daemon/daemon.cc @@ -90,7 +90,7 @@ public: bool init(int argc, char* argv[], bool* foreground, int* ret); bool parseArgs(int argc, char const** argv, bool* dump_settings, bool* foreground, int* exit_code); bool reopenLogFile(char const* filename); - int start(bool foreground); + int start(bool (*setupsigfn)(void*), bool foreground); void periodicUpdate(); void reportStatus(); void reconfigure(); @@ -731,7 +731,7 @@ void Daemon::stop(void) event_base_loopexit(ev_base_, nullptr); } -int Daemon::start(bool foreground) +int Daemon::start(bool (*setupsigfn)(void*), bool foreground) { bool boolVal; bool pidfile_created = false; @@ -748,7 +748,7 @@ int Daemon::start(bool foreground) /* setup event state */ ev_base_ = event_base_new(); - if (ev_base_ == nullptr) + if (ev_base_ == nullptr || (setupsigfn ? setupsigfn(ev_base_) : true) == false) { auto const error_code = errno; auto const errmsg = fmt::format( @@ -937,9 +937,9 @@ CLEANUP: return 0; } -static int daemon_start(void* varg, bool foreground) +static int daemon_start(void* varg, bool (*setupsigfn)(void*), bool foreground) { - return static_cast(varg)->start(foreground); + return static_cast(varg)->start(setupsigfn, foreground); } bool Daemon::init(int argc, char* argv[], bool* foreground, int* ret) diff --git a/daemon/daemon.h b/daemon/daemon.h index d681e12f7..e598f90e7 100644 --- a/daemon/daemon.h +++ b/daemon/daemon.h @@ -9,7 +9,7 @@ struct tr_error; typedef struct dtr_callbacks { - int (*on_start)(void* arg, bool foreground); + int (*on_start)(void* arg, bool (*setupsigfn)(void*), bool foreground); void (*on_stop)(void* arg); void (*on_reconfigure)(void* arg); } dtr_callbacks;