Signal 是什麼#

Signal 是 Linux 提供給 process 的「軟體中斷」。當某個事件發生(使用者按 Ctrl-C、子行程結束、kernel 偵測 segfault),kernel 會向 process 發送一個 signal,打斷它原本的執行流程,跳去執行對應的 signal handler。

  • Signal 是非同步的:可能在任何指令之間插入
  • Signal 是有編號的:例如 SIGTERM=15、SIGKILL=9
  • Signal 有「disposition」:default、ignore、custom handler

常用 Signal 一覽#

下列幾個 signal 在 container 與服務管理場景最常用,值得熟記。

  • SIGTERM(15):請求終止,可被捕捉、可被忽略,預設行為是終止
  • SIGKILL(9):強制終止,不可被捕捉、不可被忽略
  • SIGINT(2):使用者中斷(Ctrl-C),可被捕捉,預設終止
  • SIGHUP(1):終端斷線;服務常用作 reload 設定的訊號
  • SIGCHLD(17 在 x86_64):子行程狀態改變(exit、stopped、continued)
  • SIGUSR1(10)/SIGUSR2(12):使用者自訂語意
  • SIGSTOP(19):暫停 process,不可被捕捉
  • SIGCONT(18):恢復暫停的 process

SIGKILL 與 SIGSTOP 是 kernel 強制執行的,無法被 process 自己改變行為。其他幾乎都可以捕捉或忽略。

Signal Disposition#

每個 signal 對某個 process 有一種「disposition」設定,描述收到時要做什麼。

  • Default(SIG_DFL):依 signal 種類有預設行為(terminate、ignore、core dump、stop、continue)
  • Ignore(SIG_IGN):直接丟掉,不做任何事
  • Custom handler:跳到使用者指定的函式執行

切換 disposition 用 sigaction(2)(推薦)或 signal(2)(古老、語意不一致)。

Trap:Shell 層級的 Signal Handler#

在 shell script 裡,要對 signal 做事不是用 sigaction,而是用 trap

#!/bin/bash
trap 'echo got SIGTERM; exit 0' TERM
trap 'echo got SIGINT;  exit 130' INT

while true; do
    sleep 1
done
  • trap '<command>' SIGNAME ...:收到該 signal 時執行 command
  • trap '' SIGNAME:忽略
  • trap - SIGNAME:恢復預設

trap 在 bash 與 dash 行為類似,但 dash(Ubuntu /bin/sh)不支援某些 bash 擴充,後章會展開。

哪些 Signal 可以忽略#

絕大多數 signal 都可以忽略(SIG_IGN),但有兩個例外:

  • SIGKILL:永遠送達、永遠終止
  • SIGSTOP:永遠送達、永遠暫停

這兩者無法 catch、無法 ignore、無法 block。它們是 kernel 給 root 的最後手段。

Signal 與 Process Group#

Linux signal 可以一次送給整個 process group(PGID)。kill -TERM -PGID(PID 給負數)會把 SIGTERM 廣播給 group 內所有成員。

  • Shell job control 依賴 process group
  • Container init(tini)也用這個機制把 signal 從 PID 1 廣播下去
  • 若應用是 process group leader,killpg(2) 一次就能搞定整個子樹

Signal 與 PID Namespace#

Container 內的 PID namespace 對 signal 有兩個影響。

  • 從 host 對 container PID 1 發 signal,需要用 host 視角的 PID
  • Container 內 kill -TERM 1 因為 kernel 對 PID 1 的特殊保護,往往不會生效(除非 PID 1 自己裝過 handler)

詳細的 PID 1 保護規則見最後一章 11-can-pid1-be-killed

一張行為對照表#

Signal編號預設可 catch可 ignore典型用途
SIGTERM15terminategraceful shutdown
SIGKILL9terminate強制終止
SIGINT2terminateCtrl-C
SIGHUP1terminatereload / 斷線
SIGCHLD-ignorereap
SIGUSR1-terminate自訂
SIGSTOP19stop強制暫停

延伸閱讀#

  • man 7 signal
  • man 2 sigaction
  • man 1 trap (built-in in bash/dash)