liveBook · Manning

Signal handler

As explained in Modern C

A signal handler is a function invoked by the C signal-handling mechanism when a specified signal is delivered.

A handler's visible work

A handler taking an int signal number counts the delivery, then chooses a response. In the example, SIGTERM calls quick_exit, SIGABRT calls _Exit, and SIGCONT returns. The default branch restores SIG_DFL, records the signal number in an interrupt flag, and returns. The surrounding program must inspect that flag to decide what to do next. section 17.6

A signal handler is a function invoked when a specified signal is delivered. It handles an exceptional event that need not arise from an explicit call in the current code. This differs from setjmp/longjmp, which can respond to conditions detected by the program itself. Signal delivery is one reason control flow cannot always be read from syntactic nesting alone. section 17.6 section 17.0

The event's origin matters:

  • A synchronous signal follows a faulting instruction, such as one that attempts erroneous arithmetic or invalid memory access. The fault's instruction can be identified. section 17.6
  • An asynchronous signal can arrive independently of the program's current operation, such as after a termination request. It may interrupt execution in an intermediate state. section 17.6

The handler has the shape of a function returning void and accepting an int signal number. The signal interface installs a handler for a signal; raise provides a way to generate one. An installation attempt must also account for failure, represented by SIG_ERR, and for an earlier disposition such as SIG_IGN or SIG_DFL. section 17.6

143   /**
144    ** @brief A minimal signal handler
145    **
146    ** After updating the signal count, for most signals this
147    ** simply stores the signal value in "interrupt" and returns.
148    **/
149   static void signal_handler(int sig) {
150     sh_count(sig);
151     switch (sig) {
152     case SIGTERM: quick_exit(EXIT_FAILURE);
153     case SIGABRT: _Exit(EXIT_FAILURE);
154   #ifdef SIGCONT
155       // continue normal operation
156     case SIGCONT: return;
157   #endif
158     default:
159       /* reset the handling to its default */
160       signal(sig, SIG_DFL);
161       interrupt = sig;
162       return;
163     }
164   }


