3

My program has an event loop disciplined by epoll (for I/O) and condition variables (for other message activity), as well as a worker thread responsible for catching signals (SIGINT, SIGTERM, SIGHUP). SIGINT, SIGTERM, SIGHUP and SIGPIPE are blocked in all other threads.

My epoll_wait calls have a 500ms timeout, but I am trying to reduce context switches and use an infinite epoll_wait instead, woken by pipe activity when the main thread decides it's time to quit the program and the event loop should be stopped.

Similarly, my sigtimedwait call has a 500ms timeout (and checks a std::atomic<bool> after each call, to see whether it needs to stop), and I'd like to replace this with something that doesn't need to keep waking to check for interruption.

Can I raise a signal from the main thread to the signal-watching thread to achieve this, or something like that? Or is there a better way to catch signals in this day and age?

This is on CentOS 6 and 7 (though a general POSIX solution would be preferred — bonus points for mere standard C++11!).

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055

1 Answers1

5

Use signal file descriptors, instead of signal handlers.

Instead of a signal handler, the receipt of a signal is will now be done by reading from a file descriptor, which is epollable, and can be handled as part of your epoll set.

Yes, that's the better way to catch signals, on Linux, in this day and age.

Sam Varshavchik
  • 114,536
  • 5
  • 94
  • 148
  • So I should block the signals in all threads then have a single `signalfd` call masking in the ones I want to "catch" in my I/O thread? ...nice! – Lightness Races in Orbit Nov 12 '16 at 15:20
  • Yes, and then you epoll for reading, and read a `struct signalfd_siginfo` structure, that tells you everything you wanted to know about the signal, but were afraid to ask. – Sam Varshavchik Nov 12 '16 at 15:22
  • I don't want to have to do `if (event[i].fd == mySignalFd)` on every single wake-up of my I/O thread, so I could have a separate `epoll_wait` on a different epoll FD in my "signal watching thread", and mask in both the signal FD and my "program interrupted" pipe FD (which would then be masked in to _both_ epoll_waits. That right? – Lightness Races in Orbit Nov 12 '16 at 15:30
  • Well, to use signal file descriptors you basically have to block the signal for the entire process. As the man page describes, signals have to be blocked on the process level. It's either a signalfd, or a signal handler. Mutually exclusive. Once you do that, which thread reads or epolls on the signal file descriptor is, of course, up to you. – Sam Varshavchik Nov 12 '16 at 15:33