Handling signals in Linux with C++
Why signals are important
Signals are the simplest form of IPC in Unix-like systems. They are notifiers to the process that an external event has happened. As this is a system specific mechanism, there’s no portable C++ STL library providing support for signal handling. But it’s fairly easy to write one. First though a short introduction is required.
Each thread in a process has a signal mask which can be modified either via
setprocmask (for single threaded processes) or
multithreaded processes). Every raised signal is checked against the mask. If
it’s blocked, it’s residing in a PENDING state and it will be immediately
handled once unblocked. If it’s not blocked, its corresponding signal handler
will be called or the default action executed in case there is none. Of course
there are signals which can’t be blocked or its disposition can’t be altered
(like SIGKILL or SIGSTOP). In other words, pending signal is handled as
soon as thread’s signal mask unblocks it. It’s also worth to remember that
signals are not queued (aside from realtime signals - these are queued).
Multiple subsequently raised pending signals will be handled as if a single
one was raised.
What’s in the toolbox?
Most Unix like OSes provide the following APIs to allow for signal handling:
Which one to use? The use of
signal is discouraged due to portability issues
(the interface is not common for all Unix-like OSes).
sigaction seems like a
reasonable candidate but there’s a caveat. The thread on which the signal
handler, registered with
sigaction, is gonna be called is unknown. This
introduces a level of unpredictability and this is something that is not
What about the remaining
pause sounds good however it implies that we’ve already registered a signal
handler with something like
sigaction in order to stop blocking so, it won’t
solve the problem of predictable thread selection for execution of the
signal handler. The last two options are the ones I’m gonna explore.
But first, let’s create some utilities.
sigwaitinfo and friends blocks until there’s a pending signal, which it then
returns along with signal details enclosed in
siginfo_t structure. In order
for signal to become pending, its default disposition has to be altered. All
signals on all threads have to be blocked so, the default disposition is
not interfering with the signal handler I’m trying to build. How to assure
that this happens on all threads? There’s no way to do that. To achieve
that, signal mask has to be configured prior to creation of any other
threads. As a result, all children threads will inherit it. With that in mind
let’s define a class:
ScopedSigSet. By default, it will take the provided
signal mask and block all signals in it. The original mask will be saved.
Once the object is destroyed, it will be restored.
ScopedSigSet treats the signal mask as a resource and is a RAII wrapper
around it. Once it goes out of scope, the original mask is restored.
Unfortunately, since the signal mask can be altered externally anyway by 3rd
ScopedSigSet can’t provide any strict guarantees. It’s
purpose, is purely for convenience.
A couple more utilities will come in handy, specifically in regards to the signal set construction. For that purpose I defined the following functions:
extendSet is using c++17 fold expression to perform a series of
invocations, every each extending the provided signal set with a new signal.
Thanks to these two functions it’s possible to create signal sets in a very
convenient way, by just specifying the desired signals. The
sigset_t will be
automatically constructed and populated, i.e.:
Signal handler callbacks
In spirit of my previous blog post, signals will be handled with a callbacks object. The interface of this object will look the following way:
Very simple interface with only one callback. The
onSignal callback returns
a bool value. If the returned value is
true it’s gonna be interpreted by the
handler as a request to terminate.
sigwaitinfo based SignalHandler implementation
With a basic set of prerequisites out of the way it’s possible to proceed with
SignalHandler implementation. For that, I’m gonna define a class
SigWaitHandler, the interface is gonna look the following way:
The interface is as simple as it can get.
stop() allows to explicitly
request termination of the handler. As a result the
run() API will terminate
run() may be executed on any thread. Callbacks are gonna be
dispatched on the same thread.
run() will block until signal handler is
Full implementation is available in a form of library on gitlab. In this post, I’m gonna focus only on the most important bits:
SIGUSR1 serves a double purpose here. It may be used by the client API but
internally, it’s used to wake up the
sigwaitinfo for the purpose of
termination. If the sender’s
pid matches the process’ and at the same time,
isRunning flag has been set to
false it’s being interpreted as a
request to terminate.
SIGUSR1 is always unmasked in the constructor.
signalfd based SignalHandler implementation
signalfd is another mean allowing to implement a modern signal handler.
signalfd allows for creation of a file descriptor. Read operations on the
file descriptor will be unblocked once there’s a pending signal. This allows
for creation of a similar “busy” loop as in case of
sigwaitinfo. The only
difference is that the loop will be blocked on
read operation rather than
explicitly wait for a signal. This is a perfect pattern for writing efficient
server applications. The file descriptor created by
signalfd can be
multiplexed by APIs like
select along with client
connections. In this case, multiplexing is still gonna be required. Another
file descriptor is necessary, acting as an event source. Only one type of
events is needed; event indicating termination request, which will, in result,
break the dispatching loop. For that purpose, I’m gonna use
eventfd, which is
another convenient API designed specifically for that purpose.
Even more utilities
Prior to that, I’m gonna need some more utilities. First, a RAII style file descriptor wrapper:
It’s a movable only object. Copying is disabled. Interesting bit is the move assignment operator. The pattern implemented there is very similar to “copy & swap” idiom but slightly different.
On rvalue assignment, the object moves itself to a temporary. As a result, the
temporary will close the current file descriptor (once it goes out of scope)
and at the same time it’s possible to safely overwrite the fd with the one from
the right hand side object’s (that’s what the
swap operation is doing).
Another wrapper is required around
ScopedFd as it will become later apparent. The purpose of
solely to provide a uniform interface and, as well, to provide some rudimentary
error handling. Otherwise this code would be duplicated in further objects.
The implementation looks like so:
If the provided file descriptor is, for any reason, invalid, this wrapper will
provide us with some common error handling. Having
FdWrapper implemented, I
can now continue with some convenience wrappers around Linux’s APIs.
FdWrapper at hand, creation of wrappers for Linux APIs becomes trivial:
Looks very simple. Thanks to all of the prior efforts, the file descriptor
obtained from the system that way is automatically guaranteed to be closed and
I can benefit from error handling in case
signalfd fails. Some more wrappers
This one is equally simple:
It extends the
FdWrapper interface with two more APIs allowing for sending
and receiving events. For the sake of simplicity, error handling is in a quite
rudimentary shape. One last wrapper is required.
Since multiplexing is required, I’ve decided to use
epoll for that purpose.
The wrapper looks the following way:
In here, I benefit from a generic API that
FdWrapper provides to allow to add
epoll_wait is gonna operate on.
The required tool set is complete. It’s possible to proceed with the
signalfd based signal handler implementation now. It’s gonna comply with the
requirements defined by the generic signal handler interface defined earlier
(in fact this interface has been extracted for code de-duplication purposes in
the library implementation in the gitlab repository).
Error handling is simplified in this example. The implementation’s intrinsics
are quite obvious I think. The file descriptor set is comprised of two sources;
eventfd. The former one, provides means to retrieve and
handle pending signals, the latter one serves as a notification to terminate
How to use this implementation?
SignalFdHandler are implementing the same
interface, the usage is very simple. An example program skeleton may look the
I’ve summarised the discussed implementation as an independent library available on my gitlab account. There are some minor differences from the discussed implementation, mainly an interface clean up. I’m interested in feedback regarding this implementation so, feel free to reach out!
Yes, I’m aware that a similar solution is provided by
benefit is that it’s portable and not only Linux specific. It’s something
definitely recommended. I’ve decided to explore my own implementation though
for educational purposes and in situations when integration with boost asio is