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

6.4.2. Посылка сигналов самому процессу: вызовы sigraiseи alarm

Функция sigraise просто посылает сигнал выполняющемуся процессу:

Описание

uses linux;

Procedure SigRaise(Sig:integer);

Вызывающему процессу посылается сигнал, определенный параметром sig и в случае успеха функция sigraise возвращает нулевое значение. Например:

uses Linux;

Var

oa,na : PSigActionRec;

Procedure DoSig(sig : Longint);cdecl;

begin

writeln('Receiving signal: ',sig);

end;

begin

new(na);

new(oa);

na^.handler.sh:=@DoSig;

na^.Sa_Mask:=0;

na^.Sa_Flags:=0;

na^.Sa_Restorer:=Nil;

SigAction(SigUsr1,na,oa);

if LinuxError<>0 then

begin

writeln('Error: ',linuxerror,'.');

halt(1);

end;

Writeln('Sending USR1 (',sigusr1,') signal to self.');

SigRaise(sigusr1);

end.

Вызов alarm – это простой и полезный вызов, который устанавливает таймер процесса. При срабатывании таймера процессу посылается сигнал.

Описание

uses linux;

Function Alarm(Secs:longint):Longint;

Переменная secs задает время в секундах, на которое устанавливается таймер. После истечения заданного интервала времени процессу посылается сигнал SIGALRM. Поэтому вызов

alarm(60);

приводит к посылке сигнала SIGALRM через 60 секунд. Обратите внимание, что вызов alarm не приостанавливает выполнение процесса, как вызов sleep, вместо этого сразу же происходит возврат из вызова alarm, и продолжается нормальное выполнение процесса, по крайней мере, до тех пор, пока не будет получен сигнал SIGALRM. Установленный таймер будет продолжать отсчет и после вызова ехec, но вызов fork выключает таймер в дочернем процессе.

Выключить таймер можно при помощи вызова alarm с нулевым параметром:

(* Выключить таймер *)

alarm(0);

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

Вызов alarm может быть полезен, если нужно ограничить время выполнения какого-либо действия. Основная идея проста: вызывается alarm, и процесс начинает выполнение задачи. Если задача выполняется вовремя, то таймер сбрасывается. Если выполнение задачи отнимает слишком много времени, то процесс прерывается при помощи сигнала SIGTERM и выполняет корректирующие действия.

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

Функция quickreply вызывает процедуру gets из стандартной библиотеки ввода/вывода (Standard I/O Library). Процедура gets помещает очередную строку из стандартного ввода в массив char. Она возвращает либо указатель на массив, либо нулевой указатель в случае достижения конца файла или ошибки. Обратите внимание на то, что сигнал SIGALRM перехватывается процедурой обработчика прерывания catch. Это важно, так как по умолчанию получение сигнала SIGALRM приводит к завершению процесса. Процедура catch устанавливает флаг timed_out. Функция quickreply проверяет этот флаг, определяя таким образом, не истекло ли заданное время.

uses linux,stdio;

const

TIMEOUT=5; (* время в секундах *)

MAXTRIES=5; (* число попыток *)

LINESIZE=100; (* длина строки *)

CTRL_G=#7; (* ASCII символ звукового сигнала *)

var

(* Флаг, определяющий, истекло ли заданное время *)

timed_out:boolean;

(* Переменная, которая будет содержать введенную строку *)

answer:array [0..LINESIZE-1] of char;

(* Выполняется при получении сигнала SIGALRM *)

procedure catch (sig:integer);cdecl;

begin

(* Установить флаг timed_out *)

timed_out := TRUE;

(* Подать звуковой сигнал *)

write(CTRL_G);

end;

function quickreply(prompt:pchar):pchar;

var

ntries:integer;

act, oact:sigactionrec;

begin

(* Перехватить сигнал SIGALRM и сохранить старый обработчик *)

act.handler.sh := @catch;

sigaction (SIGALRM, @act, @oact);

for ntries:=1 to MAXTRIES do

begin

timed_out := FALSE;

writeln;

write(prompt, ' > ');

(* Установить таймер *)

alarm (TIMEOUT);

(* Получить введенную строку *)

gets (answer);

(* Выключить таймер *)

alarm (0);

(* Если флаг timed_out равен TRUE, завершить работу *)

if not timed_out then

break;

end;

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

sigaction (SIGALRM, @oact, nil);

(* Вернуть соответствующее значение *)

if ntries = MAXTRIES then

quickreply:=nil

else quickreply:=answer;

end;

begin

writeln;

writeln(quickreply ('Reply'));

end.

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