!@%STYLE%@!
{"css":"{\"css\": \"font-weight: bold;\"}","target":"[[{\"line\":0,\"ch\":0},{\"line\":0,\"ch\":3}],[{\"line\":1,\"ch\":0},{\"line\":1,\"ch\":3}],[{\"line\":2,\"ch\":0},{\"line\":2,\"ch\":3}],[{\"line\":3,\"ch\":0},{\"line\":3,\"ch\":3}],[{\"line\":4,\"ch\":0},{\"line\":4,\"ch\":3}],[{\"line\":5,\"ch\":0},{\"line\":5,\"ch\":3}],[{\"line\":6,\"ch\":0},{\"line\":6,\"ch\":3}],[{\"line\":6,\"ch\":6},{\"line\":6,\"ch\":17}],[{\"line\":6,\"ch\":18},{\"line\":6,\"ch\":32}],[{\"line\":4,\"ch\":45},{\"line\":4,\"ch\":48}],[{\"line\":6,\"ch\":33},{\"line\":6,\"ch\":36}],[{\"line\":18,\"ch\":10},{\"line\":18,\"ch\":13}],[{\"line\":7,\"ch\":0},{\"line\":7,\"ch\":3}],[{\"line\":7,\"ch\":8},{\"line\":7,\"ch\":16}],[{\"line\":8,\"ch\":0},{\"line\":8,\"ch\":3}],[{\"line\":8,\"ch\":8},{\"line\":8,\"ch\":14}],[{\"line\":9,\"ch\":0},{\"line\":9,\"ch\":3}],[{\"line\":9,\"ch\":8},{\"line\":9,\"ch\":12}],[{\"line\":10,\"ch\":8},{\"line\":10,\"ch\":12}],[{\"line\":13,\"ch\":8},{\"line\":13,\"ch\":12}],[{\"line\":9,\"ch\":13},{\"line\":9,\"ch\":20}],[{\"line\":9,\"ch\":22},{\"line\":9,\"ch\":32}],[{\"line\":9,\"ch\":33},{\"line\":9,\"ch\":45}],[{\"line\":10,\"ch\":28},{\"line\":10,\"ch\":40}],[{\"line\":10,\"ch\":0},{\"line\":10,\"ch\":3}],[{\"line\":9,\"ch\":8},{\"line\":9,\"ch\":12}],[{\"line\":10,\"ch\":8},{\"line\":10,\"ch\":12}],[{\"line\":13,\"ch\":8},{\"line\":13,\"ch\":12}],[{\"line\":10,\"ch\":13},{\"line\":10,\"ch\":20}],[{\"line\":10,\"ch\":22},{\"line\":10,\"ch\":27}],[{\"line\":9,\"ch\":33},{\"line\":9,\"ch\":45}],[{\"line\":10,\"ch\":28},{\"line\":10,\"ch\":40}],[{\"line\":11,\"ch\":0},{\"line\":11,\"ch\":3}],[{\"line\":11,\"ch\":6},{\"line\":11,\"ch\":12}],[{\"line\":12,\"ch\":0},{\"line\":12,\"ch\":3}],[{\"line\":13,\"ch\":0},{\"line\":13,\"ch\":3}],[{\"line\":9,\"ch\":8},{\"line\":9,\"ch\":12}],[{\"line\":10,\"ch\":8},{\"line\":10,\"ch\":12}],[{\"line\":13,\"ch\":8},{\"line\":13,\"ch\":12}],[{\"line\":4,\"ch\":60},{\"line\":4,\"ch\":66}],[{\"line\":13,\"ch\":22},{\"line\":13,\"ch\":28}],[{\"line\":19,\"ch\":10},{\"line\":19,\"ch\":16}],[{\"line\":14,\"ch\":0},{\"line\":14,\"ch\":3}],[{\"line\":14,\"ch\":6},{\"line\":14,\"ch\":12}],[{\"line\":15,\"ch\":0},{\"line\":15,\"ch\":3}],[{\"line\":15,\"ch\":8},{\"line\":15,\"ch\":15}],[{\"line\":16,\"ch\":39},{\"line\":16,\"ch\":46}],[{\"line\":16,\"ch\":0},{\"line\":16,\"ch\":3}],[{\"line\":17,\"ch\":0},{\"line\":17,\"ch\":3}],[{\"line\":1,\"ch\":27},{\"line\":1,\"ch\":33}],[{\"line\":3,\"ch\":29},{\"line\":3,\"ch\":35}],[{\"line\":4,\"ch\":28},{\"line\":4,\"ch\":34}],[{\"line\":6,\"ch\":18},{\"line\":6,\"ch\":24}],[{\"line\":17,\"ch\":10},{\"line\":17,\"ch\":16}],[{\"line\":17,\"ch\":22},{\"line\":17,\"ch\":29}],[{\"line\":18,\"ch\":0},{\"line\":18,\"ch\":3}],[{\"line\":19,\"ch\":0},{\"line\":19,\"ch\":3}],[{\"line\":4,\"ch\":60},{\"line\":4,\"ch\":66}],[{\"line\":13,\"ch\":22},{\"line\":13,\"ch\":28}],[{\"line\":19,\"ch\":10},{\"line\":19,\"ch\":16}],[{\"line\":20,\"ch\":0},{\"line\":20,\"ch\":3}],[{\"line\":21,\"ch\":0},{\"line\":21,\"ch\":3}]]"}
!@%STYLE%@!

Follow the switch from the received signal number to each response; the default branch shows the short record-and-return path. section 17.6

TAKEAWAY: Keep handler work small. Mark the interrupt condition in a global flag, return to the interrupted context, and handle the condition there. Information shared with a handler must use volatile sig_atomic_t, atomic_flag, or another lock-free atomic data type. This restriction matters because an unexpected transfer of control complicates access to program state. section 17.7 section 17.0

How Modern C covers it

How deep it goes
Explains synchronous and asynchronous delivery, handler registration, signal-specific responses, and shared-state limits without specifying a general recovery procedure.
Examples
Walks through a handler that counts deliveries, exits for SIGTERM or SIGABRT, and records other signals in an interrupt flag.
What it assumes
Assumes familiarity with C functions and program state while defining synchronous and asynchronous interrupts in context.
What you can do after
Apply it via signal() to install a handler that records an interrupt condition for later handling.
How it connects
Connects signal handlers to interrupts, setjmp/longjmp, volatile sig_atomic_t, atomic_flag, and lock-free atomic types.

Also explained in

Compare how 4 books explain signal handler →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Modern C. The section links point to the parts of the book it draws on.