Linux System Programming · intermediate · ~8 min
Recognize the bugs that catch almost every C programmer the first time they work with signals.
Signals are easy to install but easy to misuse. Here are the mistakes that bite most people, and how to avoid each one.
printf or malloc from a handlerA signal handler runs at an unpredictable moment, possibly in the middle of another call. Functions like printf and malloc are not async-signal-safe (safe to call from a handler), so calling them there can corrupt state or deadlock.
write() to print.int flagA signal can arrive between the read and the write of an ordinary variable, leaving it in an inconsistent state.
volatile sig_atomic_t. This type is guaranteed safe to read and write atomically across a signal.SIGKILL or SIGSTOPThis cannot be done. The kernel refuses to install a handler for these two signals.
SIGCHLD handler in a serverWhen a child process exits, it stays as a zombie (a finished process the parent has not yet collected) until the parent reaps it. Without a SIGCHLD handler, zombies accumulate forever.
EINTRWhen a signal interrupts a blocking system call, that call returns -1 with errno == EINTR.
SA_RESTART flag so the kernel restarts the call automatically.alarm(0) and the signalalarm(0) cancels a pending alarm. But if the kernel has already queued the delivery, there is a tiny window where the signal still arrives.
This is only a concern with the legacy signal() function. Use sigaction() instead and the problem disappears.
/* WRONG */
static int stopping = 0;
static void h(int s) { (void)s; stopping = 1; printf("stopping\n"); }
/* RIGHT */
static volatile sig_atomic_t stopping = 0;
static void h(int s) {
(void)s;
stopping = 1;
const char msg[] = "stopping\n";
write(STDERR_FILENO, msg, sizeof msg - 1);
}
signal() is fine just because it works on your Linux box. Its behavior is not portable. The same code can break on a BSD system and crash. Use sigaction() instead.Six recurring signal bugs to memorize:
volatile sig_atomic_t.SIGKILL or SIGSTOP.SIGCHLD reaper and letting zombies pile up.EINTR on interrupted system calls.alarm() cancellation has no race.