Сигналы

Сигнал - это программное средство, с помощью которого может быть прервано функционирование процесса ОС UNIX. Сигналы сообщают процессам о возникновении асинхронных событий. Механизм сигналов позволяет процессам реагировать на различные события, которые могут происходить в ходе работы процесса внутри него самого или во внешней среде.

Сигналы описаны в файле <signal.h>, каждому из них ставится в соответствие мнемоническое обозначение. Количество и семантика сигналов зависят от версии ОС UNIX.

В UNIX System V сигналы имеют номера от 1 до 19:

#define NSIG 20

#define SIGHUP 1 /* разрыв связи */

#define SIGINT 2 /* прерывание */

#define SIGQUIT 3 /* аварийный выход */

#define SIGILL 4 /* неверная машинная инструкция */

#define SIGTRAP 5 /* прерывание-ловушка */

#define SIGIOT 6 /* прерывание ввода-вывода */

#define SIGEMT 7 /* программное прерывание EMT */

#define SIGFPE 8 /* авария при выполнении операции с

/* плавающей точкой */

#define SIGKILL 9 /* уничтожение процесса */

#define SIGBUS 10 /* ошибка шины */

#define SIGSEGV 11 /* нарушение сегментации */

#define SIGSYS 12 /* ошибка выполнения системного вызова */

#define SIGPIPE 13 /* запись в канал есть, чтения нет */

#define SIGALRM 14 /* прерывание от таймера */

#define SIGTERM 15 /* программ. сигнал завершения от kill */

#define SIGUSR1 16 /* определяется пользователем */

#define SIGUSR2 17 /* определяется пользователем */

#define SIGCLD 18 /* процесс-потомок завершился */

#define SIGPWR 19 /* авария питания */

#define SIG_DFL (int(*)())0 /* все установки “по умолчанию” */

#define SIG_IGN (int(*)())1 /* игнорировать этот сигнал */

В BSD UNIX сигналов больше и описываются они следующим образом:

#define SIGHUP 1 /* разрыв связи */

#define SIGINT 2 /* прерывание */

#define SIGQUIT 3 /* аварийный выход */

#define SIGILL 4 /* неверная машинная инструкция */

#define SIGTRAP 5 /* прерывание-ловушка */

#define SIGIOT 6 /* прерывание ввода-вывода */

#define SIGABRT 6 /* используется как ABORT */

#define SIGEMT 7 /* программное прерывание EMT */

#define SIGFPE 8 /* авария при выполнении операции с плав. точкой */

#define SIGKILL 9 /* уничтожение процесса (не может быть

перехвачен или проигнорирован */

#define SIGBUS 10 /* ошибка шины */

#define SIGSEGV 11 /* нарушение сегментации */

#define SIGSYS 12 /* неправильный аргумент системного вызова */

#define SIGPIPE 13 /* запись в канал есть, чтения нет */

#define SIGALRM 14 /* прерывание от таймера */

#define SIGTERM 15 /* программ. сигнал завершения от kill */

#define SIGUSR1 16 /* определяется пользователем */

#define SIGUSR2 17 /* определяется пользователем */

#define SIGCLD 18 /* изменение статуса потомка

(завершение процесса-потомка) */

#define SIGCHLD 18 /* альтернатива для SIGCLD (POSIX) */

#define SIGPWR 19 /* авария питания */

#define SIGWINCH 20 /* изменение размера окна */

#define SIGURG 21 /* urgent socket condition */

#define SIGPOLL 22 /* pollable event occured */

#define SIGIO SIGPOLL /* socket I/O possible (SIGPOLL alias) */

#define SIGSTOP 23 /* стоп (не может быть перехвачен или проигнорирован)*/

#define SIGTSTP 24 /* требование остановки от терминала */

#define SIGCONT 25 /* остановить процесс с возможностью продолжения */

#define SIGTTIN 26 /* скрытая попытка чтения с терминала */

#define SIGTTOU 27 /* скрытая попытка записи на терминал */

#define SIGVTALRM 28 /* виртуальное время истекло */

#define SIGPROF 29 /* время конфигурирования истекло */

#define SIGXCPU 30 /* превышен лимит ЦП */

#define SIGXFSZ 31 /* превышен лимит размера файла */

#define SIGWAITING 32 /* process's lwps заблокирован */

#define SIGLWP 33 /* спецсигнал (used by thread library) */

#define SIGFREEZE 34 /* спецсигнал, используемый процессором*/

#define SIGTHAW 35 /* спецсигнал, используемый процессором*/

#define _SIGRTMIN 36 /* первый (с высшим приоритетом)

сигнал реального времени */

#define _SIGRTMAX 43 /* последний (с низшим приоритетом)

сигнал реального времени */

#define SIG_DFL (void(*)())0 /* все установки “по умолчанию” */

#define SIG_IGN (void(*)())0 /* игнорировать этот сигнал */

Примечание: причины возникновения сигналов для различных версий могут отличаться; первоначально они были обусловлены архитектурными особенностями ЭВМ PDP-11.

2.1. Причины возникновения сигналов

