Generation is the moment an event happens that creates the signal. Delivery is when the kernel actually hands that signal to the target process and the process reacts to it.
These two steps are separate. Between generation and delivery, the signal sits in a pending state. This gap matters because the process might be blocked, sleeping, or currently masking (blocking) that particular signal.
| Cause Category | Concrete Example | Signal Raised |
|---|---|---|
| Hardware Exception | Program divides an integer by zero; CPU detects fault, notifies kernel | SIGFPE |
| Hardware Exception | Program dereferences a NULL pointer (invalid memory access) | SIGSEGV |
| Hardware Exception | Program executes a malformed machine instruction | SIGILL |
| Terminal Special Key | User presses Ctrl+C at the keyboard | SIGINT |
| Terminal Special Key | User presses Ctrl+Z at the keyboard | SIGTSTP (stop) |
| Software Event | A timer set with alarm() expires | SIGALRM |
| Software Event | A child process exits | SIGCHLD |
| Software Event | Process exceeds its CPU time limit | SIGXCPU |
Most signals are delivered asynchronously β you cannot predict which instruction is executing when the signal arrives. For example, SIGALRM from a timer fires at wall-clock time, not at a particular line of code.
Some signals are synchronous β they are always triggered by a specific instruction in the program and delivered immediately. Hardware exceptions fall here: SIGSEGV always happens at the exact instruction that touches bad memory.
| Type | Predictable? | Example |
|---|---|---|
| Asynchronous | No β arrives at any time | SIGALRM, SIGINT, SIGCHLD |
| Synchronous | Yes β tied to an instruction | SIGSEGV, SIGFPE, SIGILL |
Linux has two families of signals:
| Feature | Standard Signals (1β31) | Realtime Signals (32β64) |
|---|---|---|
| Queued? | No β only one pending at a time | Yes β multiple instances queue up |
| Order guaranteed? | No | Yes β delivered lowest number first |
| Defined in | <signal.h> as SIGxxx names | SIGRTMIN to SIGRTMAX |
| This chapter covers | Yes | Described in Section 22.8 |
This demonstrates synchronous generation: dereferencing a NULL pointer always causes SIGSEGV at that exact instruction. The kernel delivers it immediately without any scheduling delay.
/* Example: Trigger SIGSEGV (synchronous signal)
Compile: gcc -o sigsegv_demo sigsegv_demo.c
Run: ./sigsegv_demo
Expected output: Segmentation fault (core dumped) */
#include <stdio.h>
int main(void)
{
int *ptr = NULL; /* null pointer */
printf("About to dereference a NULL pointer...\n");
printf("This will trigger SIGSEGV (synchronous).\n");
*ptr = 42; /* BAD: write to address 0 β SIGSEGV generated HERE */
/* The line below will never execute */
printf("This line is never reached.\n");
return 0;
}
*ptr = 42 instruction and delivered SIGSEGV synchronously.SIGALRM is asynchronous β the kernel delivers it when a real-time timer expires, regardless of what instruction is currently running. Here we use alarm() to schedule it after 3 seconds.
/* Example: Asynchronous SIGALRM after 3 seconds
Compile: gcc -o alrm_demo alrm_demo.c
Run: ./alrm_demo
Expected: alarm fires after 3s and terminates the process */
#include <stdio.h>
#include <unistd.h> /* alarm(), sleep() */
int main(void)
{
printf("Setting alarm for 3 seconds...\n");
alarm(3); /* ask kernel to send SIGALRM after 3 seconds */
/* The loop below will be interrupted asynchronously */
int i = 0;
while (1) {
printf("Working... i = %d\n", i++);
sleep(1);
}
/* Process will be killed by SIGALRM before reaching here */
return 0;
}
Pending Signals β What does “pending” really mean and how does it work?
