liveBook · Manning

Signal

As explained in Modern C, Third Edition

An asynchronous signal is an externally generated notification delivered to a running program independently of its current instruction sequence.

An asynchronous signal is an external event that interrupts a running program independently of its current instruction. A termination request or exceeded deadline can arrive while an operation is in an intermediate state. A synchronous signal, by contrast, arises from a particular faulting instruction, such as division by zero or an invalid memory access. section 19.6

A signal handler is fallback code invoked when a signal occurs. C provides signal handlers as an abstraction over hardware and software interrupts; the underlying faults and their locations vary across platforms. Unlike an exceptional condition detected by the program and handled with setjmp/longjmp, a signal can originate outside the program’s control. section 19.6 section 15.5

Installing a handler

The declarations `sh_handler* signal(int, sh_handler*);` and `int raise(int);` show two operations associated with signals. In an example setup, `sh_enable(i, signal_handler)` is called for successive known signal numbers. Installation is not guaranteed for every number: an attempted installation for `SIGKILL` reports `Invalid argument`. section 19.6

Figure 19.3 Control flow after an interrupt return jumps to the position where the interrupt occurred
figure

The control-flow figure shows execution returning to the position where an interrupt occurred. section 19.6

TAKEAWAY: An asynchronous handler may run when the interrupted execution environment is in an intermediate state. Observe the C library’s context restrictions: calling `signal` in a multithreaded program is not allowed, so a function that uses it can become unsuitable when linked into a program that uses threads. section 19.6 section 15.3.3

 #if ATOMIC_LONG_LOCK_FREE > 1
 /**
  ** @brief Keep track of the number of calls into a
  **  signal handler for each possible signal.
  **
  ** Don't use this array directly.
  **
  ** @see sh_count to update this information.
  ** @see SH_PRINT to use that information.
  **/
 extern _Atomic(unsigned long) sh_counts[];
 
 /**
  ** @brief Use this in your signal handler to keep track of the
  ** number of calls to the signal @a sig.
  **
  ** @see sh_counted to use that information.
  **/
 inline
 void sh_count(int sig) {
   if (sig < sh_known) ++sh_counts[sig];
 }
 
 inline
 unsigned long sh_counted(int sig){
   return (sig < sh_known) ? sh_counts[sig] : 0;
 }
 
 #else

This conditional listing counts handler calls with an atomic array when `ATOMIC_LONG_LOCK_FREE > 1`; it illustrates a deliberately limited operation performed by a handler. section 19.6

How Modern C, Third Edition covers it

How deep it goes
Distinguishes synchronous from asynchronous events and illustrates handler setup, installation failure, and conditional atomic counting; does not specify a general handler-safety procedure.
Examples
Uses termination requests, faulting instructions, handler-installation output, and a conditional atomic call counter.
What it assumes
Assumes familiarity with C functions and execution flow while defining signal types through concrete events.
What you can do after
Evaluate/understand when an interruption is asynchronous and why handler installation and calls to `signal` need contextual checks.
How it connects
Connects signals to control flow, hardware interrupts, traps, setjmp/longjmp, atomic operations, and multithreading.

Also explained in

Compare how 3 books explain signal →

Related concepts

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