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

       

Системный вызов halt уже известен,


uses system;
procedure halt(status:word);
Системный вызов halt уже известен, но теперь следует дать его правильное описание. Этот вызов используется для завершения процесса, хотя это также происходит, когда управление доходит до конца тела главной программы или до процедуры exit в теле главной программы.
Единственный целочисленный аргумент вызова halt называется статусом завершения (exit status) процесса, младшие восемь бит которого доступны родительскому процессу при условии, если он выполнил системный вызов wait (подробнее об этом см. в следующем разделе). При этом возвращаемое вызовом halt значение обычно используется для определения успешного или неудачного завершения выполнявшейся процессом задачи. По принятому соглашению, нулевое возвращаемое значение соответствует нормальному завершению, а ненулевое значение говорит о том, что что-то случилось.
Кроме завершения вызывающего его процесса, вызов halt имеет еще несколько последствий: наиболее важным из них является закрытие всех открытых дескрипторов файлов. Если, как это было в последнем примере, родительский процесс выполнял вызов wait, то его выполнение продолжится.
Для полноты изложения следует также упомянуть системный вызов _exit, который отличается от вызова halt наличием символа подчеркивания в начале. Он используется в точности так же, как и вызов halt. Тем не менее он не включает описанные ранее действия по очистке. В большинстве случаев следует избегать использования вызова _exit.
Упражнение 5.7. Статус завершения программы можно получить в командном интерпретаторе при помощи переменной $?, например:
$ ls nonesuch
  nonesuch: No such file or directory
$ echo $?
  2
Напишите программу fake, которая использует целочисленное значение первого аргумента в качестве статуса завершения. Используя намеченный выше метод, выполните программу fake, задавая различные значения аргументов, включая большие и отрицательные. Есть ли польза от программы fake?




uses stdio;
function wait(status:pinteger):longint;
Как было уже обсуждено, вызов wait временно приостанавливает выполнение процесса, в то время как дочерний процесс продолжает выполняться. После завершения дочернего процесса выполнение родительского процесса продолжится. Если запущено более одного дочернего процесса, то возврат из вызова wait произойдет после выхода из любого из потомков.
Вызов wait часто осуществляется родительским процессом после вызова fork, например:
.
.
.
var
  status:integer;
  cpid:longint;
cpid := fork; (*Создать новый процесс *)
if cpid = 0 then
begin
  (* Дочерний процесс *)
  (* Выполнить какие-либо действия ... *)
end
else
begin
  /* Родительский процесс, ожидание завершения дочернего */
  cpid := wait(@status);
  writeln('Дочерний процесс ', cpid, ' завершился');
end;
.
.
.
Сочетание вызовов fork и wait наиболее полезно, если дочерний процесс предназначен для выполнения совершенно другой программы при помощи вызова ехеc.
Возвращаемое значение wait обычно является идентификатором дочернего процесса, который завершил свою работу. Если вызов
wait возвращает значение -1, это может означать, что дочерние процессы не существуют, и в этом случае переменная linuxerror будет содержать код ошибки Sys_ECHILD. Возможность определить завершение каждого из дочерних процессов по отдельности означает, что родительский процесс может выполнять цикл, ожидая завершения каждого из потомков, а после того, как все они завершатся, продолжать свою работу.
Вызов wait принимает один аргумент, status, – указатель на целое число. Если указатель равен nil, то аргумент просто игнорируется. Если же вызову wait передается допустимый указатель, то после возврата из вызова wait переменная status будет содержать полезную информацию о статусе завершения процесса. Обычно эта информация будет представлять собой код завершения дочернего процесса, переданный при помощи вызова halt.
Следующая программа status показывает, как может быть использован вызов wait:


 (* Программа status -- получение статуса завершения потомка *)
uses linux,stdio;
var
  pid:longint;
  status, exit_status:integer;
begin
  pid := fork;
  if pid < 0 then
    fatal ('Ошибка вызова fork ');
  if pid = 0 then            (* потомок *)
  begin
    (* Вызвать библиотечную процедуру sleep
     * для временного прекращения работы на 4 секунды
     *)
    sleep(4);
    halt(5);                (* выход с ненулевым значением *)
  end;
  (* Если мы оказались здесь, то это родительский процесс, *)
  (* поэтому ожидать завершения дочернего процесса         *)
  pid := wait(@status);
  if pid = -1 then
  begin
    perror ('Ошибка вызова wait ');
    halt(2);
  end;
  (* Проверка статуса завершения дочернего процесса *)
  if WIFEXITED (status) then
  begin
    exit_status := WEXITSTATUS (status);
    writeln ('Статус завершения ',pid,' равен ', exit_status);
  end;
  halt(0);
end.
Значение, возвращаемое родительскому процессу при помощи вызова halt, записывается в старшие восемь бит целочисленной переменной status. Чтобы оно имело смысл, младшие восемь бит должны быть равны нулю. Функция WIFEXITED (определенная в модуле stdio) проверяет, так ли это на самом деле. Если WIFEXITED возвращает false, то это означает, что выполнение дочернего процесса было остановлено (или прекращено) другим процессом при помощи межпроцессного взаимодействия, называемого сигналом (signal) и рассматриваемого в главе 6.
Упражнение 5.8. Переделайте процедуру docommand так, чтобы она возвращала статус вызова halt выполняемой команды. Что должно происходить, если вызов wait возвращает значение -1?

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