Чтение онлайн

на главную - закладки

Жанры

Linux программирование в примерах
Шрифт:

На системе BSD или GNU/Linux обработчик сигнала не должен дополнительно использовать '

signal(signum, handler)
' для переустановки обработчика. Однако, лишний вызов не причиняет никакого вреда, поэтому сохраняется статус-кво.

В действительности, POSIX предоставляет функцию

bsd_signal
, которая идентична
signal
за тем исключением, что она гарантирует, что обработчик сигнала останется установленным:

#include <signal.h> /* XSI, устаревает */

void (*bsd_signal(int sig, void (*func)(int)))(int);

Это устраняет проблемы переносимости. Если вы знаете, что ваша программа будет работать лишь на системах POSIX, вы можете воспользоваться

bsd_signal
вместо
signal
.

Одно предостережение — эта функция также помечена как «устаревающая», что означает возможность отказа от нее в будущем стандарте. На практике, даже если от нее откажутся, поставщики скорее всего долгое время будут ее поддерживать. (Как мы увидим, функция API POSIX

sigaction
предоставляет достаточно возможностей для написания рабочей версии, если это вам нужно.)

10.4.3. Игнорирование сигналов

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

SIGINT
выводили бы сообщение и продолжали работу; смысл сигнала в том, что они должны остановиться!

Например, рассмотрите программу

sort
.
sort
, возможно, создала любое число временных файлов для использования на промежуточных этапах процесса сортировки. По получении
SIGINT
,
sort
должна удалить временные файлы и выйти. Вот упрощенная версия обработчика сигнала из GNU Coreutils
sort.c
:

/* Обработка прерываний и отсоединений. Упрощена для представления */

static void sighandler(int sig) {

 signal(sig, SIG_IGN); /* Отныне этот сигнал игнорировать */

 cleanup; /* Очистка после себя */

 signal(sig, SIG_DFL); /* Восстановление действия по умолчанию */

 raise(sig); /* Повторно отправить сигнал */

}

Установка действия

SIG_IGN
гарантирует, что все последующие появляющиеся сигналы
SIGINT
не повлияют на продолжающийся процесс очистки. Когда функция
cleanup
завершит работу, восстановление действия
SIG_DFL
позволяет системе сделать снимок образа процесса, если это нужно возникшему сигналу. Вызов
raise
восстанавливает сигнал. Затем восстановленный сигнал вызывает действие по умолчанию, которое, скорее всего, завершит программу. (Далее в этой главе мы полностью покажем обработчик сигнала
sort.c
.)

10.4.4. Системные вызовы, допускающие повторный запуск

Значение

EINTR
для
errno
(см. раздел 4.3 «Определение ошибок») указывает, что системный вызов был прерван. Хотя с этим значением ошибки может завершаться большое количество системных вызовов, двумя наиболее значительными являются
read
и
write
. Рассмотрите следующий код:

void handler(int signal) { /* обработка сигналов */ }

int main(int argc, char **argv) {

 signal(SIGINT, handler);

 ...

 while ((count = read(fd, buf, sizeof buf)) > 0) {

/* Обработка буфера */

 }

 if (count == 0)

/* конец файла, очистка и т.п. */

 else if (count == -1)

/* ошибка */

 ...

}

Предположим, что система успешно прочла (и заполнила) часть буфера, когда возник

SIGINT
. Системный вызов
read
еще не вернулся из ядра в программу, но ядро решает, что оно может доставить сигнал. Вызывается
handler
, запускается и возвращается в середину
read
. Что возвратит
read
?

В былые времена (V7, более ранние системы System V)

read
возвратила бы -1 и установила бы
errno
равным
EINTR
. Не было способа сообщить, что данные были переданы. В данном случае V7 и System V действуют, как если бы ничего не случилось: не было перемещений данных в и из буфера пользователя, и смещение файла не было изменено. BSD 4.2 изменила это. Были два случая:

Медленные устройства

«Медленное устройство» является в сущности терминалом или почти всяким другим устройством, кроме обычного файла. В этом случае

read
могла завершиться с ошибкой
EINTR
, лишь если не было передано никаких данных, когда появился сигнал. В противном случае системный вызов был бы запущен повторно, и
read
возвратилась бы нормально.

Обычные файлы

Системный вызов был бы запущен повторно В этом случае

read
вернулась бы нормально; возвращенное значение могло быть либо числом запрошенных байтов, либо числом действительно прочитанных байтов (как в случае чтения вблизи конца файла).

Поведение BSD несомненно полезно; вы всегда можете сказать, сколько данных было прочитано.

