обработка сигналов - PullRequest
       8

обработка сигналов

2 голосов
/ 01 февраля 2011

Я просто играю с сигналом в Mac OS X.

Почему следующий код не производит поведение SIGSEGV по умолчанию после завершения моего обработчика сигнала? Под Linux код работает нормально.

#include <stdio.h>
#include <signal.h>
#include <stdlib.h>

void err_crash();

void my_signal_handler (int signal)
{
    fprintf(stderr, "signal == %i\n", signal);
    fflush(stderr);
    err_crash();
}

void err_crash()
{
    static int count= 0;
    if (count)
        signal(SIGSEGV, SIG_DFL);       /* break recursion loop if we recursed */
    count++;

    // one of the two should really crash ;)
    ((void)(*((int volatile *)NULL)));
    *((int *)NULL) = 42;

    abort();                            /* in case we're not crashed yet... */
}

int main ()
{
    signal(SIGSEGV, my_signal_handler);
    err_crash();
    return 0;
}

EDIT: Вывод, который я получаю, следующий:

bonecrusher:devel sw$ g++ signal_problems.cpp -o foo
bonecrusher:devel sw$ ./foo 
signal == 11
^C
bonecrusher:devel sw$

Проблема в том, что я хочу, чтобы программа завершала работу после вывода signal == 11, но это происходит вечно, и мне приходится прерывать его.

Ответы [ 3 ]

17 голосов
/ 01 февраля 2011

Это на самом деле вызвало у меня замораживание мозга на несколько минут, и причина, по которой никогда не следует использовать signal() в этот день и возраст, только усилилась во мне.

Прежде всего, из справочных страниц для signal()

Поведение сигнала () варьируется в зависимости от Версии UNIX, а также отличается исторически в разных версиях Linux. Избегайте его использования: используйте вместо sigaction (2).

и далее вниз:

  • Если расположение установлено на функцию, то сначала либо расположение сбрасывается до SIG_DFL, или сигнал заблокирован (см. Портативность ниже), а затем вызывается обработчик с аргументом signum. Если вызов обработчик вызвал сигнал заблокирован, то сигнал разблокирован по возвращении из обработчика.

В исходных системах Unix, когда был установлен обработчик, расположение было сброшено до SIG_DFL, не блокировал входящие сигналы типа того же , а затем запустил обработчик функция. Система V предоставила это, и ядро ​​Linux делает то же самое.

Это означает, что после запуска кода в системе linux при вызове второго исключения он будет завершен напрямую.

Теперь самое интересное. BSD пытался улучшить это поведение. С man страниц снова:

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

И поскольку Mac OSX частично основан на BSD, после запуска кода на Mac OSX при вызове второго исключения будет в ожидании и ожидание выхода обработчика первого исключения. , Но так как вы никогда не выйдете, у вас тупик.

Вот почему вместо этого следует использовать sigaction(), а не signal().

Теперь несколько советов:

Обработчики должны быть короткими и возвращаться быстро. Если вы выполняете вычисления и вызываете другие функции, вы, вероятно, делаете что-то не так. Сигналы не заменяют управляемую событиями структуру.

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

Еще немного прочтения: «Делай» и «Не» внутри обработчика сигнала

1 голос
/ 01 февраля 2011

Согласно POSIX :

Если какой-либо из сигналов SIGFPE, SIGILL, SIGSEGV или SIGBUS генерируется, когда они заблокированы, результат не определен, если сигнал не былгенерируется функцией kill(), функцией sigqueue() или функцией raise().

Поскольку SIGSEGV заблокирован в обработчике сигнала SIGSEGV, результат в этом случае не определен, и любойповедение допустимо.Если вы не хотите, чтобы он был заблокирован, вы можете установить обработчик сигнала, используя sigaction() с флагом SA_NODEFER, или использовать sigprocmask(), чтобы разблокировать сигнал внутриобработчик сигнала.

0 голосов
/ 01 февраля 2011

Запустите его в отладчике и выполните пошаговые инструкции, ожидающие сбой.

Нет гарантии, что запись по недействительным адресам должна вызвать ошибку сегментации.Возможно, Mac OS X отображает эти адреса для вас, и вы перезаписываете что-то мягкое.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...