Как SIGINT соотносится с другими сигналами завершения, такими как SIGTERM, SIGQUIT и SIGKILL?

103

В системах POSIX сигналы завершения обычно имеют следующий порядок (согласно многим страницам MAN и спецификации POSIX):

  1. SIGTERM - вежливо попросить завершить процесс. Он должен завершиться корректно, очистив все ресурсы (файлы, сокеты, дочерние процессы и т. Д.), Удалив временные файлы и так далее.

  2. SIGQUIT - более сильная просьба. Он должен прекратить некорректную очистку ресурсов, которые абсолютно нуждаются в очистке, но, возможно, не удалит временные файлы, возможно, где-нибудь запишет отладочную информацию; в некоторых системах также будет записан дамп ядра (независимо от того, пойман ли сигнал приложением или нет).

  3. СИГКИЛЛ - сильнейшая просьба. Процесс даже не просит что-либо делать, но система очистит процесс, нравится ему это или нет. Скорее всего написан дамп ядра.

Как SIGINT вписывается в эту картину? Процесс CLI обычно завершается SIGINT, когда пользователь нажимает CRTL + C, однако фоновый процесс также может быть завершен SIGINT с помощью утилиты KILL. Что я не вижу в спецификациях или файлах заголовков, так это то, является ли SIGINT более или менее убедительным, чем SIGTERM, или есть ли вообще какая-либо разница между SIGINT и SIGTERM.

ОБНОВИТЬ:

Лучшее описание сигналов завершения, которое я нашел до сих пор, находится в документации GNU LibC . Это очень хорошо объясняет предполагаемое различие между SIGTERM и SIGQUIT.

О SIGTERM сказано:

Это нормальный способ вежливо попросить программу завершить работу.

А про SIGQUIT сказано:

[...] и производит дамп ядра при завершении процесса, как сигнал об ошибке программы. Вы можете думать об этом как о состоянии ошибки программы, «обнаруженной» пользователем. [...] Определенные виды очистки лучше не выполнять при обработке SIGQUIT. Например, если программа создает временные файлы, она должна обрабатывать другие запросы на завершение, удаляя временные файлы. Но SIGQUIT лучше не удалять их, чтобы пользователь мог изучить их вместе с дампом ядра.

И SIGHUP тоже достаточно хорошо объяснен. SIGHUP на самом деле не является сигналом завершения, это просто означает, что «соединение» с пользователем было потеряно, поэтому приложение не может ожидать, что пользователь прочитает какой-либо дальнейший вывод (например, вывод stdout / stderr), и нет ввода, ожидаемого от пользователь больше. Для большинства приложений это означает, что им лучше выйти. Теоретически приложение может также решить, что оно переходит в режим демона при получении SIGHUP и теперь работает как фоновый процесс, записывая выходные данные в настроенный файл журнала. Для большинства демонов, уже работающих в фоновом режиме, SIGHUP обычно означает, что они должны повторно проверить свои файлы конфигурации, поэтому вы отправляете его фоновым процессам после редактирования файлов конфигурации.

Однако на этой странице нет полезного объяснения SIGINT, кроме того, что он отправляется CRTL + C. Есть ли причина, по которой можно обрабатывать SIGINT иначе, чем SIGTERM? Если да, то по какой причине это было бы и чем было бы иначе?

Mecki
источник
1
Хороший вопрос. Я подозреваю, что в ответе будет задействована часть исторической неразберихи с Unix.
Alex B
Я знаю, что это старый вопрос, но если кто-то пришел сюда за обширным списком сигналов для вашей (Linux) ОС, их можно найти, набрав sudo fuser -lв командной строке. Для меня это вызывает:HUP INT QUIT ILL TRAP ABRT IOT BUS FPE KILL USR1 SEGV USR2 PIPE ALRM TERM STKFLT CHLD CONT STOP TSTP TTIN TTOU URG XCPU XFSZ VTALRM PROF WINCH IO PWR SYS UNUSED
Ник Булл
3
Также попробуйте kill -lполучить список сигналов.
AAAfarmclub

Ответы:

89

SIGTERM и SIGKILL предназначены для общих запросов «прекратить этот процесс». SIGTERM (по умолчанию) и SIGKILL (всегда) вызовут завершение процесса. SIGTERM может быть перехвачен процессом (например, чтобы он мог выполнить свою собственную очистку, если захочет) или даже полностью проигнорирован; но SIGKILL нельзя поймать или проигнорировать.

SIGINT и SIGQUIT предназначены специально для запросов от терминала: для генерации этих сигналов могут быть назначены определенные входные символы (в зависимости от настроек управления терминалом). Действие по умолчанию для SIGINT - это тот же вид завершения процесса, что и действие по умолчанию для SIGTERM и неизменное действие для SIGKILL; действием по умолчанию для SIGQUIT также является завершение процесса, но могут произойти дополнительные действия, определяемые реализацией, такие как создание дампа ядра. При необходимости процесс может либо поймать, либо проигнорировать.

SIGHUP, как вы говорите, предназначен для указания того, что терминальное соединение было потеряно, а не для того, чтобы быть сигналом завершения как таковым. Но, опять же, действие по умолчанию для SIGHUP (если процесс не улавливает или не игнорирует его) - завершить процесс таким же образом, как SIGTERM и т. Д.