В версии System V UNIX возникновение сигналов можно классифицировать следующим образом:

  • введение пользователем управляющего символа с терминала всем процессам, ассоциированным с данным терминалом (SIGINT, SIGQUIT, SIGHUP);
  • возникновение аварийной ситуации при функционировании пользовательского процесса (SIGILL, SIGTRAP, SIGFPE, SIGBUS, SIGSEGV, SIGSYS, SIGPIPE);
  • возникновение непредусмотренного или не поддающегося идентификации события (SIGTERM, SIGCLD, SIGPWR);
  • возникновение некоторого заранее описанного события (SIGALRM).

Посылка сигналов производится процессами - друг другу, с помощью функции kill, - или ядром. Для каждого процесса определен бинарный вектор, длина которого равна количеству сигналов в системе. При получении процессом сигнала I соответствующий i-й разряд этого вектора становится равным 1. Каждому сигналу соответствует адрес функции, которая будет вызвана для обработки данного сигнала.

2.2. Обработка сигналов

Ядро обрабатывает сигналы в контексте того процесса, который получает их, поэтому чтобы обработать сигналы, нужно запустить процесс.

Существует три способа обработки сигналов:

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

Реакцией по умолчанию со стороны процесса, исполняемого в режиме ядра, обычно является вызов функции exit (), т.е. завершение процесса. Но вместе с тем реакция процесса на принимаемый сигнал зависит от того, как сам процесс определил свое поведение в случае приема данного сигнала: процесс может проигнорировать сигнал, вызвать на выполнение другой процесс и т.д. При этом способ обработки сигналов одного типа не влияет на обработку сигналов других типов.

Обрабатывая сигнал, ядро определяет тип сигнала и очищает (гасит) разряд в записи таблицы процессов, соответствующий данному типу сигнала и установленный в момент получения сигнала процессом. Таким образом, когда процесс получает любой неигнорируемый им сигнал (за исключением SIGILL и SIGTRAP), ОС UNIX автоматически восстанавливает реакцию “по умолчанию” на всякое последующее получение этого сигнала.

Замечание 1: Если необходима многократная обработка одного и того же сигнала, процесс должен каждый раз осуществлять системный вызов signal для установления требуемой реакции на данный сигнал.

Замечание 2: Процесс не в состоянии узнать, сколько однотипных сигналов им было получено. В том случае, если процесс не успевает обработать все поступившие сигналы, происходит потеря информации.

Если функции обработки сигнала присвоено значение по умолчанию, ядро в отдельных случаях перед завершением процесса сбрасывает на внешний носитель (дампирует) образ процесса в памяти. Дампирование удобно для программистов тем, что позволяет установить причину завершения процесса и посредством этого вести отладку программ. Ядро дампирует состояние памяти при поступлении сигналов, которые сообщают о каких-нибудь ошибках в выполнении процессов, как например, попытка исполнения запрещенной команды или обращение к адресу, находящемуся за пределами виртуального адресного пространства процесса. Ядро не дампирует состояние памяти, если сигнал не связан с программной ошибкой, за исключением внешнего сигнала о выходе (quit), обычно вызываемого одновременным нажатием клавиш Ctrl+|.

Если процесс получает сигнал SIGINT, который было решено игнорировать (signal(SIGINT,SIG_IGN)), выполнение процесса продолжается так, словно сигнала и не было. Поскольку ядро не сбрасывает значение соответствующего поля, свидетельствующего о необходимости игнорирования сигнала данного типа, то когда сигнал поступит вновь, процесс опять не обратит на него внимание.

В том случае, если процесс получает сигнал, реагирование на который установлено системным вызовом signal, сразу по возвращении процесса в режим задачи выполняется заранее условленное действие, описанное в вызове signal. После выполнения функции обработки сигнала управление будет передано на то место в программе пользователя, где было произведено обращение к системной функции или произошло прерывание.

Если во время исполнения системной функции приходит сигнал, а процесс приостановлен с допускающим прерывания приоритетом, этот сигнал побуждает процесс выйти из приостанова, вернуться в режим задачи и вызвать функцию обработки сигнала. Когда функция обработки сигнала завершается, процесс выходит из системной функции с ошибкой, сообщающей о прерывании ее выполнения. После этого пользователь может запустить системную функцию повторно.

2.3. Группы процессов

Несмотря на то, что в системе UNIX процессы идентифицируются уникальным кодом (PID), системе иногда приходится использовать для идентификации процессов номер “группы”, в которую они входят. Например, процессы, имеющие общего предка в лице регистрационного интерпретатора shell, взаимосвязаны, и поэтому когда пользователь нажимает клавиши “ delete ” или “ break ”, или когда терминальная линия “зависает”, все эти процессы получают соответствующие сигналы. Ядро использует код группы процессов для идентификации группы взаимосвязанных процессов, которые при наступлении определенных событий должны получать общий сигнал. Код группы запоминается в таблице процессов. При выполнении функции fork процесс-потомок наследует код группы своего родителя.

Для того, чтобы образовать новую группу процессов, следует воспользоваться системной функцией setpgrp:

grp = setpgrp()

где grp - новый код группы процессов, равный его коду идентификации процесса, осуществившего вызов setpgrp ().


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: