- Linux signals
- Description
- Finding system-specific signals
- Signals in Linux
- Signals not supported by Linux
- Sending signals from the keyboard
- Real-time signals
- Examples: sending signals
- Related commands
- Практика работы с сигналами
- Функция обработчик сигналов
- Блокирование сигналов
- sigwait
- Посыл сигнала
- Пример использования сигналов
Linux signals
On Unix-like operating systems such as Linux, signals are software interrupts. They provide a way for the user (or a process) to directly communicate with a process.
Software may be programmed to respond intelligently to a wide array of signals, and certain signals cause processes to behave in a standardized, predefined way at the kernel level.
Description
Process signals were developed as part of UNIX in the 1970s. They are used on all modern Unix-like operating systems, including Linux, BSD, and macOS X.
When a signal is sent to a process, the operating system interrupts the normal flow of the process execution and delivers the notification. If the process has previously registered a way to handle that particular signal, that routine is executed, otherwise the system executes the default signal handler.
Signals can be sent with the kill command, which is named for its default signal (SIGKILL) that instructs the OS to forcefully terminate a process before doing anything else.
Signal names are commonly abbreviated without their SIG prefix, e.g., «KILL», including in the command arguments of kill.
Finding system-specific signals
Signals are defined in the system library signal.h. To view the signals used by your operating system, open a terminal and run man signal or man 7 signal.
Signals in Linux
Signal | Number | Description | Standard |
---|---|---|---|
SIGHUP | 1 | The HUP signal is sent to a process when its controlling terminal is closed. It was originally designed to notify a serial line drop (HUP stands for «Hang Up»). In modern systems, this signal usually indicates the controlling pseudo or virtual terminal is closed. | POSIX |
SIGINT | 2 | The INT signal is sent to a process by its controlling terminal when a user wants to interrupt the process. This signal is often initiated by pressing Ctrl + C , but on some systems, the «delete» character or «break» key can be used. | ANSI |
SIGQUIT | 3 | The QUIT signal is sent to a process by its controlling terminal when the user requests that the process perform a core dump. | POSIX |
SIGILL | 4 | Illegal instruction. The ILL signal is sent to a process when it attempts to execute a malformed, unknown, or privileged instruction. | ANSI |
SIGTRAP | 5 | Trace trap. The TRAP signal is sent to a process when a condition arises that a debugger is tracing — for example, when a particular function is executed, or when a particular variable changes value. | POSIX |
SIGABRT, SIGIOT | 6 | Abort process. ABRT is usually sent by the process itself, when it calls the abort() system call to signal an abnormal termination, but it can be sent from any process like any other signal. SIGIOT is a synonym for SIGABRT. (IOT stands for input/output trap, a signal which originated on the PDP-11.) | 4.2 BSD |
SIGBUS | 7 | The BUS signal is sent to a process when it causes a bus error, such as an incorrect memory access alignment or non-existent physical address. In Linux, this signal maps to SIGUNUSED, because memory access errors of this kind are not possible. | 4.2 BSD |
SIGFPE | 8 | Floating point exception. The FPE signal is sent to a process when it executes erroneous arithmetic operations, such as division by zero. | ANSI |
SIGKILL | 9 | Forcefully terminate a process. With STOP, this is one of two signals which cannot be intercepted, ignored, or handled by the process itself. | POSIX |
SIGUSR1 | 10 | User-defined signal 1. This is one of two signals designated for custom user signal handling. | POSIX |
SIGSEGV | 11 | The SEGV signal is sent to a process when it makes an invalid virtual memory reference, or segmentation fault, i.e., when it performs a segmentation violation. | |
SIGUSR2 | 12 | User-defined signal 2. This is one of two signals designated for custom user signal handling. | POSIX |
SIGPIPE | 13 | The PIPE signal is sent to a process when it attempts to write to a pipe without a process connected to the other end. | POSIX |
SIGALRM | 14 | The ALRM signal notifies a process that the time interval specified in a call to the alarm() system function has expired. | POSIX |
SIGTERM | 15 | The TERM signal is sent to a process to request its termination. Unlike the KILL signal, it can be caught and interpreted or ignored by the process. This signal allows the process to perform nice termination releasing resources and saving state if appropriate. It should be noted that SIGINT is nearly identical to SIGTERM. | ANSI |
SIGSTKFLT | 16 | Stack fault. Maps to SIGUNUSED in Linux. | |
SIGCHLD | 17 | The CHLD signal is sent to a process when a child process terminates, is interrupted, or resumes after being interrupted. One common usage of the signal is to instruct the operating system to clean up the resources used by a child process after its termination without an explicit call to the wait system call. | POSIX |
SIGCONT | 18 | Continue executing after stopped, e.g., by STOP | POSIX |
SIGSTOP | 19 | The STOP signal instructs the operating system to stop a process for later resumption. This is one of two signals, along with KILL that cannot be intercepted, ignored, or handled by the process itself. | POSIX |
SIGTSTP | 20 | The TSTP signal is sent to a process by its controlling terminal to request it to stop temporarily. It is commonly initiated by the user pressing Ctrl + Z . Unlike SIGSTOP, this process can register a signal handler for or ignore the signal. | POSIX |
SIGTTIN | 21 | The TTIN signal is sent to a process when it attempts to read from the tty while in the background. This signal can be received only by processes under job control. Daemons do not have controlling terminals and should never receive this signal. | POSIX |
SIGTTOU | 22 | TTOU signal is sent to a process when it attempts to write from the tty while in the background. The compliment to TTIN. | POSIX |
SIGURG | 23 | The URG signal is sent to a process when a socket has urgent or out-of-band data available to read. | 4.2 BSD |
SIGXCPU | 24 | The XCPU signal is sent to a process when it has used up the CPU for a duration that exceeds a certain predetermined user-settable value. The arrival of an XCPU signal provides the receiving process a chance to quickly save any intermediate results and to exit gracefully, before it is terminated by the operating system using the SIGKILL signal. | 4.2 BSD |
SIGXFSZ | 25 | The XFSZ signal is sent to a process when it grows a file larger than the maximum allowed size. | 4.2 BSD |
SIGVTALRM | 26 | Virtual alarm clock. May be sent by the alarm() system call. By default, this signal kills the process, but it’s intended for use with process-specific signal handling. | 4.2 BSD |
SIGPROF | 27 | Profiling alarm clock. Indicates expiration of a timer that measures CPU time used by the current process («user» time), and CPU time expended on behalf of the process by the system («system» time). These times may be used to implement code profiling facilities. By default, this signal terminates the process, but it’s intended for use with process-specific signal handling. | 4.2 BSD |
SIGWINCH | 28 | Window change. The WINCH signal is sent to a process when its controlling terminal changes size, for instance if you resize it in your window manager. | 4.3 BSD, Sun |
SIGIO, SIGPOLL | 29 | Input/output is now possible. SIGPOLL is a synonym for SIGIO, and in Linux its behavior is identical to SIGURG. | 4.2 BSD |
SIGPWR, SIGLOST | 30 | Power failure. The PWR signal is sent to a process when the system detects a power failure. SIGLOST is a synonym for SIGPWR. | System V |
SIGUNUSED, SIGSYS | 31 | Unused signal. This signal is provided for compatibility reasons, for example when porting software from an operating system with different or unsupported signals in Linux. In Linux, SIGSYS is a synonym for SIGUNUSED. | System V r4 |
Signals not supported by Linux
The following signals may be used by other systems, such as BSD, but are interpreted as SIGUNUSED in Linux.
SIGEMT | The EMT signal is sent to a process when an emulator trap occurs. Unused in Linux. |
SIGINFO | The INFO signal is sent to a process when a status request is received from the controlling terminal. Unused in Linux |
SIGLOST | The LOST signal is sent to a process when a file lock is lost. Unused in Linux. |
SIGSYS | The SYS signal is sent to a process when it passes a bad argument to a system call. Unused in Linux. |
Sending signals from the keyboard
Signals may be sent from the keyboard. Several standard defaults are listed below. Default key combinations for sending interrupt signals can be defined with the stty command.
Ctrl-C | Send SIGINT (Interrupt). By default, this causes a process to terminate. |
Ctrl-Z | Send SIGTSTP (Suspend). By default, this causes a process to suspend all operation. |
Ctrl-\ | Send SIGQUIT (Quit). By default, this causes a process to terminate immediately and dump the core. |
Ctrl-T | Send SIGINFO (Info). By default, this causes the operating system to display information about the command. Not supported on all systems. |
Real-time signals
Real-time signals are a set of signals with no predefined purpose, for programmers to use as they want in their software. Two signal names, SIGRTMIN and SIGRTMAX, define the minimum and maximum signal numbers of the real-time signals. For example, the programmer may use the signal number as SIGRTMIN+3 to refer to the fourth real-time signal number.
Examples: sending signals
The kill command sends signals to processes. Your shell may have a built-in version of kill, which supersedes the version installed at /bin/kill. The two versions have slightly different options, but basic functions are the same. The following examples may run using either version of kill.
The process to be signaled is referred to by PID (process ID). If you’re not sure of the process ID, you can find it with the ps command, for example ps -aux.
Send the KILL signal to the process with PID 1234.
Kill three processes: PIDs 123, 456, and 789.
Send signal number 15 (TERM) to processes 1234 and 5678.
Same as the previous command.
List all available signals. Example output:
The special process ID -1 refers to all processes other than kill and the system root process. This command attempts to kill (-9) every possible process (-1) on the system. For more information, see the documentation of kill, linked below.
Related commands
kill — End a process.
stty — Change terminal line settings.
Источник
Практика работы с сигналами
Хочу запечатлеть небольшой опыт работы с сигналами в Linux. Ниже будут представлены примеры использования наиболее значимых конструкций в этой области. Постараюсь разложить все по отдельным полочкам, чтобы всегда было легко глянуть и вспомнить, что и как использовать.
Важные факты о сигналах:
- Сигналы в Linux играют роль некоего средства межпроцессного взаимодействия (а так же и межпоточного)
- Каждый процесс имеет маску сигналов (сигналов, получение которых он игнорирует)
- Каждая нить (thread), так же как и процесс, имеет свою маску сигналов
- При получении сигнала(если он не блокируется) процесс/нить прерывается, управление передается в функцию обработчик сигнала, и если эта функция не приводит к завершению процесса/нити, то управление передается в точку на которой процесс/нить была прервана
- Можно установить свою функцию обработчик сигнала, но только для процесса. Данный обработчик будет вызываться и для каждой нити порожденной из этого процесса
Я не буду углубляться в теорию сигналов, что откуда зачем и куда. Меня в первую очередь интересует сам механизм работы с ними. Поэтому в качестве используемых сигналов будут выступать SIGUSR1 и SIGUSR2, это два единственных сигнала отданных в полное распоряжение пользователя. А так же я постараюсь уделить больше внимание именно межпоточному взаимодействию сигналов.
Итак, поехали.
Функция обработчик сигналов
Данная функция вызывается, когда процесс (или нить) получает неблокируемый сигнал. Дефолтный обработчик завершает наш процесс (нить). Но мы можем сами определить обработчики для интересующих нас сигналов. Следует очень осторожно относится к написанию обработчика сигналов, это не просто функция, выполняющаяся по коллбеку, происходит прерывание текущего потока выполнения без какой либо подготовительной работы, таким образом глобальные объекты могут находится в неконсистентном состоянии. Автор не берется приводить свод правил, так как сам их не знает, и призывает последовать совету Kobolog (надеюсь он не против, что я ссылаюсь на него) и изучить хотя бы вот этот материал FAQ.
Установить новый обработчик сигнала можно двумя функциями
Которая принимает номер сигнала, указатель на функцию обработчик (или же SIG_IGN (игнорировать сигнал) или SIG_DFL (дефолтный обработчик)), и возвращает старый обработчик. Сигналы SIGKILL и SIGSTOP не могут быть «перехвачены» или проигнорированы. Использование этой функции крайне не приветствуется, потому что:
- функция не блокирует получение других сигналов пока выполняется текущий обработчик, он будет прерван и начнет выполняться новый обработчик
- после первого получения сигнала (для которого мы установили свой обработчик), его обработчик будет сброшен на SIG_DFL
Этих недостатков лишена функция
Которая также принимает номер сигнала (кроме SIGKILL и SIGSTOP). Второй аргумент это новое описание для сигнала, через третий возвращается старое значение. Структура struct sigaction имеет следующие интересующие нас поля
- sa_handler — аналогичен sighandler_t в функции signal
- sa_mask — маска сигналов который будут блокированы пока выполняется наш обработчик. + по дефолту блокируется и сам полученный сигнал
- sa_flags — позволяет задать дополнительные действия при обработке сигнала о которых лучше почитать тут
Использование данной функции выглядит совсем просто
Здесь мы установили наш обработчик для сигналов SIGUSR1 и SUGUSR2, а также указали, что необходимо блокировать эти же сигналы пока выполняется обработчик.
С обработчиком сигналов есть один не очень удобный момент, он устанавливается на весь процесс и все порожденные нити сразу. Мы не имеет возможность для каждой нити установить свой обработчик сигналов.
Но при этом следует понимать что когда сигнал адресуется процессу, обработчик вызывается именно для главной нити (представляющей процесс). Если же сигнал адресуется для нити, то обработчик вызывается из контекста этой нити. См пример 1.
Блокирование сигналов
Для того, чтобы заблокировать некоторый сигналы для процесса, необходимо добавить их в маску сигналов данного процесса. Для этого используется функция
Мы можем к уже существующей маске сигналов добавить новые сигналы (SIG_BLOCK), можем из этой маски убрать часть сигналов (SIG_UNBLOCK), а так же установить полностью нашу маску сигналов (SIG_SETMASK).
Для работы с маской сигналов внутри нити используется функция
которая позволяет сделать все тоже, но уже для каждой нити в отдельности.
Невозможно заблокировать сигналы SIGKILL или SIGSTOP при помощи этих функций. Попытки это сделать будут игнорироваться.
sigwait
Данная функция позволяет приостановить выполнении процесса (или нити) до получения нужного сигнала (или одного из маски сигналов). Особенностью этой функции является то, что при получении сигнала не будет вызвана функции обработчик сигнала. См. пример 2.
Посыл сигнала
Для того, чтобы послать сигнал процессу можно использовать две функции
С первой все понятно. Вторая нужна для того, чтобы послать сигнал самому себе, и по сути равносильна kill(getpid(), signal). Функция getpid() возвращает PID текущего процесса.
Для того, чтобы послать сигнал отдельной нити, используется функция
Пример использования сигналов
Все, что я описал выше, не дает ответа на вопрос «Зачем мне использовать сигналы». Теперь я хотел бы привести реальный пример использования сигналов и где без них попросту не обойтись.
Представьте, что вы хотите читать или писать какие-то данные в какое то устройство, но это может привести к блокированию. Ну например, чтение в случае работы с сокетами. Или может быть запись в пайп. Вы можете вынести это в отдельный поток, чтобы не блокировать основную работу. Но что делать когда вам нужно завершить приложение? Как корректно прервать блокирующую операцию IO? Можно было бы задавать таймаут, но это не очень хорошее решение. Для этого есть более удобные средства: функции pselect и ppoll. Разница между ними исключительно в юзабельности, поведение у них одинаковое. В первую очередь эти функции нужны для мультиплексирования работы с IO (select/poll). Префикс ‘p’ в начале функции указывает на то, что данная функция может быть корректно прервана сигналом.
Итак, сформулируем требование:
Необходимо разработать приложение, открывающее сокет (для простоты UDP) и выполняющее в потоке операцию чтения. Данное приложение должно корректно без задержек завершаться по требованию пользователя.
Функция треда выглядит вот так
stop это глобальный булев флаг который устанавливается в true нашим обработчиком, что сообщает потоку о необходимости завершиться.
Логика работы такая:
- проверяем, что пока стартовал тред его еще не пожелали завершить
- блокируем завершающий сигнал
- проверяем, что пока блокировали, нас не пожелали завершить
- вызываем ppoll передавая в качестве последнего параметра маску сигналов по которой ждется сигнал
- после выхода из ppoll проверяем что вышли не из за сигнала о завершении
Вот так выглядит главная функция
Устанавливаем наш обработчик для SIGINT, и когда нужно завершить дочерний поток шлем ему этот сигнал.
Полный листинг см. пример 3.
На мой взгляд, недостатком данного способа является то, что в случае нескольких потоков мы можем завершить их только все сразу. Нет возможности устанавливать свой обработчик сигналов для каждого треда. Таким образом, нет возможности реализовать полноценное межпоточное взаимодействие через сигналы. Linux way это не предусматривает.
PS. Исходные коды разместил на сервисе PasteBin (ссылку не даю, а то еще за рекламу посчитают).
PPS. Прошу простить за обилие ошибок. Язык, слабая моя сторона. Спасибо, всем кто помог их исправить.
Данная статья не претендует на полное (и глубокое) описание работы с сигналами и нацелена в первую очередь на тех, кто до этого момента не сталкивались с понятием «сигнал». Для более глубоко понимания работы сигналов автор призывает обратиться в более компетентные источники и ознакомиться с конструктивной критикой в комментариях.
Источник