Signals and Signal Handlers
Signals are a form of inter-process communication (IPC): the kernel or another process can send a signal to a process to notify it of an event (e.g. terminal interrupt, child exited, segmentation fault). Each signal has a default action (terminate, ignore, core dump, etc.); a process can ignore the signal, use the default, or install a custom handler. SIGKILL (9) and SIGSTOP (19) cannot be caught or ignored — the kernel enforces them. When a child terminates, the kernel sends SIGCHLD to the parent; the parent should call wait() or waitpid() to reap the child and avoid zombies (see Process Lifecycle).
Default signal for kill
Section titled “Default signal for kill”The default signal sent by kill <pid> is SIGTERM (15) — a request to terminate gracefully. To send another signal: kill -9 <pid> (SIGKILL) or kill -l to list signal names/numbers.
How the kernel delivers signals
Section titled “How the kernel delivers signals”- Signal is sent — Via
kill(),killpg(), or by the kernel (e.g. SIGSEGV on invalid access, SIGCHLD when child exits). - Kernel records it — Pending signals are stored per process. If the same signal is sent again before delivery, it may be merged (standard signals are not queued).
- Process is interrupted — When the process returns to user mode from the kernel (syscall return, timer interrupt, etc.), the kernel checks for pending signals.
- Delivery — The kernel invokes the process’s action for that signal: ignore (discard), default (e.g. terminate, core dump), or handler (call the user-registered function). Delivery happens at a “safe” point (e.g. when the process is about to return to user space).
- Handler runs — If a custom handler is installed, it runs in the process’s context; when it returns, execution resumes (unless the handler longjmp’s or exits).
Relevant tools
Section titled “Relevant tools”| Tool | Purpose |
|---|---|
kill, killall, pkill | Send signals to processes. |
trap | Shell builtin to set signal handlers in scripts. |
strace | Trace syscalls and signal delivery (strace -e signal). |
ps, top, htop | Find PIDs; show state. |
/proc/<pid>/status | SigBlk, SigIgn, SigCgt (blocked, ignored, caught). |
gdb | Attach and handle signals (e.g. handle SIGINT print). |
dmesg | Kernel messages (e.g. after crash). |
Using the tools
Section titled “Using the tools”- List signals — Use
kill -lto list signal names (and numbers on some systems). - Send signals —
kill <pid>(SIGTERM),kill -9 <pid>(SIGKILL),killall -9 name,pkill -9 -f pattern. - Shell —
trap 'echo Caught; exit 1' SIGINTto handle Ctrl+C in a script. - Process signal masks —
cat /proc/<pid>/statusand check SigBlk, SigIgn, SigCgt. - Trace signals —
strace -e signal -p <pid>to see signals received. - Crashes — Use
gdbto attach or run the program; inspect core dumps or handle signals.
Handling signals without source code
Section titled “Handling signals without source code”When you cannot modify the program, you can still observe or influence signals:
- Wrapper script — Run the program in a script that sets
trapand thenexecs the binary. The wrapper can log or forward signals (though SIGKILL/SIGSTOP cannot be caught). - gdb — Attach with
gdb -p <pid>. Usehandle SIGINT print stopto intercept and print (or pass to the program). Useful for debugging crashes. - strace —
strace -e trace=signal -p <pid>shows when signals are delivered. Does not change behavior, only observes. - LD_PRELOAD — Load a shared library that overrides
signal()orsigaction()and installs your own handler before calling the original. Advanced; use with care.
Common signals reference
Section titled “Common signals reference”| Signal | Number | Purpose | Default action | Catchable? |
|---|---|---|---|---|
| SIGINT | 2 | Interrupt (e.g. Ctrl+C) | Terminate | Yes |
| SIGQUIT | 3 | Quit (e.g. Ctrl+\) | Core dump + terminate | Yes |
| SIGTERM | 15 | Request graceful shutdown | Terminate | Yes |
| SIGKILL | 9 | Force kill | Terminate | No |
| SIGSTOP | 19 | Stop process (suspend) | Stop | No |
| SIGCHLD | 17 | Child terminated/stopped | Ignore | Yes |
| SIGSEGV | 11 | Invalid memory access | Core dump + terminate | Yes (for debugging) |
SIGCHLD — Sent to the parent when a child changes state (exits, stops, continues). The parent should call wait() or waitpid() to reap the child and free its exit status; otherwise the child can remain a zombie (see Process Lifecycle).
Summary table
Section titled “Summary table”| Signal | Number | Purpose | Default | Catchable? |
|---|---|---|---|---|
| SIGINT | 2 | Interrupt | Terminate | Yes |
| SIGTERM | 15 | Graceful shutdown | Terminate | Yes |
| SIGKILL | 9 | Force kill | Terminate | No |
| SIGCHLD | 17 | Child state change | Ignore | Yes |
| SIGSEGV | 11 | Invalid memory access | Core + terminate | Yes |