async-signal-safety
Picture being interrupted exactly while you are halfway through reorganizing your desk — drawers open, papers in mid-air. If the interruption asks you to reorganize the same desk again, you will make a mess: the desk is in a half-finished state. A signal handler faces this exact problem. It can interrupt your program at any instruction, possibly in the middle of a function that left some shared structure half-updated. If the handler then calls that same kind of function, it operates on a broken, half-finished state.
Concretely: suppose your main code is inside malloc(), which is partway through editing the allocator's internal free list, and a signal fires. Your handler now runs and also calls malloc(). The free list is in an inconsistent intermediate state, so this second malloc() can corrupt it or crash. The same danger applies to printf() (uses internal buffers and locks), most of stdio, and many library calls. A function is 'async-signal-safe' if it is guaranteed to work correctly even when called from a signal handler that interrupted any other code. POSIX defines a specific, short list of such functions — write(), read(), _exit(), kill(), signal(), and a few dozen more — and only those may be called from a handler.
The practical rule writes itself: do almost nothing inside a signal handler. The safe, standard pattern is to set one variable of type volatile sig_atomic_t (a type guaranteed to be updated atomically) and return immediately, then let your normal program loop notice that flag and do the real work in a safe context. If you must report something from the handler, use write() to a file descriptor, never printf(). This is not pedantry: signal-handler bugs are notorious precisely because they appear only when a signal lands at one unlucky instruction, so they are rare, non-deterministic, and brutally hard to reproduce.
DANGEROUS: void h(int s){ printf("got it\n"); } /* printf is NOT async-signal-safe */ SAFE: void h(int s){ const char m[]="got it\n"; write(2, m, 7); } /* write IS safe */
Inside a handler, write() is fine but printf() can deadlock or corrupt. When in doubt, just set a flag.
malloc(), free(), and printf() are NOT async-signal-safe — calling them from a handler is a classic latent bug that may survive testing and crash only rarely in production. The flag-and-return pattern sidesteps the whole problem.