daemon: use signalfd-based signal handling if available (#3778)

If signalfd(2) interface is available, prefer it over traditional signal
handlers. This is mostly intended to drop dedicated signal handling thread
and hook signal processing into libevent event loop in the most natural way.

Signed-off-by: Dmitry Antipov <dantipov@cloudlinux.com>

Signed-off-by: Dmitry Antipov <dantipov@cloudlinux.com>
This commit is contained in:
Dmitry Antipov 2022-09-07 23:12:35 +03:00 committed by GitHub
parent 2bcb8f8535
commit 050ee1cbbd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 75 additions and 9 deletions

View File

@ -539,6 +539,7 @@ endif()
include(LargeFileSupport)
set(NEEDED_HEADERS
sys/signalfd.h
sys/statvfs.h
xfs/xfs.h
xlocale.h)

View File

@ -6,6 +6,10 @@
#include <assert.h>
#include <errno.h>
#include <pthread.h>
#ifdef HAVE_SYS_SIGNALFD_H
#include <event2/event.h>
#include <sys/signalfd.h>
#endif /* signalfd API */
#include <signal.h>
#include <stdlib.h> /* abort(), daemon(), exit() */
#include <fcntl.h> /* 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<struct event_base*>(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;
}

View File

@ -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
{

View File

@ -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<Daemon*>(varg)->start(foreground);
return static_cast<Daemon*>(varg)->start(setupsigfn, foreground);
}
bool Daemon::init(int argc, char* argv[], bool* foreground, int* ret)

View File

@ -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;