# 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. ```c #include 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: ```c volatile sig_atomic_t stop = 0; void handler(int sig) { stop = 1; } // in main loop: if (stop) { cleanup(); exit(0); } ``` ## Practice ```c // 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 #include #include 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).