Книга: UNIX: разработка сетевых приложений
Функция signal
Разделы на этой странице:
Функция signal
Согласно POSIX, чтобы определить действие для сигнала, нужно вызвать функцию sigaction
. Однако это достаточно сложно, поскольку один аргумент этой функции — это структура, для которой необходимо выделение памяти и заполнение. Поэтому проще задать действие сигнала с помощью функции signal
. Первый ее аргумент — это имя сигнала, а второй — либо указатель на функцию, либо одна из констант SIG_IGN
и SIG_DFL
. Но функция signal
существовала еще до появления POSIX.1, и ее различные реализации имеют разную семантику сигналов с целью обеспечения обратной совместимости. В то же время POSIX четко диктует семантику при вызове функции sigaction
. Это обеспечивает простой интерфейс с соблюдением семантики POSIX. Мы включили эту функцию в нашу собственную библиотеку вместе функциями err_XXX
и функциями-обертками, которые мы используем для построения всех наших программ. Она представлена в листинге 5.5. Функция-обертка Signal
здесь не показана, потому что ее вид не зависит от того, какую именно функцию signal
она должна вызывать.
Листинг 5.5. Функция signal, вызывающая функцию POSIX sigaction
//lib/signal.c
1 #include "unp.h"
2 Sigfunc*
3 signal(int signo, Sigfunc *func)
4 {
5 struct sigaction act, oact;
6 act.sa_handler = func;
7 sigemptyset(&act.sa_mask);
8 act.sa_flags = 0;
9 if (signo == SIGALRM) {
10 #ifdef SA_INTERRUPT
11 act.sa_flags |= SA_INTERRUPT; /* SunOS 4.x */
12 #endif
13 } else {
14 #ifdef SA_RESTART
15 act.sa_flags |= SA_RESTART; /* SVR4, 44BSD */
16 #endif
17 }
18 if (sigaction(signo, &act, &oact) < 0)
19 return (SIG_ERR);
20 return (oact.sa_handler);
21 }
Упрощение прототипа функции при использовании typedef
2-3
Обычный прототип для функции signal
усложняется наличием вложенных скобок:
void (*signal(int signo, void (*func)(int)))(int);
Чтобы упростить эту запись, мы определяем тип Sigfunc
в нашем заголовочном файле unp.h
следующим образом:
typedef void Sigfunc(int);
указывая тем самым, что обработчики сигналов — это функции с целочисленным аргументом, ничего не возвращающие (void
). Тогда прототип функции выглядит следующим образом:
Sigfunc *signal(int signo, Sigfunc *func);
Указатель на функцию, являющуюся обработчиком сигнала, — это второй аргумент функции и в то же время возвращаемое функцией значение.
Установка обработчика
6
Элемент sa_handler
структуры sigaction
устанавливается равным аргументу func
функции signal
.
Установка маски сигнала для обработчика
7
POSIX позволяет нам задавать набор сигналов, которые будут блокированы при вызове обработчика сигналов. Любой блокируемый сигнал не может быть доставлен процессу. Мы устанавливаем элемент sa_mask
равным пустому набору. Это означает, что во время работы обработчика дополнительные сигналы не блокируются. POSIX гарантирует, что перехватываемый сигнал всегда блокирован, пока выполняется его обработчик.
Установка флага SA_RESTART
8-17
Флаг SA_RESTART
не является обязательным, и если он установлен, то системный вызов, прерываемый этим сигналом, будет автоматически снова выполнен ядром. (В продолжении нашего примера мы более подробно поговорим о прерванных системных вызовах.) Если перехватываемый сигнал не является сигналом SIGALRM
, мы задаем флаг SA_RESTART
, если таковой определен. (Причина, по которой сигнал SIGALRM
обрабатывается отдельно, состоит в том, что обычно цель его генерации - ввести ограничение по времени в операцию ввода-вывода, как показано в листинге 14.2. В этом случае мы хотим, чтобы блокированный системный вызов был прерван сигналом.) Более ранние системы, особенно SunOS 4.x, автоматически перезапускают прерванный системный вызов по умолчанию и затем определяют флаг SA_INTERRUPT
. Если этот флаг задан, мы устанавливаем его при перехвате сигнала SIGALRM
.
Вызов функции sigaction
18-20
Мы вызываем функцию sigaction
, а затем возвращаем старое действие сигнала как результат функции signal
.
В книге мы везде используем функцию signal
из листинга 5.5.
- 10.3. Стандартные сигналы С: signal() и raise()
- 10.3.1. Функция signal()
- Функция sem_wait
- Функция signal_rt
- 10.6.4. Перехват сигналов: sigaction()
- Сигналы
- 10.3.2. Программная отправка сигналов: raise()
- 10.4.2. BSD и GNU
- Надежные сигналы
- Состояния дежурного ожидания
- Приложение В Таблица сигналов
- Ждущие блокировки