Related question here and here.
In the Linux GPLv3+ project https://github.com/bstarynk/helpcovid/ (multi-threaded, C++17, web server application) commit b616defc5e54ba869. The need is to be able to terminate gracefully such a web server (interacting with some PostGreSQL database using libpqxx
). So issue#35.
I did read both signal(7) and signal-safety(7) and signalfd(2). And I am aware of criticisms against signalfd.
I have a single background C++ std::thread
poll(2)-ing on several file descriptors. See file hcv_background.cc
where the hcv_start_background_thread
function is called from main
function in file hcv_main.cc
and the created std::thread
runs the hcv_background_thread_body
function (an event loop doing the poll(2)....)
So hcv_start_background_thread
has:
{
sigset_t sigmaskbits;
memset (&sigmaskbits, 0, sizeof(sigmaskbits));
sigemptyset(&sigmaskbits);
sigaddset(&sigmaskbits, SIGTERM);
sigaddset(&sigmaskbits, SIGHUP);
sigaddset(&sigmaskbits, SIGXCPU);
sigaddset(&sigmaskbits, SIGPIPE);
/// http://man7.org/linux/man-pages/man2/sigprocmask.2.html
if (sigprocmask(SIG_UNBLOCK, &sigmaskbits, nullptr))
HCV_FATALOUT("hcv_start_background_thread: sigprocmask failure");
HCV_DEBUGOUT("hcv_start_background_thread sigprocmask done");
hcv_bg_signal_fd = signalfd(-1, &sigmaskbits, SFD_NONBLOCK | SFD_CLOEXEC);
if (hcv_bg_signal_fd < 0)
HCV_FATALOUT("hcv_start_background_thread: signalfd failure");
HCV_DEBUGOUT("hcv_start_background_thread hcv_bg_signal_fd=" << hcv_bg_signal_fd);
}
and the hcv_background_thread_body
function has an event loop doing
while (!hcv_should_stop_bg_thread.load())
{
struct pollfd polltab[4];
memset(&polltab, 0, sizeof(polltab));
polltab[0].fd = hcv_bg_event_fd;
polltab[0].events = POLL_IN;
polltab[1].fd = hcv_bg_signal_fd;
polltab[1].events = POLL_IN;
polltab[1].fd = hcv_bg_timer_fd;
polltab[1].events = POLL_IN;
HCV_DEBUGOUT("hcv_background_thread_body before poll");
int nbfd = poll(polltab, 3,
hcv_debugging.load()?(2*HCV_BACKGROUND_TICK_TIMEOUT):HCV_BACKGROUND_TICK_TIMEOUT);
and later in the same event loop
if (nbfd>0) /* some file descriptor is readable */
{
HCV_DEBUGOUT("hcv_background_thread_body: after poll nbfd:" << nbfd);
if ((polltab[0].revents & POLL_IN) && polltab[0].fd == hcv_bg_event_fd)
{
int64_t evrk=0;
HCV_DEBUGOUT("hcv_background_thread_body pollable hcv_bg_event_fd="
<< hcv_bg_event_fd);
int byrd = read (hcv_bg_event_fd, &evrk, sizeof(evrk));
if (byrd==sizeof(evrk))
{
HCV_DEBUGOUT("hcv_background_thread_body: got " << evrk
<< " from hcv_bg_event_fd=" << hcv_bg_event_fd);
hcv_bg_do_event(evrk);
}
else
HCV_SYSLOGOUT(LOG_WARNING,
"hcv_background_thread_body read hcv_bg_event_fd#" <<hcv_bg_event_fd << " failed, byrd=" << byrd);
};
if ((polltab[1].revents & POLL_IN) && polltab[1].fd == hcv_bg_signal_fd)
{
HCV_DEBUGOUT("hcv_background_thread_body pollable hcv_bg_signal_fd="
<< hcv_bg_signal_fd);
struct signalfd_siginfo signalinfo;
memset (&signalinfo, 0, sizeof(signalinfo));
int byrd = read(hcv_bg_signal_fd, &signalinfo, sizeof(signalinfo));
if (byrd < 0)
HCV_FATALOUT("hcv_background_thread_body: failed read of hcv_bg_signal_fd="
<< hcv_bg_signal_fd);
else if (byrd != sizeof(signalinfo))
// should never happen... see signalfd(2)
HCV_FATALOUT("hcv_background_thread_body: corrupted read of hcv_bg_signal_fd="
<< hcv_bg_signal_fd << ", byrd=" << byrd);
HCV_DEBUGOUT("hcv_background_thread_body: got signalinfo #" << signalinfo.ssi_signo
<< " from hcv_bg_signal_fd=" << hcv_bg_signal_fd);
if (signalinfo.ssi_signo == SIGTERM)
{
HCV_SYSLOGOUT(LOG_NOTICE, "hcv_background_thread_body got SIGTERM at "
<< (hcv_monotonic_real_time() - hcv_monotonic_start_time)
<< " elapsed seconds");
hcv_process_SIGTERM_signal();
hcv_should_stop_bg_thread.store (true);
}
But hcv_process_SIGTERM_signal
never got called.
What am I doing wrong?