Системное программирование в UNIX средствами Free Pascal

       

Вызывающему процессу посылается сигнал, определенный


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.

Содержание раздела