Нормальное и аварийное завершение
Получение большинства сигналов приводит к нормальному завершению
(normal termination)
процесса. Действие сигнала при этом похоже на неожиданный вызов процессом функции _exit. Статус завершения, возвращаемый при этом родительскому процессу, сообщит о причине завершения дочернего процесса. В файле stdio определены макросы, которые позволяют родительскому процессу определить причину завершения дочернего процесса (получение сигнала и, собственно, значение сигнала. Следующий фрагмент программы демонстрирует родительский процесс, проверяющий причину завершения дочернего процесса и выводящий соответствующее сообщение:
uses stdio;
.
.
pid:=wait(@status);
if pid=-1 then
begin
perror('ошибка вызова wait');
halt(1);
end;
(* Проверка нормального завершения дочернего процесса *)
if WIFEXITED(status) then
begin
exit_status := WEXITSTATUS(status);
writeln('Статус завершения ', pid, ' был ', exit_status);
end;
(* Проверка, получил ли дочерний процесс сигнал *)
if WIFSIGNALED(status) then
begin
sig_no := WTERMSIG(status);
writeln('Сигнал номер ', sig_no, ' завершил процесс ', pid);
end;
(* Проверка остановки дочернего процесса *)
if WIFSTOPPED(status) then
begin
sig_no := WSTOPSIG(status);
writeln('Сигнал номер ', sig_no, ' остановил процесс ', pid);
end;
Как уже упоминалось, сигналы SIGABRT, SIGBUS, SIGSEGV, SIGQUIT, SIGILL, SIGTRAP, SIGSYS, SIGXCPU, SIGXFSZ и SIGFPE приводят к аварийному завершению и обычно сопровождаются сбросом образа памяти на диск. Образ памяти процесса записывается в файл с именем core в текущем рабочем каталоге процесса (термин core, или сердечник, напоминает о временах, когда оперативная память состояла из матриц ферритовых сердечников). Файл core будет содержать значения всех переменных программы, регистров процессора и необходимую управляющую информацию ядра на момент завершения программы. Статус завершения процесса после аварийного завершения будет тем же, каким он был бы в случае нормального завершения из-за этого сигнала, только в нем будет дополнительно выставлен седьмой бит младшего байта. В большинстве современных систем UNIX
определен макрос WCOREDUMP, который возвращает истинное или ложное значение в зависимости от установки этого бита в своем аргументе. Тем не менее следует учесть, что макрос WCOREDUMP не определен спецификацией XSI. С применением этого макроса предыдущий пример можно переписать так:
(* Проверка, получил ли дочерний процесс сигнал *)
if WIFSIGNALED(status) then
begin
sig_no := WTERMSIG(status);
writeln('Сигнал номер ', sig_no, ' завершил процесс ', pid);
if WCOREDUMP(status) then
writeln('... создан файл дампа памяти');
end;
Формат файла core известен отладчикам UNIX, и этот файл можно использовать для изучения состояния процесса в момент сброса образа памяти. Этим можно воспользоваться для определения точки, в которой возникает проблема.
Стоит также упомянуть функцию abort, которая не имеет аргументов:
abort;
Эта функция посылает вызвавшему ее процессу сигнал SIGABRT, вызывая его аварийное завершение, то есть сброс образа памяти. Процедура
abort полезна в качестве средства отладки, так как позволяет процессу записать свое текущее состояние, если что-то происходит не так. Она также иллюстрирует тот факт, что процесс может послать сигнал самому себе.