libstddjb
skalibs
Software
www.skarnet.org

Safe wrappers

Lots of functions in libstddjb, declared for instance in allreadwrite.h or djbunix.h, are just "safe wrappers" around corresponding system functions. For instance, fd_read() is a safe wrapper around the system read() function.

The problem

Quite a lot of system calls are defined by the Single Unix Specification v4 as interruptible: when the process is in the middle of such a system call and receives a signal that it does not ignore, the system call immediately returns -1 EINTR (after the signal handler, if any, has been executed).

This means that the intended execution of the process is at the mercy of a stray signal. If a signal happens at the wrong time, a system call fails when it could have succeeded. This is not acceptable.

The solution

So, in order to be perfectly reliable, when a program makes an interruptible system call, it must check whether the return value is -1 EINTR, and restart the system call if it is the case. This is annoying to write; so, libstddjb provides small wrappers around interruptible system calls, so that programmers can just call those safe wrappers and never bother with this again.

The performance loss from having a wrapper layer is totally negligible compared to the cost of using a system call in the first place.

But isn't it what the SA_RESTART flag is meant to address?

Yes, it is. Unfortunately, SA_RESTART only protects interruptible system calls from signals you actually have control over, and set a handler for with sigaction(). This is not enough. You cannot decide that every signal sent to your process should have SA_RESTART behaviour; and the Single Unix specification says nothing about signals you do not control. For instance, you cannot trap SIGSTOP; SIGSTOP does not kill your process, which should resume flawlessly at the next SIGCONT; and according to the specification, it is valid for SIGSTOP and SIGCONT to not have SA_RESTART behaviour. So if you get a SIGSTOP while performing an interruptible system call, that system call may return -1 EINTR, this is not an OS bug, and there's nothing you can do about it with sigaction().

SA_RESTART is only a partial solution: in other words, it doesn't work. Until the Single Unix specification explicitly states that untrapped non-lethal signals MUST have SA_RESTART behaviour by default, you need safe wrappers to protect interruptible system calls.