Скачиваний:
106
Добавлен:
12.05.2015
Размер:
670.21 Кб
Скачать

10.15. Функция abort

Ранее уже упоминалось, что вызов функции abort приводит к аварийному завершению процесса.

#include <stdlib.h>

void abort (void);

/* эта функция никогда не возвращает управление */

Эта функция передает сигнал SIGABRT вызывающему процессу. (Процессы не должны игнорировать этот сигнал). Стандарт ISO C определяет, что функция abort должна извещать операционную систему об аварийном завершении с помощью вызова функции raise(SIGABRT).

Стандарт ISO C требует, чтобы функция abort никогда не возвращала управление, даже в том случае, когда приложение перехватывает сигнал SIGABRT. Если сигнал перехватывается, то единственный способ для обработчика не вернуть управление в вызывающий процесс – это вызвать одну из функций exit, _exit или _Exit. Помимо этого, стандарт Posix.1 указывает, что функция abort должна выполняться даже в том случае, если процесс заблокировал или игнорирует сигнал SIGABRT.

Процессу позволено перехватывать сигнал SIGABRT, чтобы он мог выполнить необходимые действия перед завершением. Если процесс не завершается из обработчика сигнала, то стандарт Posix.1 указывает, что функция abort должна завершить процесс, когда обработчик сигнала вернет управление.

Стандарт ISO C оставляет на усмотрение реализации решение вопроса о сбросе буферов ввода-вывода и удалении временных файлов (раздел 5.10). Стандарт Posix.1 пошел гораздо дальше и требует, чтобы функция abort, если она завершает процесс, воздействовала на открытые потоки ввода-вывода так же, как функция fclose.

Пример. В листинге 10.18 приводится реализация функции abort, соответствующая требованиям стандарта Posix.1.

Листинг 10.18. Реализация функции abort, соответствующая требованиям стандарта Posix.1

#include <signal.h>

#include <stdio.h>

void my_abort(void) /* функция abort() в стиле POSIX */

{

sigset_t mask;

struct sigaction action;

/*

* Вызывающий процесс не может игнорировать SIGABRT. Если это так,

* то необходимо сбросить диспозицию сигнала в значение по умолчанию.

*/

sigaction(SIGABRT, NULL, &action);

if (action.sa_handler == SIG_IGN)

{

action.sa_handler = SIG_DFL;

sigaction(SIGABRT, &action, NULL);

}

if (action.sa_handler == SIG_DFL)

fflush(NULL); /* сбросить буферы всех потоков ввода-вывода */

/*

* Вызывающий процесс не может заблокировать SIGABRT;

* убедитесь, что он не заблокирован.

*/

sigfillset(&mask);

sigdelset(&mask, SIGABRT); /* в маске разблокирован только SIGABRT */

sigprocmask(SIG_SETMASK, &mask, NULL);

kill(getpid(), SIGABRT); /* послать сигнал */

/*

* Если мы вернулись сюда, значит, процесс перехватил SIGABRT

* и вернул управление.

*/

fflush(NULL); /* сбросить буферы всех потоков ввода-вывода */

action.sa_handler = SIG_DFL; /* Установить диспозицию сигнала */

sigaction(SIGABRT, &action, NULL); /* в значение по умолчанию. */

sigprocmask(SIG_SETMASK, &mask, NULL); /* на всякий случай ... */

kill(getpid(), SIGABRT); /* и еще раз */

exit(1); /* этот вызов никогда не будет выполнен ... */

}

Прежде всего, мы проверяем, будет ли выполнено действие по умолчанию для сигнала SIGABRT – если это так, то мы сбрасываем буферы всех открытых потоков ввода-вывода. Это не равносильно вызову функции fclose (поскольку мы лишь сбрасываем буферы, а не закрываем потоки), но система сама закроет все открытые файлы, когда процесс завершится. Если процесс перехватил сигнал и вернул управление, мы опять сбрасываем буферы всех открытых потоков ввода-вывода, поскольку процесс мог выводить некоторые данные в обработчике сигнала. Единственное, что мы не сможем обработать, –это вызов функции _exit или _Exit из обработчика. В этом случае все данные, оставшиеся в буферах ввода-вывода, будут утеряны. Но мы будем исходить из предположения, что вызывающий процесс просто не пожелал сбрасывать содержимое буферов.

В разделе 10.8 мы говорили, что если в результате вызова функции kill будет сгенерирован сигнал для вызывающего процесса и этот сигнал не заблокирован, (что гарантирует функция my_abort из листинга 10.18), то этот сигнал (или любой другой незаблокированный сигнал, ожидающий обработки) будет доставлен процессу еще до выхода из функции kill. В данном случае мы блокируем доставку всех сигналов, за исключением SIGABRT, поэтому мы наверняка знаем, что если вызов функции kill вернул управление, значит, сигнал был перехвачен и обработан процессом.

Соседние файлы в папке Chapter.3