Site Tools


wiki:signal.h

Table of Contents

signal.h

signal.h is how your program hears from the OS when something happens outside its normal execution: the user pressed Ctrl-C, a timer expired, you divided by zero, or another process sent you a notification. Signals are asynchronous — they can arrive between any two instructions — which makes them tricky to handle correctly.

#include <signal.h>
 
void handler(int sig) {
    write(1, "caught SIGINT\n", 14);  // write() is safe here; printf() is not
}
 
int main(void) {
    signal(SIGINT, handler);   // Ctrl-C will now call handler instead of killing us
    while (1) pause();         // sleep until a signal arrives
    return 0;
}

signal(signum, handler) registers your function. SIG_IGN ignores the signal entirely; SIG_DFL restores the default action.

Common signals:

Signal Default Cause
SIGINT Terminate Ctrl-C
SIGTERM Terminate kill (default)
SIGKILL Terminate kill -9, cannot be caught or ignored
SIGSEGV Dump + terminate Invalid memory access
SIGFPE Dump + terminate Floating-point exception
SIGALRM Terminate alarm() timer expired
SIGHUP Terminate Terminal closed; daemons use this to reload config

Signal handlers run asynchronously, which means they can interrupt your program between any two instructions. Most library functions are not safe to call inside a handler because they hold internal locks that might already be held. printf, malloc, free — all off-limits. The safe set is small: write, _exit, sem_post, and a few others.

The standard pattern for clean shutdown is to set a flag in the handler and check it in the main loop:

volatile sig_atomic_t stop = 0;
void handler(int sig) { stop = 1; }
// in main loop: if (stop) { cleanup(); exit(0); }

Practice

// compile: gcc -o sigdemo sigdemo.c
// run: ./sigdemo    then press Ctrl-C to trigger the handler
// description: SIGINT handler sets a flag; main loop polls and exits cleanly
 
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
 
volatile sig_atomic_t stop = 0;
 
void handler(int sig) {
    stop = 1;  // safe: just set a flag
}
 
int main(void) {
    signal(SIGINT, handler);
    puts("running... press Ctrl-C to stop");
    while (!stop) {
        putchar('.');
        fflush(stdout);
        sleep(1);
    }
    puts("\nshutting down cleanly");
    return 0;
}

Run it and press Ctrl-C. The handler fires, sets stop, and the main loop exits on the next iteration. Notice that the handler only sets a flag — it does not call printf or exit. That is correct signal handling. If you moved puts("shutting down cleanly") into the handler itself, it would be technically unsafe (though it would probably work on Linux in practice — “probably” is the problem).

wiki/signal.h.md · Last modified: by 127.0.0.1