Скачиваний:
56
Добавлен:
08.01.2014
Размер:
2.6 Mб
Скачать

Пример 3: восстановление прежнего действия

Как упоминалось выше, в структуре sigaction может быть заполнен третий параметр oact. Это позволяет сохранять и восстанавливать прежнее состояние обработчика сигнала, как показано в следующем примере:

uses linux;

var

act, oact: sigactionrec;

(* Сохранить старый обработчик сигнала SIGTERM *)

sigaction(SIGTERM, nil, @oact);

(* Определить новый обработчик сигнала SIGTERM *)

act.handler.sh := SIG_IGN;

sigaction(SIGTERM, @act, nil);

(* Выполнить какие-либо действия *)

(* Восстановить старый обработчик *)

sigaction(SIGTERM, @oact, nil);

Пример 4: аккуратный выход

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

(* Аккуратный выход из программы *)

uses linux;

procedure g_exit(s:integer);cdecl;

begin

unlink ('tempfile');

writeln (stderr, 'Прерывание - выход из программы');

halt(1);

end;

Можно связать эту процедуру с определенным сигналом:

var

act:sigactionrec;

.

.

act.handler.sh := @g_exit;

sigaction (SIGINT, @act, nil);

Если после этого вызова пользователь нажмет клавишу прерывания, то управление будет автоматически передано процедуре g_exit. Можно дополнить процедуру g_exit другими необходимыми для завершения операциями.

6.2.3. Сигналы и системные вызовы

В большинстве случаев, если процессу посылается сигнал во время выполнения им системного вызова, то обработка сигнала откладывается до завершения вызова. Но некоторые системные вызовы ведут себя по-другому, и их выполнение можно прервать при помощи сигнала. Это относится к вызовам ввода/вывода (fdread, fdwrite, fdopen, и т.д.), вызовам wait или pause (который мы обсудим в свое время). Во всех случаях, если процесс перехватывает вызов, то прерванный системный вызов возвращает значение –1 и помещает в переменную linuxerror значение Sys_EINTR. Такие ситуации можно обрабатывать при помощи следующего кода:

if fdwrite(tfd, buf, size) < 0 then

begin

if linuxerror = Sys_EINTR then

begin

warn('Вызов fdwrite прерван');

.

.

.

end;

end;

В этом случае, если программа хочет вернуться к системному вызову fdwrite, то она должна использовать цикл и оператор continue. Но процедура sigactionrec позволяет автоматически повторять прерванный таким образом системный вызов. Это достигается установкой значения SA_RESTART в поле sa_flags структуры sigactionrec. Если установлен этот флаг, то системный вызов будет выполнен снова, и значение переменной linuxerror не будет установлено.

Важно отметить, что сигналы UNIX обычно не могут накапливаться. Другими словами, в любой момент времени только один сигнал каждого типа может ожидать обработки данным процессом, хотя несколько сигналов разных типов могут ожидать обработки одновременно. Фактически то, что сигналы не могут накапливаться, означает, что они не могут использоваться в качестве полностью надежного метода межпроцессного взаимодействия, так как процесс не может быть уверен, что посланный им сигнал не будет «потерян».

Упражнение 6.1. Измените программу smallsh из предыдущей главы так, чтобы она обрабатывала клавиши прерывания и завершения как настоящий командный интерпретатор. Выполнение фоновых процессов не должно прерываться сигналами SIGINT и SIGQUIT. Некоторые командные интерпретаторы, (а именно C-shell и Korn shell) помещают фоновые процессы в другую группу процессов. В чем преимущества и недостатки этого подхода? (В последних версиях стандарта POSIX введено накопление сигналов, но в качестве необязательного расширения.)

Соседние файлы в папке Полищук, Семериков. Системное программирование в UNIX средствами Free Pascal