Skip to main content
RunBook Academy

LinuxVI · ProcessesSignals

Signals — SIGTERM, SIGKILL, SIGHUP, and the rest

Intermediate⏱ ~12 minbashkilltrapps

What you'll learn

  • Send and receive signals correctly
  • Distinguish catchable from uncatchable signals
  • Write a signal handler that handles SIGTERM gracefully
  • Avoid the common signal-handling bugs

Prerequisites

Verified against Ubuntu 24.04 LTS · Debian 12 (Bookworm) · RHEL 9.x · Rocky Linux 9.x · AlmaLinux 9.x · Linux kernel 6.1 LTS / 6.6 LTS · systemd 255+ · OpenSSH 8.7p1 (RHEL 9) / 9.6p1 (Ubuntu 24.04) · nftables 1.0.x · chrony 4.x · Pacemaker 2.1.x · Corosync 3.1.x · 2026-08-09

Not yet marked complete on this device.

Signals are Linux’s asynchronous notification mechanism. A signal is a small integer (1-31 on Linux, with real-time signals above) that the kernel delivers to a process. The process can ignore it, catch it (with a handler), or accept the default action.

The signal list

SignalNumberDefault actionCatching?
SIGHUP1TerminateYes — many daemons reload config
SIGINT2TerminateYes — Ctrl-C handler
SIGQUIT3Core dumpYes
SIGILL4Core dumpYes
SIGTRAP5Core dumpYes
SIGABRT6Core dumpYes
SIGBUS7Core dumpYes
SIGFPE8Core dumpYes
SIGKILL9Terminate (immediately)NO — uncatchable
SIGUSR110TerminateYes — application-defined
SIGSEGV11Core dumpYes
SIGUSR212TerminateYes — application-defined
SIGPIPE13TerminateYes — write to closed pipe
SIGALRM14TerminateYes — timer
SIGTERM15TerminateYes — graceful shutdown
SIGSTKFLT16TerminateYes
SIGCHLD17IgnoreYes — parent notification of child exit
SIGCONT18ContinueYes
SIGSTOP19Stop (suspend)NO — uncatchable
SIGTSTP20StopYes — Ctrl-Z in a terminal
SIGTTIN21StopYes
SIGTTOU22StopYes
SIGURG23IgnoreYes
SIGXCPU24Core dumpYes
SIGXFSZ25Core dumpYes
SIGVTALRM26TerminateYes
SIGPROF27TerminateYes
SIGWINCH28IgnoreYes — terminal window resize
SIGIO/SIGPOLL29TerminateYes
SIGPWR30TerminateYes
SIGSYS31Core dumpYes
Read-only / Safekill -l
$ kill -l 2>&1 | head -5
 1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL
5) SIGTRAP      6) SIGABRT      7) SIGBUS       8) SIGFPE
9) SIGKILL     10) SIGUSR1     11) SIGSEGV     12) SIGUSR2
13) SIGPIPE     14) SIGALRM     15) SIGTERM     16) SIGSTKFLT
17) SIGCHLD     18) SIGCONT     19) SIGSTOP     20) SIGTSTP

Illustrative output

Sending signals

Service impact possiblekill
$ kill 1234; kill -TERM 1234; kill -KILL 1234; kill -HUP $(pgrep nginx)
...

Illustrative output

Service impact possiblepkill, killall
$ pkill -TERM -f nginx; killall -HUP sshd
...

Illustrative output

Catching signals

A process catches a signal by registering a handler via signal() or sigaction(). When the signal arrives, the kernel interrupts the process’s normal flow and calls the handler.

Read-only / Safesignal demo
$ cat /tmp/sigterm-demo.sh
#!/bin/bash
LOCK=/tmp/sigterm-demo.lock

cleanup() {
  echo "received SIGTERM, cleaning up"
  rm -f "$LOCK"
  exit 0
}

trap cleanup TERM
trap 'echo "received SIGINT, exiting"; rm -f "$LOCK"; exit 130' INT

echo "PID: $$"
touch "$LOCK"
echo "waiting..."

while true; do
  sleep 1 & wait $!
done

Illustrative output

Two details in that script are the whole lesson.

The trap argument is a single word or a quoted string. trap takes the handler as one argument. Writing

trap echo cleaning up; rm -f "$LOCK"; exit 0 TERM

does not install that pipeline as a handler. Bash reads trap echo cleaning up as the trap command, then runs the rest immediately. The safe forms are a function name, as with trap cleanup TERM, or a single-quoted string, as with the SIGINT line. A function name is easier to read and easier to test, because you can call cleanup directly.

A foreground sleep delays the handler. Bash does not interrupt a foreground child to run a trap. It waits for the child to exit, then runs the handler. With a plain sleep 1 the delay is invisible; with sleep 300 in a polling loop the process appears to ignore SIGTERM for five minutes, systemd hits TimeoutStopSec, and SIGKILL arrives with the cleanup never having run. Backgrounding the sleep and calling wait fixes it: wait is interruptible, so the handler fires immediately.

Service impact possibletrap in action
$ ./sigterm-demo.sh & echo $!; sleep 5; kill -TERM $!; wait $!
PID: 12345
waiting...
received SIGTERM, cleaning up

Illustrative output

Catching vs blocking vs ignoring

Three options when a signal arrives:

OptionEffect
DefaultThe kernel applies the signal’s default action (terminate, core dump, ignore, stop, continue)
Ignore (SIG_IGN)The kernel discards the signal; the process never knows
HandlerThe kernel runs a function the process registered; on return, the process resumes
Read-only / Safeignore SIGTERM
$ trap '' TERM; sleep 60
...

Illustrative output

Real-time signals

Linux supports real-time signals from SIGRTMIN (typically 32) to SIGRTMAX. Real-time signals:

  • Carry a sigval_t payload (an integer or a pointer).
  • Are queued, not coalesced — multiple instances of the same signal are delivered separately.
  • Have a defined delivery order (lower-numbered first; for the same number, by sender’s PID).
Service impact possibleRTMIN+3
$ kill -RTMIN+3 1234
...

Illustrative output

Production discipline

PracticeWhy
Every daemon handles SIGTERM by cleaning up and exiting.systemd escalates to SIGKILL after TimeoutStopSec. A handler that does not exit in time triggers SIGKILL.
SIGHUP reloads configuration.Convention; nginx, sshd, rsyslog, and most daemons follow it.
SIGUSR1 / SIGUSR2 are application-specific.“Rotate logs”, “dump state”, “reopen file”; document what each means.
Never block SIGKILL or SIGSTOP.The kernel enforces this regardless. Trying to do so is a bug.
Always test signal handlers.Many production daemons have been killed by SIGKILL because their SIGTERM handler never returned.

Knowledge check

Knowledge check · 5 questions

  1. Q1. Which of the following signals cannot be caught, blocked, or ignored?

  2. Q2. Real-time signals (SIGRTMIN+) carry a payload and are queued individually.

  3. Q3. Which of the following are correct signal-handling practices for production daemons? Select all that apply.

  4. Q4. A bash daemon installs a SIGTERM trap that removes its lock file, then loops on a foreground `sleep 300`. On `systemctl stop` the unit takes the full TimeoutStopSec, is SIGKILLed, and the lock file is left behind. What is wrong?

  5. Q5. Writing `trap cleanup-and-exit TERM`, where cleanup-and-exit is meant as a description of what to do, installs a working handler.

Passing score: 75%. Answers are checked in this browser.