SIGNAL(7) | Руководство программиста Linux | SIGNAL(7) |
signal - обзор сигналов
В Linux поддерживаются надёжные (reliable) сигналы POSIX (далее, «стандартные сигналы») и сигналы реального времени POSIX.
Каждый сигнал имеет текущий обработчик, который определяет, что будет делать процесс при поступлении сигнала.
В таблице далее есть столбец «Действие», в котором указан обработчик по умолчанию для каждого сигнала:
Процесс может изменить обработчик сигнала с помощью sigaction(2) или signal(2) (менее переносим; дополнительную информацию смотрите в signal(2)). Используя данные системные вызовы процесс может выбрать одно из следующих действий при получении сигнала: выполнить действие по умолчанию, игнорировать сигнал, поймать сигнал обработчиком сигнала — функцией, задаваемой программистом, которая автоматически вызывается при получении сигнала (по умолчанию обработчик сигнала использует обычный стек процесса. Возможно сделать так, чтобы обработчик сигнала использовал альтернативный стек; как это делается и когда это может быть полезно смотрите в sigaltstack(2)).
Реакция на сигналы является атрибутом процесса: в многонитевом приложении реакция на определённый сигнал одинакова для всех нитей.
Потомок, созданный с помощью fork(2), наследует реакцию на сигналы от своего родителя. При execve(2) реакция на сигналы устанавливается в значение по умолчанию; реакция на игнорируемые сигналы не изменяется.
Для отправки сигнала можно использовать следующие системные вызовы и библиотечные функции:
Следующие системные вызовы приостанавливают выполнение вызывающей нити до тех пор, пока не будет пойман сигнал (или необработанный сигнал не завершит процесс):
В отличие от асинхронного получения сигнала через обработчик, возможно синхронно получить сигнал, то есть блокировать выполнение до поступления сигнала в некоторой точке, в которой ядро вернёт информацию о сигнале вызывающему. Для этого существует два пути:
Сигнал может быть заблокирован. Это означает, что он не будет доставлен до тех пор, пока не будет разблокирован. В промежуток времени от генерации сигнала и до его доставки о сигнале говорят как об ожидающем.
В каждой нити процесса имеется независимая сигнальная маска, определяющая набор сигналов, которые нить, в данный момент, блокирует. Нить может управлять сигнальной маской с помощью pthread_sigmask(3). В обычном однонитевом приложении для работы с сигнальной маской можно использовать вызов sigprocmask(2).
Потомок, создаваемый с помощью fork(2), наследует копию родительской маски сигналов; маска сигналов сохраняется при вызове execve(2).
Сигнал может быть сгенерирован (а значит и стать ожидающим) как для всего процесса (например, при отправке с помощью kill(2)) так и для отдельной нити (например, некоторые сигналы, такие как SIGSEGV и SIGFPE, сгенерированные в следствии выполнения определённой инструкции на машинном языке в самой нити, или сигналы, направленные определённой нити с помощью pthread_kill(3)). Направленный процессу сигнал может быть доставлен в любую из нитей, у которых сигнал не заблокирован. Если имеется несколько таких нитей, то ядро выбирает произвольную нить, которой и доставит сигнал.
Нить может получить набор сигналов, которые находятся в состоянии ожидания с помощью вызова sigpending(2). Этот набор будет состоять из объединения набора ожидающих сигналов, направленных процессу, и набора ожидающих сигналов для вызвавшей нити.
Потомок, созданный с помощью fork(2), первоначально имеет пустой набор ожидающих сигналов; набор ожидающих сигналов сохраняется при вызове execve(2).
Linux поддерживает стандартные сигналы, перечисленные далее. Во второй колонке таблицы указан стандарт (если есть), которым введён сигнал, например, «P1990» — сигнал описан в первоначальной версии стандарта POSIX.1-1990; «P2001» — сигнал добавлен в SUSv2 и POSIX.1-2001.
Сигнал | Стандарт | Действие | Комментарий |
SIGABRT | P1990 | Core | Сигнал аварии (abort), посланный abort(3) |
SIGALRM | P1990 | Term | Сигнал таймера, посланный alarm(2) |
SIGBUS | P2001 | Core | Ошибка шины (некорректный адрес доступа) |
SIGCHLD | P1990 | Ign | Потомок остановлен или завершился |
SIGCLD | - | Ign | Синоним SIGCHLD |
SIGCONT | P1990 | Cont | Продолжить, если остановлен |
SIGEMT | - | Term | Ловушка эмулятора |
SIGFPE | P1990 | Core | Ошибка операций с плавающей запятой |
SIGHUP | P1990 | Term | Обнаружен обрыв связи с управляющим |
терминалом, либо завершение управляющего терминалом процесса | |||
SIGILL | P1990 | Core | Недопустимая инструкция |
SIGINFO | - | Синоним SIGPWR | |
SIGINT | P1990 | Term | Прерывание с клавиатуры |
SIGIO | - | Term | Теперь возможен ввод/вывод (4.2BSD) |
SIGIOT | - | Core | Ловушка IOT. Синоним SIGABRT |
SIGKILL | P1990 | Term | Kill-сигнал |
SIGLOST | - | Term | Утрачена блокировка файла (не используется) |
SIGPIPE | P1990 | Term | Обрыв канала: запись в канал без |
читателей; смотрите pipe(7) | |||
SIGPOLL | P2001 | Term | Опрашиваемое событие (Sys V) |
Синоним SIGIO | |||
SIGPROF | P2001 | Term | Время профилирования истекло |
SIGPWR | - | Term | Отказ питания (System V) |
SIGQUIT | P1990 | Core | Выход с клавиатуры |
SIGSEGV | P1990 | Core | Некорректная ссылка в память |
SIGSTKFLT | - | Term | Ошибка стека на сопроцессоре (не используется) |
SIGSTOP | P1990 | Stop | Остановить процесс |
SIGTSTP | P1990 | Stop | Останов введён с терминала |
SIGSYS | P2001 | Core | Неправильный системный вызов (SVr4); |
смотрите также seccomp(2) | |||
SIGTERM | P1990 | Term | Сигнал завершения |
SIGTRAP | P2001 | Core | Прерывание из-за трассировки/останова |
SIGTTIN | P1990 | Stop | Ввод с терминала для фонового процесса |
SIGTTOU | P1990 | Stop | Вывод с терминала для фонового процесса |
SIGUNUSED | - | Core | Синоним SIGSYS |
SIGURG | P2001 | Ign | Требующее внимание условие сокета (4.2BSD) |
SIGUSR1 | P1990 | Term | Определяемый пользователем сигнал 1 |
SIGUSR2 | P1990 | Term | Определяемый пользователем сигнал 2 |
SIGVTALRM | P2001 | Term | Виртуальный будильник (4.2BSD) |
SIGXCPU | P2001 | Core | Превышен предел процессорного времени (4.2BSD); |
смотрите setrlimit(2) | |||
SIGXFSZ | P2001 | Core | Превышен предел размера файла (4.2BSD); |
смотрите setrlimit(2) | |||
SIGWINCH | - | Ign | Сигнал изменения размера окна (4.3BSD, Sun) |
Сигналы SIGKILL и SIGSTOP нельзя поймать, заблокировать или проигнорировать.
В Linux до версии 2.2 включительно поведением по умолчанию для сигналов SIGSYS, SIGXCPU, SIGXFSZ и SIGBUS (на всех архитектурах кроме SPARC и MIPS) было завершение процесса без создания дампа (в некоторых системах UNIX действием по умолчанию для SIGXCPU и SIGXFSZ является завершение процесса без создания дампа). Linux версии 2.4 соответствует требованиям POSIX.1-2001 для этих сигналов и завершает процесс с созданием дампа.
Сигнал SIGEMT не определён в POSIX.1-2001, но, тем не менее, появляется почти во всех системах UNIX, где действием по умолчанию для него является завершение процесса с созданием дампа.
Сигнал SIGPWR (не определён в POSIX.1-2001) по умолчанию, обычно, игнорируется (в других системах UNIX).
Для сигнала SIGIO (не определён в POSIX.1-2001) в других системах UNIX действием по умолчанию является игнорирование.
Числовое значение каждого сигнала показано в таблице ниже. У многих сигналов номера различаются на разных архитектурах. Первое числовое значение в каждой строке таблицы описывает номер сигнала на x86, ARM и большинстве других архитектур; второе значение для Alpha и SPARC, третье для MIPS, последнее для PARISC. Символ минус (-) означает, что сигнал отсутствует в соответствующей архитектуре.
Сигнал | x86/ARM | Alpha/ | MIPS | PARISC | Примечания |
большинство других | SPARC | ||||
SIGHUP | 1 | 1 | 1 | 1 | |
SIGINT | 2 | 2 | 2 | 2 | |
SIGQUIT | 3 | 3 | 3 | 3 | |
SIGILL | 4 | 4 | 4 | 4 | |
SIGTRAP | 5 | 5 | 5 | 5 | |
SIGABRT | 6 | 6 | 6 | 6 | |
SIGIOT | 6 | 6 | 6 | 6 | |
SIGBUS | 7 | 10 | 10 | 10 | |
SIGEMT | - | 7 | 7 | - | |
SIGFPE | 8 | 8 | 8 | 8 | |
SIGKILL | 9 | 9 | 9 | 9 | |
SIGUSR1 | 10 | 30 | 16 | 16 | |
SIGSEGV | 11 | 11 | 11 | 11 | |
SIGUSR2 | 12 | 31 | 17 | 17 | |
SIGPIPE | 13 | 13 | 13 | 13 | |
SIGALRM | 14 | 14 | 14 | 14 | |
SIGTERM | 15 | 15 | 15 | 15 | |
SIGSTKFLT | 16 | - | - | 7 | |
SIGCHLD | 17 | 20 | 18 | 18 | |
SIGCLD | - | - | 18 | - | |
SIGCONT | 18 | 19 | 25 | 26 | |
SIGSTOP | 19 | 17 | 23 | 24 | |
SIGTSTP | 20 | 18 | 24 | 25 | |
SIGTTIN | 21 | 21 | 26 | 27 | |
SIGTTOU | 22 | 22 | 27 | 28 | |
SIGURG | 23 | 16 | 21 | 29 | |
SIGXCPU | 24 | 24 | 30 | 12 | |
SIGXFSZ | 25 | 25 | 31 | 30 | |
SIGVTALRM | 26 | 26 | 28 | 20 | |
SIGPROF | 27 | 27 | 29 | 21 | |
SIGWINCH | 28 | 28 | 20 | 23 | |
SIGIO | 29 | 23 | 22 | 22 | |
SIGPOLL | Тот же, что SIGIO | ||||
SIGPWR | 30 | 29/- | 19 | 19 | |
SIGINFO | - | 29/- | - | - | |
SIGLOST | - | -/29 | - | - | |
SIGSYS | 31 | 12 | 12 | 31 | |
SIGUNUSED | 31 | - | - | 31 |
Также заметим следующее:
Начиная с версии 2.2, Linux поддерживает сигналы реального времени согласно первоначальному описанию расширений реального времени в POSIX.1b (теперь включено в POSIX.1-2001). Диапазон поддерживаемых сигналов реального времени определяется макросами SIGRTMIN и SIGRTMAX. Согласно POSIX.1-2001 требуется, чтобы реализация поддерживала не менее _POSIX_RTSIG_MAX (8) сигналов реального времени.
Ядро Linux поддерживает 33 таких сигнала, начиная с номера 32 до номера 64. Однако внутри реализации нитей POSIX в glibc используется два (для NPTL) или три (для LinuxThreads) сигнала реального времени (смотрите pthreads(7)), а значение SIGRTMIN корректируется должным образом (до 34 или 35). Так как диапазон доступных сигналов реального времени различается в зависимости от реализации нитей в glibc (и это может происходить во время выполнения при смене ядра и glibc), и, более того, диапазон сигналов реального времени различен в разных системах UNIX, то программы никогда не должны задавать сигналы реального времени по номерам, а вместо этого всегда должны записывать их в виде SIGRTMIN+n и выполнять проверку (во время выполнения), что SIGRTMIN+n не превышает SIGRTMAX.
В отличие от стандартных сигналов, сигналы реального времени не имеют предопределенного назначения: весь набор сигналов реального времени приложения могут использовать так, как им нужно.
Действием по умолчанию для необработанных сигналов реального времени является завершение процесса (terminate).
Сигналы реального времени отличаются от обычных в следующем:
Если процессу передан и стандартный сигнал, и сигнал реального времени, то в POSIX однозначно не определено, какой из них будет доставлен первым. В Linux, как и во многих других реализациях в таких случаях, отдан приоритет стандартным сигналам.
В соответствии с POSIX, реализация должна позволять ставить в очередь процесса, как минимум, _POSIX_SIGQUEUE_MAX (32) сигнала реального времени. Однако в Linux это делается по-другому. В ядрах до версии 2.6.7 включительно, Linux накладывает общесистемный лимит на количество сигналов режима реального времени в очереди для всех процессов. Этот лимит может быть получен и изменён (если есть права) через файл /proc/sys/kernel/rtsig-max. Текущее количество сигналов режима реального времени в очереди можно получить из файла /proc/sys/kernel/rtsig-nr. В Linux 2.6.8 данные интерфейсы /proc были заменены на ограничение ресурса RLIMIT_SIGPENDING, которое устанавливает ограничение на очередь сигналов на каждого пользователя отдельно; дополнительную информацию можно найти в setrlimit(2).
Для дополнительных сигналов реального времени требуется расширение структуры набора сигналов (sigset_t) с 32 до 64 бит. В связи с этим, различные системные вызовы заменены на новые системные вызов, поддерживающие набор сигналов большего размера. Вот соответствие старых и новых системных вызовов:
Linux версии 2.0 и более ранние | Linux версии 2.2 и новее |
sigaction(2) | rt_sigaction(2) |
sigpending(2) | rt_sigpending(2) |
sigprocmask(2) | rt_sigprocmask(2) |
sigreturn(2) | rt_sigreturn(2) |
sigsuspend(2) | rt_sigsuspend(2) |
sigtimedwait(2) | rt_sigtimedwait(2) |
Если обработчик сигнала вызван во время заблокированного системного вызова или библиотечной функции, то может произойти следующее:
Выбираемое поведение зависит от интерфейса и от того, был ли обработчик сигнала установлен с флагом SA_RESTART (смотрите sigaction(2)). Но в различных системах UNIX есть другие различия; далее описаны подробности для Linux.
Если заблокированный вызов к одному из следующих интерфейсов прерван обработчиком сигнала, то вызов автоматически перезапускается после завершения обработчика сигнала, если задействован флаг SA_RESTART; иначе вызов завершается ошибкой EINTR:
Следующие интерфейсы никогда не перезапускаются после прерывания обработчиком сигнала независимо от наличия SA_RESTART; они всегда завершаются с ошибкой EINTR, если прерываются обработчиком сигнала:
Функция sleep(3) также никогда не перезапускается, если прервана обработчиком сигнала, но сообщает об успешном выполнении: возвращает количество оставшиеся для сна секунд.
В Linux, даже в отсутствии обработчиков сигнала, некоторые блокирующие интерфейсы могут завершаться с ошибкой EINTR, если процесс останавливается одним из сигналов останова и затем возобновляет работу при получении сигнала SIGCONT. Такое поведение не предусмотрено POSIX.1 и в других системах отсутствует.
Интерфейсы Linux, к которым это относится:
POSIX.1, кроме описанных исключений.
Описание безопасных асинхронных функций при работе с сигналами смотрите в signal-safety(7).
kill(1), clone(2), getrlimit(2), kill(2), restart_syscall(2), rt_sigqueueinfo(2), setitimer(2), setrlimit(2), sgetmask(2), sigaction(2), sigaltstack(2), signal(2), signalfd(2), sigpending(2), sigprocmask(2), sigreturn(2), sigsuspend(2), sigwaitinfo(2), abort(3), bsd_signal(3), killpg(3), longjmp(3), pthread_sigqueue(3), raise(3), sigqueue(3), sigset(3), sigsetops(3), sigvec(3), sigwait(3), strsignal(3), sysv_signal(3), core(5), proc(5), nptl(7), pthreads(7), sigevent(7)
2019-03-06 | Linux |