В определениях POSIX есть таблица, в signal.hкоторой перечислены различные сигналы, их действия и цели по умолчанию, а в главе « Общий интерфейс терминала» содержится более подробная информация о сигналах, связанных с терминалом.

Мэтью Слэттери
источник
10
Это ключевой момент: SIGINT и SIGQUIT могут быть сгенерированы из терминала с использованием одиночных символов во время работы программы. Остальные сигналы должны каким-то образом генерироваться другой программой (например, командой kill). SIGINT менее жесток, чем SIGQUIT; последний производит дамп ядра. SIGKILL не может быть пойман. SIGHUP генерируется, если ваше соединение зависает (окно закрывается и т. Д.). Итак, все они имеют разное значение.
Джонатан Леффлер,
TTY Demystified содержит некоторую легко усваиваемую информацию о том, как сигналы взаимодействуют с подсистемой tty ядра. Добавляет контекст к вашему ответу.
Daniel Näslund
2
Похоже, что спецификации не очень точны, но я понимаю, что SIgint просит программу остановить текущее действие, а не обязательно выйти. Для программы, разработанной только для выполнения одного действия за запуск, которое подразумевает выход, но для интерактивной программы, которая имеет какой-то цикл чтения-оценки-печати, это может означать отказ от текущего eval и возврат к чтению пользовательского ввода. Я думаю, что на sigint это не так.
bdsl
Какой сигнал отправляется при перезагрузке?
Дэн Даскалеску
10

Как заметил DarkDust, многие сигналы имеют одинаковые результаты, но процессы могут присоединять к ним разные действия, различая, как генерируется каждый сигнал. Глядя на исходный код ядра FreeBSD (kern_sig.c), я вижу, что два сигнала обрабатываются одинаково, они завершают процесс и доставляются в любой поток.

SA_KILL|SA_PROC,             /* SIGINT */
SA_KILL|SA_PROC,             /* SIGTERM */
Диомидис Спинеллис
источник
9

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 rebootотправляет SIGTERM процессам, засыпает на секунду, а затем отправляет SIGKILL. Кажется, это обычное соглашение для разных дистрибутивов.

Когда вы завершаете работу системы BusyBox с помощью:

reboot

он отправляет сигнал процессу инициализации.

Затем обработчик сигнала инициализации вызывает:

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

Вот минимальный конкретный пример этого .

Сигналы, отправленные ядром

Чиро Сантилли 郝海东 冠状 病 六四 事件 法轮功
источник
8

После быстрого поиска в Google sigint vs sigterm , похоже, единственная предполагаемая разница между ними заключается в том, был ли он инициирован сочетанием клавиш или явным вызовомkill .

В результате вы можете, например, перехватить sigint и сделать с ним что-то особенное, зная, что он, вероятно, был отправлен с помощью сочетания клавиш. Возможно, обновите экран или что-то в этом роде, вместо того, чтобы умирать (не рекомендуется, как люди ожидают^C убить программу, просто пример).

Я также узнал, что ^\должен отправлять sigquit, который я могу начать использовать сам. Выглядит очень полезно.

Джонатан
источник
3

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

При этом SIGINT действительно предназначен для прерывания Ctrl-C, в то время как SIGTERM является общим терминальным сигналом. Не существует концепции «более сильного» сигнала, за единственным исключением, что есть сигналы, которые нельзя заблокировать или обработать (SIGKILL и SIGSTOP, согласно странице руководства).

Сигнал может быть «более сильным», чем другой сигнал, только в отношении того, как принимающий процесс обрабатывает сигнал (и каково действие по умолчанию для этого сигнала). Например, по умолчанию и SIGTERM, и SIGINT приводят к завершению. Но если вы проигнорируете SIGTERM, он не завершит ваш процесс, в то время как SIGINT все еще завершает работу.

Темная пыль
источник
0

За исключением нескольких сигналов, обработчики сигналов могут улавливать различные сигналы, или поведение по умолчанию при получении сигнала может быть изменено. См. Подробности на signal(7)странице руководства .

Игнасио Васкес-Абрамс
источник
Да, но если я не знаю «значения» единственного числа, улавливать сигнал бессмысленно, потому что я не буду знать, что делать в моем приложении. GNU C, например, объясняет разницу между SIGQUIT и SIGTERM. Но это дает мало информации о SIGINT: gnu.org/s/libc/manual/html_node/Termination-Signals.html
Mecki
«Сигнал SIGINT(« программное прерывание ») отправляется, когда пользователь набирает символ INTR (обычно C-c)». «SIGINT 2 Term Interrupt с клавиатуры». Вы нажимаете Ctrl-C, SIGINTотправляется. Процесс нормально умирает. Что еще дать?
Игнасио Васкес-Абрамс,
Возможно, там может быть описание намерения, которое программист должен предполагать у пользователя, когда он нажимает ctrl-c, то есть семантику сообщения. В качестве примера спецификация HTTP поясняет, что когда пользователь отправляет запрос GET, сервер не должен предполагать, что он хочет, чтобы он что-то сделал, кроме отправки ответа.
bdsl