Как 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).