Что такое сигнал
Сигнал — это однословное сообщение, которое ядро доставляет процессу: «терминал закрылся», «вы обратились к недопустимой памяти», «пожалуйста, остановитесь». Для большинства из них процесс может установить обработчик, проигнорировать их или принять действие по умолчанию, которым обычно является завершение (иногда с дампом памяти). Два сигнала нельзя ни перехватить, ни проигнорировать: SIGKILL завершает процесс на месте, а SIGSTOP замораживает его.
TERM против KILL
kill PID отправляет SIGTERM: просьбу. Хорошо написанная программа перехватывает его, завершает текущий запрос, сбрасывает буферы файлов, закрывает соединения и выходит; именно его первым отправляют systemd, Docker и Kubernetes. kill -9 отправляет SIGKILL: ядро удаляет процесс, не выполняя ни строчки его кода, поэтому блокировки остаются занятыми, временные файлы остаются, а незавершённые записи теряются. Используйте его только после того, как TERM дали время (systemd ждёт TimeoutStopSec, Docker — 10 секунд по умолчанию) и он не сработал.
Сигналы как API
- SIGHUP: демоны перечитывают конфигурацию (nginx, sshd, HAProxy с семантикой
-sfчерез reload в systemd). Для процесса в переднем плане он означает, что терминал пропал;nohupигнорирует его. - SIGUSR1 / SIGUSR2: определяются программой. nginx переоткрывает логи по USR1 и обновляет бинарник по USR2;
ddвыводит прогресс по USR1; Gunicorn и Unicorn используют их для плавного перезапуска. - SIGPIPE: запись в канал, читатель которого завершился. Его действие по умолчанию — завершение — объясняет, почему
yes | headзаканчивается и почему серверы должны игнорировать его или обрабатывать ошибки записи. - SIGCHLD: дочерний процесс завершился; родители забирают детей через
wait(), а родитель, который этого не делает, оставляет зомби. - SIGWINCH: размер терминала изменился; редакторы и мультиплексоры перерисовываются.
Отправка сигналов
kill -TERM 1234 # по имени (или kill -15 1234)
kill -s USR1 $(pidof nginx)
pkill -HUP sshd # по имени процесса
killall -9 runaway # все процессы с этим именем
systemctl kill -s HUP myservice
docker kill --signal=SIGUSR1 container Номера 1–15 одинаковы во всех Unix; выше они различаются по архитектурам (SIGUSR1 — это 10 на x86 и 30 на SPARC/MIPS), поэтому в скриптах следует использовать имена.
Вопросы
В чём разница между SIGTERM и SIGKILL?
SIGTERM просит процесс завершиться, и его можно обработать; SIGKILL завершает его немедленно, и его нельзя перехватить. Всегда сначала пробуйте TERM; KILL — для зависших процессов.
Что такое сигнал 11 / SIGSEGV?
Ошибка сегментации: программа прочитала или записала память, которая ей не принадлежит, обычно нулевой или висячий указатель в коде на C/C++ или баг в нативном расширении. Shell сообщает код выхода 139.
Почему мой процесс завершился с кодом 137, хотя никто не запускал kill -9?
Это сделало ядро: при исчерпании памяти OOM killer отправляет SIGKILL самому большому процессу, а среды выполнения контейнеров делают то же при достижении лимита памяти. Проверьте dmesg или флаг OOMKilled контейнера.
Можно ли игнорировать SIGINT, чтобы Ctrl-C не останавливал мой скрипт?
Да: trap "" INT в bash или signal.signal(SIGINT, SIG_IGN) в Python. Обычно лучше перехватить его и прибраться перед выходом, чтобы пользователь всё же мог остановить скрипт.