2015-01-17 1 views
3

저는 Win7/MSVC 2010sp1, g ++ 버전 (4.4.7, 4.1.2)이있는 두 개의 다른 Linux 상자 (Red Hat) 및 xlC++ (08.00.0000.0025)가있는 AIX에 살고 있습니다.Linux 신호 처리에서 예기치 않은 동작이 발생하는 이유는 무엇입니까?

얼마 전부터 AIX에서 Linux로 코드를 옮겨야한다는 요청이있었습니다. Linux가 조금 다르다는 것을 알기에는 너무 오래 걸리지 않았습니다. 일반적으로 신호가 던져지면 처리하고 C++ 예외를 throw합니다. 예상대로 작동하지 않았습니다.

Long story short, throwing c++ exceptions from a signal handler isn't going to work.

언젠가 나중에, I 함께 핸들러에서 예외 setjmp는 이동/longjmp를 사용하는 수정을 넣어. 시험 후에도 모든 플랫폼에서 작동합니다. 의무적 인 입방체의 행복한 춤을 추후 나는 단위 테스트를 시작했다. 죄송합니다.

일부 테스트가 Linux에서 실패했습니다. 내가 본 것은 레이즈 기능이 한 번만 작동한다는 것입니다. SIGILL을 사용한 두 가지 테스트에서 첫 번째 테스트가 통과되었고 두 번째 테스트가 실패했습니다. 나는 도끼를 터뜨 렸고 가능한 많은 걸쇠를 제거하기 위해 코드를 자르기 시작했습니다. 이 작은 예가 나온다.

#include <csetjmp> 
#include <iostream> 
#include <signal.h> 

jmp_buf mJmpBuf; 
jmp_buf *mpJmpBuf = &mJmpBuf; 
int status = 0; 
int testCount = 3; 

void handler(int signalNumber) 
{ 
    signal(signalNumber, handler); 
    longjmp(*mpJmpBuf, signalNumber); 
} 

int main(void) 
{ 
    if (signal(SIGILL, handler) != SIG_ERR) 
    { 
     for (int test = 1; test <= testCount; test++) 
     { 
      try 
      { 
       std::cerr << "Test " << test << "\n"; 
       if ((status = setjmp(*mpJmpBuf)) == 0) 
       { 
        std::cerr << " About to raise SIGILL" << "\n"; 
        int returnStatus = raise(SIGILL); 
        std::cerr << " Raise returned value " << returnStatus 
           << "\n"; 
       } 
       else 
       { 
        std::cerr << " Caught signal. Converting signal " 
           << status << " to exception" << "\n"; 
        std::exception e; 
        throw e; 
       } 
       std::cerr << " SIGILL should have been thrown **********\n"; 
      } 
      catch (std::exception &) 
      { std::cerr << " Caught exception as expected\n"; } 
     } 
    } 
    else 
    { std::cerr << "The signal handler wasn't registered\n"; } 

    return 0; 
} 

Windows 및 AIX 상자의 경우 예상되는 출력을 얻습니다.

Test 1 
    About to raise SIGILL 
    Caught signal. Converting signal 4 to exception 
    Caught exception as expected Test 2 
    About to raise SIGILL 
    Caught signal. Converting signal 4 to exception 
    Caught exception as expected Test 3 
    About to raise SIGILL 
    Caught signal. Converting signal 4 to exception 
    Caught exception as expected 

두 Linux 상자의 경우 다음과 같습니다.

Test 1 
    About to raise SIGILL 
    Caught signal. Converting signal 4 to exception 
    Caught exception as expected 
Test 2 
    About to raise SIGILL 
    Raise returned value 0 
    SIGILL should have been thrown ********** 
Test 3 
    About to raise SIGILL 
    Raise returned value 0 
    SIGILL should have been thrown ********** 

그래서, 내 진짜 질문은 " 은 무슨 일이야?"입니다

내 retorical 질문

은 다음과 같습니다

  • 다른 사람이이 동작을 관찰 있습니까?
  • 이 문제를 해결하려면 어떻게해야합니까?
  • 내가 알아야 할 다른 사항은 무엇입니까?

답변

3

신호와 점프를 혼합 할 때 올바른 동작을 보장하려면 sigsetjmp/siglongjmp을 사용해야합니다. 코드를 변경하면 Linux에서 제대로 작동합니다.

권장하지 않는 이전 신호 API도 사용했습니다. 훨씬 더 신뢰할 수있는 sigaction 인터페이스를 사용하는 것이 좋습니다. 첫 번째 이점은 처리기에서 신호 캐치를 재설정 할 필요가 없다는 것입니다.