Поведение POSIX сходно, но не идентично первоначальному поведению BSD. POSIX указывает, что

read
[108] завершается с ошибкой
EINTR
лишь в случае появления сигнала до начала перемещения данных. Хотя POSIX ничего не говорит о «медленных устройствах», на практике это условие проявляется именно на них.

108

Хотя мы описываем

read
, эти правила применяются ко всем системным вызовам, которые могут завершиться с ошибкой
EINTR
, как, например, семейство функций
wait
Примеч. автора.

В противном случае, если сигнал прерывает частично выполненную

read
, возвращенное значение является числом уже прочитанных байтов. По этой причине (а также для возможности обработки коротких файлов) всегда следует проверять возвращаемое
read
значение и никогда не предполагать, что прочитано все запрошенное количество байтов. (Функция POSIX API
sigaction
, описанная позже, позволяет при желании получить поведение повторно вызываемых системных вызовов BSD.)

10.4.4.1. Пример: GNU Coreutils

safe_read
и
safe_write

Для обработки случая EINTR в традиционных системах GNU Coreutils использует две функции,

safe_read
и
safe_write
. Код несколько запутан из-за того, что один и тот же файл за счет включения #include и макросов реализует обе функции. Из файла
lib/safe-read.c
в дистрибутиве Coreutils:

1 /* Интерфейс read и write для .повторных запусков после прерываний.

Поделиться:
Популярные книги

Атлант расправил плечи. Часть I. Непротивление (др. перевод)

Рэнд Айн
1. Атлант расправил плечи
Фантастика:
социально-философская фантастика
8.48
рейтинг книги
Атлант расправил плечи. Часть I. Непротивление (др. перевод)

"Фантастика 2024-71". Компиляция. Книги 1-29

Бульба Наталья Владимировна
Фантастика 2024. Компиляция
Фантастика:
боевая фантастика
альтернативная история
5.00
рейтинг книги
Фантастика 2024-71. Компиляция. Книги 1-29

Я снова царь. Книга XXXIII

Дрейк Сириус
33. Дорогой барон!
Фантастика:
юмористическое фэнтези
аниме
попаданцы
5.00
рейтинг книги
Я снова царь. Книга XXXIII

"Фантастика 2024-147".Компиляция. Книги 1-28

Погуляй Юрий Александрович
Фантастика 2024. Компиляция
Фантастика:
фэнтези
боевая фантастика
попаданцы
альтернативная история
аниме
5.00
рейтинг книги
Фантастика 2024-147.Компиляция. Книги 1-28

"Фантастика 2023-139". Компиляция. Книги 1-20

Поселягин Владимир Геннадьевич
Фантастика 2023. Компиляция
Фантастика:
фэнтези
героическая фантастика
боевая фантастика
городское фэнтези
попаданцы
аниме
5.00
рейтинг книги
Фантастика 2023-139. Компиляция. Книги 1-20

Я до сих пор не царь. Книга XXVII

Дрейк Сириус
27. Дорогой барон!
Фантастика:
юмористическое фэнтези
аниме
попаданцы
5.00
рейтинг книги
Я до сих пор не царь. Книга XXVII

Корсаков

Кощеев Владимир
1. Корсаков
Фантастика:
альтернативная история
аниме
попаданцы
5.00
рейтинг книги
Корсаков

Собрание сочинений. Том третий

Гашек Ярослав
3. Ярослав Гашек. Собрание сочинений в 6-ти томах
Юмор:
юмористическая проза
5.00
рейтинг книги
Собрание сочинений. Том третий

Аврора Горелика (сборник)

Аксенов Василий Павлович
Поэзия:
драматургия
6.25
рейтинг книги
Аврора Горелика (сборник)

Дважды одаренный. Том II

Тарс Элиан
2. Дважды одаренный
Фантастика:
городское фэнтези
альтернативная история
аниме
5.25
рейтинг книги
Дважды одаренный. Том II

Сиротский Бруклин

Литэм Джонатан
Детективы:
прочие детективы
6.25
рейтинг книги
Сиротский Бруклин

Тень Нерона

Алферова Марианна Владимировна
3. Сыщик
Фантастика:
детективная фантастика
6.25
рейтинг книги
Тень Нерона

Лекарь Империи 2

Карелин Сергей Витальевич
2. Лекарь Империи
Фантастика:
городское фэнтези
аниме
дорама
фэнтези
попаданцы
5.00
рейтинг книги
Лекарь Империи 2

Тень Гегемона

Кард Орсон Скотт
2. Эндер Виггин. Сага теней
Фантастика:
научная фантастика
7.11
рейтинг книги
Тень Гегемона