C Mastery / signal.h and setjmp.h
Part 3 — The Standard Library

signal.h and setjmp.h

This chapter covers <signal.h> (signal handling) and <setjmp.h> (nonlocal jumps). Both are powerful, both are highly restricted in what you may safely do, and both are frequent sources of undefined behavior.

Why This Matters

Signals are how a program reacts to asynchronous events (Ctrl-C, timers, fatal errors). setjmp/longjmp implement nonlocal control flow (error recovery, coroutines). Both require precise knowledge of their restrictions to use safely.

Prerequisites

Core Concept

Signals

<signal.h> declares signal() to install a handler and raise() to send a signal. Standard signals include SIGINT, SIGABRT, SIGFPE, SIGSEGV, SIGTERM.

void (*signal(int sig, void (*handler)(int)))(int);
int raise(int sig);

A signal handler is a function taking int and returning void. The only portable actions inside a handler are extremely limited: you may assign to a volatile sig_atomic_t object and return, or call _Exit/abort. Doing almost anything else (printf, malloc, etc.) is not guaranteed to be safe.

sig_atomic_t

volatile sig_atomic_t is the only type guaranteed to be safely readable/ writable from a signal handler. Use it for flags.

setjmp/longjmp

int setjmp(jmp_buf env);
void longjmp(jmp_buf env, int val);

setjmp records the current execution context; longjmp restores it, making setjmp return a second time with value val (or 1 if val is 0).

Use cases: error recovery and early exit from deep call chains. But the rules are strict.

Syntax

#include <signal.h>
#include <setjmp.h>

static volatile sig_atomic_t g_flag = 0;

void handler(int sig) {
    g_flag = 1;   /* the only safe kind of action */
}

int main(void) {
    signal(SIGINT, handler);
    while (!g_flag) {
        /* wait */
    }
    return 0;
}

Examples

Signal flag

#include <signal.h>
#include <stdio.h>

static volatile sig_atomic_t stop = 0;

static void on_signal(int sig)
{
    (void)sig;
    stop = 1;
}

int main(void)
{
    signal(SIGINT, on_signal);
    while (!stop) {
        /* busy wait */
    }
    puts("stopped");
    return 0;
}

setjmp/longjmp error recovery

#include <setjmp.h>
#include <stdio.h>

static jmp_buf env;

void fail(void)
{
    longjmp(env, 1);
}

int main(void)
{
    if (setjmp(env) == 0) {
        puts("first pass");
        fail();
    } else {
        puts("recovered");
    }
    return 0;
}

Expected output: first pass then recovered.

How It Works

A signal is an asynchronous notification delivered by the OS/runtime. When a signal arrives, the currently executing code is interrupted and the handler runs (on the same thread, in a limited context). setjmp saves registers/ stack state into jmp_buf; longjmp restores it, transferring control back.

Variations

Signal semantics vary

The C standard defines a minimal, portable subset. POSIX greatly expands signal semantics (sigaction, blocked signals, SA_RESTART, etc.), which is covered in c.os.7.

longjmp restrictions

longjmp may be called only if the function containing setjmp has not yet returned. Jumping into a scope with VLAs has special restrictions.

Common Mistakes

Undefined Behavior

general). VERIFIED

VERIFIED

restricted ways).

Portability

more predictable semantics.

Under the Hood

Signals interrupt normal control flow at the machine level (the OS saves context, runs the handler, restores). setjmp/longjmp save and restore the register/stack state, essentially a manual nonlocal goto.

Practical Usage

code (e.g., a parser's error path), not as general control flow.

Exercises

1. Write a program that sets a flag in a SIGINT handler and exits cleanly. 2. Demonstrate setjmp/longjmp error recovery. 3. Explain why calling printf in a signal handler is unsafe. 4. Use volatile sig_atomic_t and explain its necessity.

Deep Challenge

Implement a small, safe signal-handling design where a handler sets a flag and the main loop performs all real work, and explain why this design is portable. Then discuss the POSIX sigaction improvements you would make.

References

Verification

verified.`

Progress

Concept checkboxes

Mastery levels

ConceptCurrent level (0–8)Target level
c.lib.signal06
c.lib.setjmp06