Источники сигналов: аппаратура, ядро, программист
Откуда берутся сигналы
Любой сигнал можно послать вызовом kill, но у каждого есть типичный источник — событие, ради которого сигнал придуман. Это и спрашивают в задаче 1.
1. Аппаратные исключения
Процессор не смог выполнить инструкцию → исключение → обработчик ядра → сигнал тому потоку, который выполнил инструкцию. Это синхронные сигналы.
| Исключение процессора | Сигнал | Пример |
|---|---|---|
| страничный отказ на недопустимом адресе / нарушение прав | SIGSEGV |
*NULL = 1, запись в .rodata, переполнение стека |
| ошибка шины: невыровненный доступ (на строгих архитектурах), за концом отображённого файла, аппаратная ошибка памяти | SIGBUS |
mmap файла и обращение за его концом |
| деление целого на ноль, переполнение при делении | SIGFPE |
1 / 0, INT_MIN / -1 |
| недопустимая или привилегированная инструкция | SIGILL |
порча кода, инструкция новее процессора |
| точка останова, пошаговое выполнение | SIGTRAP |
работа отладчика |
Почему это «связано с аппаратным событием»
Первоисточник — сам процессор: он обнаружил проблему при выполнении инструкции и сгенерировал исключение. Ядро лишь переводит исключение в сигнал. Для таблицы задачи 1 это SIGBUS и SIGFPE (а также SIGSEGV и SIGILL, если встретятся).
Если такой сигнал заблокирован или игнорируется в момент исключения, Linux всё равно убивает процесс: продолжать выполнение с той же инструкции бессмысленно — исключение повторится.
2. Программные события ядра
Ядро сообщает процессу о событии, не связанном с ошибкой процессора:
| Сигнал | Событие | По умолчанию |
|---|---|---|
SIGCHLD |
потомок завершился, остановился или продолжил работу | Ign |
SIGPIPE |
запись в канал/сокет без читателей | Term |
SIGALRM |
истёк таймер alarm() / setitimer |
Term |
SIGXCPU, SIGXFSZ |
превышен лимит процессорного времени / размера файла | Core |
SIGURG |
срочные данные в сокете | Ign |
SIGIO |
ввод-вывод возможен (асинхронный режим) | Term |
SIGSYS |
недопустимый системный вызов (seccomp) | Core |
SIGKILL |
убийца нехватки памяти (OOM killer) выбрал процесс | Term |
SIGCHLD — самый частый: именно так родитель узнаёт, что пора вызвать wait.
3. Драйвер терминала
Терминал — тоже часть ядра. Он превращает специальные символы и ситуации в сигналы активной группе процессов (или конкретной группе):
| Ситуация | Сигнал | По умолчанию |
|---|---|---|
| Ctrl+C | SIGINT |
Term |
| Ctrl+\ | SIGQUIT |
Core |
| Ctrl+Z | SIGTSTP |
Stop |
| фоновая группа читает терминал | SIGTTIN |
Stop |
фоновая группа пишет (при tostop) или меняет настройки |
SIGTTOU |
Stop |
| терминал закрыт / сеанс потерял терминал | SIGHUP |
Term |
| изменился размер окна | SIGWINCH |
Ign |
Символы настраиваются: stty -a покажет intr = ^C; quit = ^\; susp = ^Z.
4. Явная отправка программистом
Некоторые сигналы существуют только для того, чтобы их посылали программы:
| Сигнал | Как и зачем |
|---|---|
SIGUSR1, SIGUSR2 |
смысл задаёт программа: «перечитать конфигурацию», «переоткрыть журнал» |
SIGABRT |
abort() — аварийное завершение по решению самой программы (так срабатывает неудачный assert) |
SIGTERM |
просьба завершиться: kill pid, init при выключении |
SIGKILL |
безусловное уничтожение: kill -9 pid (также OOM killer ядра) |
SIGSTOP |
безусловная остановка: kill -STOP pid, отладчик |
SIGCONT |
продолжение: kill -CONT pid, shell по командам fg/bg |
SIGRTMIN…SIGRTMAX |
сигналы реального времени: sigqueue(pid, sig, value) с данными |
#include <assert.h>
assert(ptr != NULL); /* если ложно: сообщение и abort() → SIGABRT → core dump */
Итог
- Аппаратные исключения →
SIGSEGV,SIGBUS,SIGFPE,SIGILL,SIGTRAP(синхронно, потоку-виновнику). - Программные события ядра →
SIGCHLD,SIGPIPE,SIGALRM,SIGXCPU,SIGURG. - Драйвер терминала →
SIGINT,SIGQUIT,SIGTSTP,SIGTTIN,SIGTTOU,SIGHUP,SIGWINCH. - По инициативе программиста →
SIGUSR1/2,SIGABRT(черезabort),SIGTERM,SIGKILL,SIGSTOP,SIGCONT, сигналы реального времени.
Практика решено 0 из 5
Какой основной источник у каждого сигнала?
| Аппаратное исключение | Программное событие ядра | Драйвер терминала | Явно программа или пользователь | |
|---|---|---|---|---|
| SIGSEGV | ||||
| SIGFPE | ||||
| SIGBUS | ||||
| SIGCHLD | ||||
| SIGPIPE | ||||
| SIGALRM | ||||
| SIGINT | ||||
| SIGTTIN | ||||
| SIGUSR2 | ||||
| SIGABRT | ||||
| SIGRTMIN |
Что произойдёт с программой? (ответ — имя сигнала)
int a = 1, b = 0;
printf("%d\n", a / b);
Программа отобразила файл размером 100 байт через mmap на 2 страницы и обращается ко второй странице. Какой сигнал она получит?
Когда ядро посылает процессу SIGPIPE?
Когда процесс-родитель получает SIGCHLD?
Войдите, чтобы отмечать пройденные уроки.