Функция abort() завершает вызывающий процесс путем подачи сигнала SIGABRT. Действие по умолчанию для сигнала SIGABRT — создание файла дампа ядра и завершение процесса. Файл дампа впоследствии может быть использован отладчиком для изучения состояния программы на момент вызова функции abort().

Стандарт SUSv3 требует, чтобы функция abort() переопределяла эффект блокирования сигнала SIGABRT. Более того, стандарт SUSv3 устанавливает, что abort() должна завершать процесс в том случае, если он не перехватывает сигнал, обработчик которого не выполняет возврат. Последнее предложение требует осмысления. Среди методов завершения процессов, описываемых в разделе 21.2, только метод, предполагающий использование нелокального перехода, может рассматриваться как имеющий отношение к этому предложению. Если применяется этот метод, то эффект функции abort() будет обнулен; во всех остальных случаях функция abort() всегда завершает процесс.

В большинстве реализаций завершение процесса гарантируется следующим образом: если процесс не завершен после однократной подачи сигнала SIGABRT (то есть обработчик перехватывает сигнал и выполняет возврат таким образом, что выполнение функции abort() возобновляется), то функция abort() восстанавливает обработку сигнала SIGABRT до SIG_DFL и повторно подает сигнал SIGABRT, который гарантированно завершит процесс.

Если функция abort() успешно завершает процесс, то она также сбрасывает и закрывает потоки stdio.

Пример использования функции abort() приводится при рассмотрении функций обработки ошибок в листинге 3.3.

21.3. Обработка сигнала на альтернативном стеке: signalstack()

Как правило, при активации обработчика сигнала ядро выделяет для него участок на стеке процесса. Однако это может быть невозможно, если процесс попытается расширить стек за пределы максимально возможного размера. Например, такое может произойти, если стек становится настолько большим, что сталкивается с участком отображенной памяти или увеличивающейся областью динамически распределяемой памяти (кучей) либо достигает ресурсного ограничения RLIMIT_STACK (см. раздел 36.3).

Когда процесс пытается увеличить стек за пределы установленного максимально возможного размера, ядро направляет в процесс сигнал SIGSEGV. Однако по причине того, что пространство стека израсходовано, ядро не сможет выделить участок для обработчика сигнала SIGSEGV, возможно установленного в программе. Следовательно, инициализации обработчика не происходит и процесс завершается (действие по умолчанию для сигнала SIGSEGV).

Если же нам нужно, чтобы в вышеописанной ситуации происходила обработка сигнала SIGSEGV, мы можем поступить следующим образом.

1. Выделить участок памяти, называемый альтернативным сигнальным стеком, который может использоваться в качестве кадра стека для обработчика сигнала.

2. Применить системный вызов signalstack() для информирования ядра о наличии альтернативного сигнального стека.

3. При установке обработчика сигнала указать флаг SA_ONSTACK, чтобы информировать ядро о том, что кадр для данного обработчика должен быть создан на альтернативном стеке.

Системный вызов signalstack() не только создает альтернативный сигнальный стек, но также возвращает информацию о любом уже созданном альтернативном сигнальном стеке.

#include

int signalstack(const stack_t *sigstack, stack_t *old_sigstack);

Возвращает 0 при успешном завершении или –1 при ошибке

Аргумент sigstack указывает на структуру, в которой приводятся местоположение и атрибуты нового альтернативного сигнального стека. Аргумент old_sigstack указывает на структуру, используемую для возврата информации о ранее созданном альтернативном сигнальном стеке (если таковой был создан). Любой из этих аргументов может быть указан как NULL. Например, мы можем получить информацию о существующем альтернативном сигнальном стеке, не изменяя его, просто указав аргумент sigstack как NULL. В противном случае каждый аргумент будет указывать на структуру следующего типа:

typedef struct {

void *ss_sp; /* Начальный адрес альтернативного стека*/

int ss_flags; /* Флаги: SS_ONSTACK, SS_DISABLE */

size_t ss_size; /* Размер альтернативного стека */

} stack_t;

В полях ss_sp и ss_size указываются местоположение и размер альтернативного сигнального стека. Когда мы действительно им воспользуемся, ядро возьмет на себя заботу о выравнивании указанного значения поля ss_sp с границей адресов, совместимой с применяемой аппаратной архитектурой.

Как правило, место для альтернативного сигнального стека выделяется либо статически, либо динамически на куче. Стандартом SUSv3 устанавливается использование константы SIGSTKSZ для указания типичного значения размера альтернативного стека и константы MINSIGSTKSZ для указания минимального размера, требующегося для активации обработчика сигнала. В Linux/х86-32 эти константы определены значениями 8192 и 2048 соответственно.

Перейти на страницу:

Похожие книги