Отметим, что после прерывания сигнал вновь настраивается на onintr
. Это обусловлено тем, что когда сигналы возникают, они автоматически настраиваются на реакцию по умолчанию.
Некоторые программы, которые "хотят" обнаружить сигналы, просто не могут быть остановлены в произвольный момент, например в середине обновления сложных составных данных. Решение состоит в том, что подпрограмма обработки прерывания должна установить флаг и вернуться к месту вызова exit
или longjmp
. Выполнение программы продолжится точно с того места, где оно было прервано, а флаг прерывания будет проверен позднее.
С этим подходом связана одна трудность. Предположим, что, когда посылается сигнал прерывания, программа читается с терминала. Описанная подпрограмма непременно вызывается; она устанавливает свой флаг и возвращается. Если бы, как отмечалось выше, было верно то, что выполнение возобновляется точно с того места, где оно прервалось, программа продолжала бы чтение с терминала до ввода пользователем другой строки. Однако здесь возникает недоразумение, поскольку пользователь может не знать, что программа читает, и предположительно предпочел бы, чтобы сигнал сразу оказал действие. Для разрешения проблемы система должна закончить read
, но с сообщением об ошибке, указывающим, что произошло: errno
присваивается EINTR
, определенное в заголовке
, чтобы обозначить прерванный системный вызов.
Так, программы, которые "ловят" сигналы и продолжают после этого свою работу, должны быть готовы к появлению ошибок, вызванных прерванными системными вызовами. (Следует остерегаться системных вызовов read
— чтение с терминала, wait
, pause
). Такая программа при чтении стандартного входного потока могла бы использовать фрагмент, подобный следующему:
#include
extern int errno;
...
if (read(0, &c, 1) <= 0) /* EOF или прерывание */
if (errno == EINTR) { /* EOF, вызванный прерыванием */
errno = 0; /* устанавливается для следующего раза */
} else { /* настоящий конец файла */
...
}
Очень сложно постоянно следить за тем, как реакция на сигнал комбинируется с выполнением других программ. Предположим, программа ловит сигналы прерывания и располагает средствами (типа "!
"в ed
) для выполнения других программ. Тогда программа могла бы выглядеть так:
if (fork() == 0)
execlp(...);
signal(SIGINT, SIG_IGN); /* родитель игнорирует прерывание */
wait(&status); /* пока потомок не завершился */
signal(SIGINT, onintr); /* восстанавливает прерывания */
Почему? Сигналы посылаются всем вашим процессам. Предположим, программа, которую вы вызвали, ловит свои собственные сигналы прерывания, как это делает редактор. Если вы прервете выполнение подпрограммы, она получит сигнал, вернется к своему главному циклу и, возможно, начнет читать с вашего терминала. Но вызывающая программа также перейдет от wait
к подпрограмме и будет читать с терминала. Два процесса, читающие с вашего терминала, создадут трудную ситуацию, так как в результате системе придется гадать, к кому попадет та или иная строка входного потока. Решение состоит в том, чтобы родительская программа игнорировала прерывания, пока не завершился процесс-потомок. Это решение нашло свое отражение при обработке сигнала в system
:
#include
system(s) /* run command line s */
char *s;
{
int status, pid, w, tty;
int (*istat)(), (*qstat)();
...
if ((pid = fork()) == 0) {
...
execlp("sh", "sh", "-c", s, (char*)0);
exit(127);
}
...
istat = signal(SIGINT, SIG_IGN);
qstat = signal(SIGQUIT, SIG_IGN);
while ((w = wait(&status)) != pid && w != -1);
if (w == -1)
status = -1;
signal(SIGINT, istat);
signal(SIGQUIT, qstat);
return status;
}
Несколько слов по поводу описаний: функция signal
, очевидно, имеет довольно странный второй аргумент. Фактически он представляет собой указатель на функцию, поставляющую целое значение, и в то же время это тип самой подпрограммы сигнала. Две величины, SIG_IGN
и SIG_DFL
, имеют правильный тип, но выбраны так, что не совпадают ни с одной из существующих функции. Для любознательных покажем, как они определены для PDP-11 и VAX: определения, видимо, достаточно "неуклюжи", чтобы стимулировать использование
.
#define SIG_DFL (int(*)())0
#define SIG_IGM (int(*)())1
Вильям Л Саймон , Вильям Саймон , Наталья Владимировна Макеева , Нора Робертс , Юрий Викторович Щербатых
Зарубежная компьютерная, околокомпьютерная литература / ОС и Сети, интернет / Короткие любовные романы / Психология / Прочая справочная литература / Образование и наука / Книги по IT / Словари и Энциклопедии