Pages: Welcome | Projects

Signalfd, signals can be done right

2017/8/14
Tags: [ Hacking ] [ GNU/Linux ]

I like programming with POSIX. My experience so far is only related with GNU/Linux, since it's both my operating system of choice and the one I'm programming under for work.

POSIX is quite powerful, but it has a bunch of bad system calls. A legacy of bad programming practices (with respect to modern standards), with global variables (e.g. errno, which is nowadays thread-local) and non-reentrant code. I can think of many system calls having this problem.

The kind of functionality which baffles me most is the signal (7) handling in the POSIX C library: it is pretty much impossible to use it while carrying some non-global context.

For instance, the sigaction (2) manpage mentions a context which can be carried around, and points to the getcontext (3) manpage. This one in turn mentions the following:

CONFORMING TO SUSv2, POSIX.1-2001. POSIX.1-2008 removes the specification of getcontext(), citing portability issues, and recommending that applications be rewritten to use POSIX threads instead.

…so essentially, as I interpret this, the right way to do it would be having a dedicated thread to work with signal handling. And that thread would need to handle some global context, again.

It could be interesting to check out what the POSIX.1-2008 says about this portability issues.

In the meanwhile I found out about signalfd (2), a Linux-specific call which allows to handle signals by means of a file descriptor. The file descriptor interface is in my opinion way cleaner than the signal one! Then of course if portability is an issue I would definitely suggest to go for something like LibEvent instead.

Here I could find a good example of how to use signalfd. It is really clean and easy to carry around a file descriptor, and a perfectly reentrant handling can be done by means of poll (2) (or epoll (7), since we gave up our portability, already).

The only heads up is: use sigprocmask before signalfd, as shown in the example, or the default signal handling will take place (even if that would be "ignore" via SIG_IGN).