Сигналы вглубь: что ловится, что нет
Сигналы вглубь: что перехватывается, а что нет.
Что такое сигнал
Сигнал — асинхронное уведомление, которое ядро или другой процесс доставляет процессу. Асинхронное значит, что оно приходит в произвольный момент, а не тогда, когда процесс сам его ждёт. Процесс в это время может считать, спать или обрабатывать запрос, и сигнал прервёт его на середине.
Отправить сигнал можно командой 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.
Дрилл · вопросы как на собесе
Проверь себя без подсказок
Сформулируй ответ вслух или письменно, потом раскрой и честно отметь: знал или нет.
Для чего нужны сигналы? Перечисли 5–10 самых частых.
LIN-010Что делает команда kill? Какие сигналы можно слать?
LIN-026В чём разница между Ctrl+C и Ctrl+Z? Какой сигнал получит активный процесс?
LIN-035Прошли материал до конца? Отметьте урок пройденным.
Прогресс сохранён в этом браузере
Почистишь историю или откроешь с телефона, и отметки пропадут. Оставь почту, они переедут в аккаунт. Пароль придумывать не нужно.
Готово. теперь в аккаунте: прогресс виден с любого устройства. Мой прогресс