← Linux: процессы вглубь
12 мин · средне · Урок 3 из 7

Сигналы вглубь: что ловится, что нет

Сигналы вглубь: что перехватывается, а что нет.

Что такое сигнал

Сигнал — асинхронное уведомление, которое ядро или другой процесс доставляет процессу. Асинхронное значит, что оно приходит в произвольный момент, а не тогда, когда процесс сам его ждёт. Процесс в это время может считать, спать или обрабатывать запрос, и сигнал прервёт его на середине.

Отправить сигнал можно командой kill. Название сбивает с толку: kill означает «послать сигнал», а не обязательно завершить.

kill -TERM 1234    # послать SIGTERM процессу 1234
kill -HUP 1234     # послать SIGHUP

Полный список имён и номеров показывает kill -l:

$ kill -l
 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
...

Пять действий по умолчанию

У каждого сигнала есть действие по умолчанию — то, что произойдёт, если процесс не задал свой обработчик. Всего таких действий пять.

ДействиеЧто делает
Termзавершить процесс
Ignпроигнорировать сигнал
Coreзавершить и записать core dump
Stopприостановить выполнение
Contпродолжить приостановленный

Например, у SIGSEGV (обращение к чужой памяти) действие по умолчанию Core: процесс падает и оставляет дамп для отладки. У SIGCHLD (потомок завершился) действие по умолчанию Ign, поэтому родитель по умолчанию про такой сигнал ничего не делает.

Свой обработчик почти на любой сигнал

Процесс может назначить свою функцию-обработчик почти на любой сигнал и тем самым переопределить действие по умолчанию. На этом стоит graceful shutdown: демон ловит SIGTERM, дописывает данные и закрывает соединения, а не умирает мгновенно.

Два сигнала переопределить нельзя: SIGKILL (9) и SIGSTOP (19). Это единственные два, которые процесс не может перехватить, заблокировать или проигнорировать. Ядро обрабатывает их само, минуя код процесса.

kill -9 1234     # SIGKILL: процесс не увидит его, ядро снимет насильно
kill -STOP 1234  # SIGSTOP: заморозка, тоже без права отказа

Частые сигналы

SIGTERM (15) — вежливая просьба завершиться. Это сигнал по умолчанию у kill, когда номер не указан. Процесс волен обработать его и прибраться за собой.

SIGKILL (9) — жёсткое завершение без права на обработку. Данные, которые процесс не успел записать, теряются.

SIGHUP (1) — исторически «терминал закрылся». У демонов по соглашению означает «перечитай конфиг», поэтому kill -HUP часто применяют вместо перезапуска сервиса.

SIGINT (2) прилетает по Ctrl+C, SIGTSTP (20) приходит по Ctrl+Z. Оба генерирует терминал, и оба процесс может перехватить. Не путай SIGTSTP с SIGSTOP (19): первый вежливый и переопределяемый, второй неотменяемый.

$ sleep 300
^C                 # терминал шлёт SIGINT (2), sleep завершается
$ sleep 300
^Z                 # терминал шлёт SIGTSTP (20), sleep уходит в стоп
[1]+  Stopped   sleep 300

Две частые ловушки

Первая: «kill всегда убивает». По умолчанию kill шлёт SIGTERM, а его процесс может перехватить и, например, проигнорировать. Если процесс не реагирует на SIGTERM, он останется жить.

Вторая: «kill -9 завершает корректно». Наоборот: SIGKILL рвёт процесс на любом месте. Полузаписанный файл, неснятый lock, оборванное соединение с БД. Правильный порядок: сначала SIGTERM, дать время на graceful, и только для зависшего намертво процесса применять SIGKILL.

Сироты и зомби

Когда родитель умирает раньше потомка, потомок становится осиротевшим и его усыновляет init (PID 1). Init периодически делает wait() и забирает код возврата усыновлённых, поэтому долго висеть они не будут. С ядра 3.4 роль сборщика можно делегировать вместо PID 1 промежуточному процессу-subreaper через prctl(PR_SET_CHILD_SUBREAPER).

Зомби — завершённый процесс, чей код возврата ещё не забрал родитель вызовом wait(). Он держит запись в таблице процессов (номер PID), но не память. Ресурсов почти не ест, опасен только числом: если родитель не вызывает wait(), зомби копятся и могут исчерпать таблицу PID.

$ ps aux | awk '$8 ~ /Z/'
user  4821  0.0  0.0   0    0  Z   10:22  0:00 [worker] <defunct>

Что важно запомнить

Сигнал — асинхронное уведомление; действий по умолчанию пять: Term, Ign, Core, Stop, Cont.

SIGKILL (9) и SIGSTOP (19) — единственные, что нельзя перехватить, заблокировать или проигнорировать.

SIGTERM (15) вежливый и переопределяемый, у kill он по умолчанию; SIGKILL рвёт без сохранения. Сначала TERM, потом KILL.

SIGCHLD по умолчанию игнорируется; зомби держит запись PID, а не память; сироту усыновляет init (PID 1) и делает wait().

В следующем уроке — зомби и сироты: откуда берутся и как их убирает reaping.

Дрилл · вопросы как на собесе

Проверь себя без подсказок

Сформулируй ответ вслух или письменно, потом раскрой и честно отметь: знал или нет.

01

Для чего нужны сигналы? Перечисли 5–10 самых частых.

LIN-010
02

Что делает команда kill? Какие сигналы можно слать?

LIN-026
03

В чём разница между Ctrl+C и Ctrl+Z? Какой сигнал получит активный процесс?

LIN-035

Прошли материал до конца? Отметьте урок пройденным.