Почему мой обработчик сигналов Linux запускается только один раз - PullRequest
3 голосов
/ 27 мая 2010
#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 / g ++ 4.2:

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

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

Ответы [ 3 ]

2 голосов
/ 27 мая 2010

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

2 голосов
/ 27 мая 2010

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

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

1 голос
/ 28 мая 2010

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

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

Тем не менее, мне любопытно, имеет ли отношение ошибка SIGFPE к состоянию fe * кроме ().

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

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