Как SIGINT относится к другим сигналам завершения, таким как SIGTERM, SIGQUIT и SIGKILL?
В системах POSIX сигналы терминации обычно имеют следующий порядок (согласно многим страницам MAN и спецификации POSIX):
-
SIGTERM - вежливо попросить процесс прекратить работу. Он прекращает изящество, очищая все ресурсы (файлы, сокеты, дочерние процессы и т.д.), Удаляя временные файлы и т.д.
-
SIGQUIT - более сильный запрос. Он должен прекратить несправедливое, все еще очищать ресурсы, которые абсолютно нуждаются в очистке, но, возможно, не удалять временные файлы, возможно, где-то писать информацию об отладке; на какой-то системе также будет записываться основной дамп (независимо от того, пойман ли сигнал приложением или нет).
-
SIGKILL - самый сильный запрос. Процесс даже не просят ничего сделать, но система очистит процесс, нравится это или нет. Скорее всего, создается дамп ядра.
Как SIGINT вписывается в эту картинку? Процесс CLI обычно заканчивается SIGINT, когда пользователь нажимает CRTL + C, однако фоновый процесс также может быть прерван SIGINT с помощью утилиты KILL. То, что я не вижу в спецификациях или заголовочных файлах, - это если SIGINT более или менее силен, чем SIGTERM, или существует какая-либо разница между SIGINT и SIGTERM вообще.
UPDATE:
Лучшее описание сигналов завершения, которые я нашел до сих пор, находится в документации GNU LibC. Он очень хорошо объясняет, что существует разница между SIGTERM и SIGQUIT.
В нем говорится о SIGTERM:
Это обычный способ вежливо просить программу прекратить работу.
И он говорит о SIGQUIT:
[...] и создает дамп ядра, когда он завершает процесс, точно так же, как сигнал программной ошибки. Вы можете думать об этом как о программном ошибке, "обнаруженном" пользователем. [...] Некоторые виды очистки лучше всего пропускать при обработке SIGQUIT. Например, если программа создает временные файлы, он должен обрабатывать другие запросы на завершение, удаляя временные файлы. Но SIGQUIT лучше не удалять их, чтобы пользователь мог их исследовать в в сочетании с дампом ядра.
И SIGHUP также объясняется достаточно хорошо. SIGHUP на самом деле не является сигналом завершения, это просто означает, что "соединение" с пользователем было потеряно, поэтому приложение не может ожидать, что пользователь прочитает какой-либо дальнейший вывод (например, вывод stdout/stderr), и нет ожидаемого результата от пользователя. Для большинства приложений, которые означают, что они лучше уходят. Теоретически приложение может также решить, что оно переходит в режим демона при получении SIGHUP и теперь выполняется как фоновый процесс, записывая вывод в сконфигурированный файл журнала. Для большинства демонов, уже работающих в фоновом режиме, SIGHUP обычно означает, что они должны пересмотреть свои файлы конфигурации, поэтому вы отправляете их в фоновый процесс после редактирования файлов конфигурации.
Однако на этой странице нет полезного объяснения SIGINT, кроме того, что оно отправляется CRTL + C. Есть ли причина, по которой можно было бы обрабатывать SIGINT иначе, чем SIGTERM? Если да, то какова была бы причина и как будет отличаться обработка?
Ответы
Ответ 1
SIGTERM и SIGKILL предназначены для общего назначения "прекратить этот процесс". SIGTERM (по умолчанию) и SIGKILL (всегда) вызовет завершение процесса. SIGTERM может быть захвачен процессом (например, чтобы он мог выполнять свою собственную очистку, если захочет), или даже полностью игнорировал его; но SIGKILL нельзя поймать или проигнорировать.
SIGINT и SIGQUIT предназначены специально для запросов от терминала: для ввода этих сигналов могут быть назначены конкретные входные символы (в зависимости от настроек управления терминалом). Действие по умолчанию для SIGINT - это то же самое завершение процесса, что и действие по умолчанию для SIGTERM и неизменяемое действие для SIGKILL; действие по умолчанию для SIGQUIT также является завершением процесса, но могут возникнуть дополнительные действия, определенные для реализации, такие как генерация дампа ядра. Любой может быть пойман или проигнорирован процессом, если требуется.
SIGHUP, как вы говорите, предназначен для указания того, что терминальное соединение потеряно, а не как сигнал терминации как таковой. Но, опять же, действие по умолчанию для SIGHUP (если процесс не улавливает или игнорирует его) заключается в том, чтобы завершить процесс так же, как SIGTERM и т.д.
В определениях POSIX есть таблица signal.h
, в которой перечислены различные сигналы и их действия и цели по умолчанию, а в главе Общий интерфейс терминалов содержится более подробная информация о сигналах, связанных с терминалом.
Ответ 2
Как отмечал DarkDust, многие сигналы имеют одинаковые результаты, но процессы могут приложить к ним разные действия, различая, как генерируется каждый сигнал. Посмотрев исходный код ядра FreeBSD (kern_sig.c), я вижу, что оба сигнала обрабатываются одинаково, они завершают процесс и доставляются в любой поток.
SA_KILL|SA_PROC, /* SIGINT */
SA_KILL|SA_PROC, /* SIGTERM */
Ответ 3
После быстрого поиска в Google sigint vs sigterm, похоже, единственная предполагаемая разница между ними заключается в том, была ли она инициирована клавиатурой ярлык или явный вызов kill
.
В результате вы могли бы, например, перехватить sigint и сделать что-то особенное с ним, зная, что это скорее всего отправлено с помощью сочетания клавиш. Возможно, обновите экран или что-то еще, вместо того, чтобы умереть (не рекомендуется, поскольку люди ожидают, что ^C
, чтобы убить программу, просто пример).
Я также узнал, что ^\
должен отправить sigquit, который я могу начать использовать сам. Выглядит очень полезно.
Ответ 4
man 7 signal
Это удобная ненормативная справочная страница проекта man-страниц Linux, на которую вы часто хотите посмотреть информацию о сигналах Linux.
Версия 3.22 упоминает интересные вещи, такие как:
Сигналы SIGKILL и SIGSTOP не могут быть пойманы, заблокированы или проигнорированы.
и содержит таблицу:
Signal Value Action Comment
----------------------------------------------------------------------
SIGHUP 1 Term Hangup detected on controlling terminal
or death of controlling process
SIGINT 2 Term Interrupt from keyboard
SIGQUIT 3 Core Quit from keyboard
SIGILL 4 Core Illegal Instruction
SIGABRT 6 Core Abort signal from abort(3)
SIGFPE 8 Core Floating point exception
SIGKILL 9 Term Kill signal
SIGSEGV 11 Core Invalid memory reference
SIGPIPE 13 Term Broken pipe: write to pipe with no
readers
SIGALRM 14 Term Timer signal from alarm(2)
SIGTERM 15 Term Termination signal
SIGUSR1 30,10,16 Term User-defined signal 1
SIGUSR2 31,12,17 Term User-defined signal 2
SIGCHLD 20,17,18 Ign Child stopped or terminated
SIGCONT 19,18,25 Cont Continue if stopped
SIGSTOP 17,19,23 Stop Stop process
SIGTSTP 18,20,24 Stop Stop typed at tty
SIGTTIN 21,21,26 Stop tty input for background process
SIGTTOU 22,22,27 Stop tty output for background process
который суммирует сигнал Action
, который различает, например, SIGQUIT от SIGQUIT, так как SIGQUIT имеет действие Core
и SIGINT Term
.
Действия задокументированы в одном документе:
The entries in the "Action" column of the tables below specify the default disposition for each signal, as follows:
Term Default action is to terminate the process.
Ign Default action is to ignore the signal.
Core Default action is to terminate the process and dump core (see core(5)).
Stop Default action is to stop the process.
Cont Default action is to continue the process if it is currently stopped.
Я не вижу никакой разницы между SIGTERM и SIGINT с точки зрения ядра, так как оба имеют действие Term
и оба могут быть перехвачены. Похоже, что это просто "различие между соглашениями об использовании":
- SIGINT - это то, что происходит, когда вы выполняете CTRL-C с терминала
- SIGTERM - это сигнал по умолчанию, посылаемый
kill
Некоторые сигналы соответствуют стандарту ANSI C, а другие нет
Значительная разница в том, что:
- SIGINT и SIGTERM - это ANSI C, поэтому они более портативны
- SIGQUIT и SIGKILL не являются
Они описаны в разделе "7.14 Обработка сигналов" в проекте C99 N1256:
- SIGINT получение интерактивного сигнала внимания
- SIGTERM запрос на прекращение отправлен в программу
что делает SIGINT хорошим кандидатом на интерактивные Ctrl + C.
POSIX 7
POSIX 7 документирует сигналы с заголовком signal.h
: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/signal.h.html
На этой странице также есть следующая интересная таблица, в которой упоминаются некоторые вещи, которые мы уже видели в man 7 signal
:
Signal Default Action Description
SIGABRT A Process abort signal.
SIGALRM T Alarm clock.
SIGBUS A Access to an undefined portion of a memory object.
SIGCHLD I Child process terminated, stopped,
SIGCONT C Continue executing, if stopped.
SIGFPE A Erroneous arithmetic operation.
SIGHUP T Hangup.
SIGILL A Illegal instruction.
SIGINT T Terminal interrupt signal.
SIGKILL T Kill (cannot be caught or ignored).
SIGPIPE T Write on a pipe with no one to read it.
SIGQUIT A Terminal quit signal.
SIGSEGV A Invalid memory reference.
SIGSTOP S Stop executing (cannot be caught or ignored).
SIGTERM T Termination signal.
SIGTSTP S Terminal stop signal.
SIGTTIN S Background process attempting read.
SIGTTOU S Background process attempting write.
SIGUSR1 T User-defined signal 1.
SIGUSR2 T User-defined signal 2.
SIGTRAP A Trace/breakpoint trap.
SIGURG I High bandwidth data is available at a socket.
SIGXCPU A CPU time limit exceeded.
SIGXFSZ A File size limit exceeded.
BusyBox init
Команда BusyBox 1.29.2 default reboot
отправляет процессам сигнал SIGTERM, на секунду останавливается, а затем отправляет сигнал SIGKILL. Похоже, это общее соглашение в разных дистрибутивах.
Когда вы выключаете систему BusyBox с помощью:
reboot
он отправляет сигнал процессу init.
Затем обработчик сигнала init завершает вызов:
static void run_shutdown_and_kill_processes(void)
{
/* Run everything to be run at "shutdown". This is done _prior_
* to killing everything, in case people wish to use scripts to
* shut things down gracefully... */
run_actions(SHUTDOWN);
message(L_CONSOLE | L_LOG, "The system is going down NOW!");
/* Send signals to every process _except_ pid 1 */
kill(-1, SIGTERM);
message(L_CONSOLE, "Sent SIG%s to all processes", "TERM");
sync();
sleep(1);
kill(-1, SIGKILL);
message(L_CONSOLE, "Sent SIG%s to all processes", "KILL");
sync();
/*sleep(1); - callers take care about making a pause */
}
который печатает в терминал:
The system is going down NOW!
Sent SIGTERM to all processes
Sent SIGKILL to all processes
Вот минимальный конкретный пример этого.
Сигналы, отправленные ядром
Ответ 5
Используя kill
(как системный вызов, так и утилиту), вы можете отправлять практически любой сигнал на любой процесс, если у вас есть разрешение. Процесс не может отличить, как оживился сигнал и кто его отправил.
Как сказано, SIGINT действительно предназначен для воспроизведения прерывания Ctrl-C, тогда как SIGTERM является общим терминальным сигналом. Нет понятия, что сигнал "более силен", за исключением того, что есть сигналы, которые нельзя заблокировать или обработать (SIGKILL и SIGSTOP, согласно странице руководства).
Сигнал может быть только "более сильным", чем другой сигнал в отношении того, как принимающий процесс обрабатывает сигнал (и каково действие по умолчанию для этого сигнала). Например, по умолчанию оба SIGTERM и SIGINT приводят к завершению. Но если вы проигнорируете SIGTERM, то это не остановит ваш процесс, пока SIGINT все еще делает.
Ответ 6
За исключением нескольких сигналов, обработчики сигналов могут захватывать различные сигналы, или поведение по умолчанию при получении сигнала может быть изменено. Подробнее см. Справочную страницу signal(7)
.