2010-05-27 3 views
3
#include <iostream> 
#include <signal.h> 
#include <fenv.h> 
#include <string.h> 

void signal_handler(int sig, siginfo_t *siginfo, void* context) 
{ 
    std::cout << " signal_handler " << fetestexcept(FE_ALL_EXCEPT) << std::endl; 
    throw "exception"; 
} 

void divide() { 
    float a = 1000., b = 0., c, f = 1e-300; 
    c = a/b; 

    std::cout << c << " and f = " << f << std::endl; 
} 

void init_sig_hanlder() { 
    feenableexcept(FE_ALL_EXCEPT); 

    struct sigaction sa, initial_sa; 

    sa.sa_sigaction = &signal_handler ; 
    sigemptyset(&sa.sa_mask) ; 
    sa.sa_flags = SA_SIGINFO; // man sigaction(3) // allows for void(*)(int,siginfo_t*,void*) handler 

    sigaction(SIGFPE, &sa, &initial_sa); 

} 

int main(int argc, char** argv) { 
    init_sig_hanlder(); 

    while(true) 
    { 
     try { 
    sleep(1); 
    divide(); 
     } 
     catch(const char * a) { 
    std::cout << "Exception in catch: " << a << std::endl; 
     }  
     catch(...) { 
    std::cout << "Exception in ..." << std::endl; 
     }  
    } 

    return 0; 
} 

Производят следующие результаты на Linux/г ++ 4.2:Почему мой обработчик сигнала линукс запустить только один раз

signal_handler 0
Исключение в улове: исключение
инф и е = 0
инф и е = 0
инфа и е = 0
инфа и е = 0

Таким образом, обработчик сигналов выполняется в первый раз, но следующее исключение fp не запускает обработчик снова. Где я ошибаюсь?

+0

Странно, что fetestexcept возвращает 0 в вашем обработчике, который, как представляется, указывает на то, что время, которое вызвал ваш обработчик, не будет помечено никакими типами SIGFPE. – msw

ответ

2

Я не думаю, что исключение исключения из обработчика сигнала - хорошая практика. Операционная система ожидает, что обработчик сигнала будет return, потому что сигнал заблокирован, пока вызван обработчик для него. Выбрасывая исключение, вы не позволяете системе разблокировать сигнал.

+0

Хорошо, на самом деле мой код более сложный, чем этот. Я проверю, возвращается ли обработчик или генерирует исключение, потому что это кажется хорошим объяснением. –

+0

, а также выброс из обработчика не допускается, использование cout - не очень хорошая идея. Это, скорее всего, не является безопасным сигналом. В этой простой программе это может не иметь значения, но если вы собираетесь делать IO в обработчике, open/write/close, вероятно, единственный безопасный способ. –

2

Как я помню, обработчики сигналов должны быть объявлены «extern» C », потому что библиотека/ядро ​​будет использовать соглашения о вызовах C, а не соглашение о вызове C++ для вашей функции. Но функции, которые являются внешними «С», не могут генерировать исключения, поэтому, по крайней мере, формально ваш код не является «правильным»

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

+0

// Скопировано из ответа на Tomer Vromen Хорошо, на самом деле мой код сложнее этого. Я проверю, возвращается ли обработчик или генерирует исключение, потому что это кажется хорошим объяснением. –

+0

Более пристальный взгляд на код показал, что я не генерирую исключение в обработчике. Реальная проблема - перейти к следующей инструкции. On solaris выполняется со следующим кодом:
aContext-> uc_mcontext.gregs [REG_PC] = aContext-> uc_mcontext.gregs [REG_nPC]; –

+0

Я не могу найти аналогичный пример на платформе Linux, я получил регистр EIP, указывающий на следующую инструкцию, но я не знаю, как нажать значение. –

1

Вы должны использовать sigsetjmp/siglongjmp для кода вроде этого, а не исключений.

Использование исключений здесь неверно, и изменение jmp должно быть первым шагом, чтобы исключить поведение нечетной платформы (особенно, поскольку стандарт C++ допускает реализацию исключений с использованием механизмов доставки сигналов).

Тем не менее, мне любопытно, может ли отказ SIGFPE быть поднят, что-то связано с состоянием fe * except().

Вопрос: Что происходит с этим состоянием до и после начального деления на ноль? Возможно, есть ожидание того, что feclearexcept() требуется, чтобы получить еще один SIGFPE, когда вы попробуете это снова.

+0

На самом деле, я делаю следующее: - создайте объект C++ в стеке, который будет проверен после вычислительного кода, - вызывается код вычисления вызова, вызывающий SIGFPE, - обработчик сигнала и устанавливают некоторые флаги в ранее созданный объект, - вызывается метод Check() и может генерировать исключения Первая ошибка заключалась в том, чтобы запустить исключение в обработчике, поэтому я подавил этот вызов, но программа вернулась к операции отмены. Я бы пропустил эту инструкцию, но сброс флагов FPU с помощью feclearexcept()/fesetenv() не работает. Я посмотрю на sigsetjmp/siglongjmp. –

Смежные вопросы