Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
208 views
in Technique[技术] by (71.8m points)

c++ - signal handling

I'm just playing with signal in Mac OS X.

Why does the following code not produce the default behavior of SIGSEGV after my signal handler has finished? Under Linux, the code works fine.

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

void err_crash();

void my_signal_handler (int signal)
{
    fprintf(stderr, "signal == %i
", 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: The output I get is the following:

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

The problem is that I want that the program terminates after the output of signal == 11, but it rans forever and I have to interrupt it.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

This actually caused me brain freeze for a few minutes, and the reason why one should never use signal() in this day and age only grew stronger in me.

First of all, from the man pages for signal()

The behavior of signal() varies across UNIX versions, and has also varied historically across different versions of Linux. Avoid its use: use sigaction(2) instead.

and further down :

  • If the disposition is set to a function, then first either the disposition is reset to SIG_DFL, or the signal is blocked (see Portability below), and then handler is called with argument signum. If invocation of the handler caused the signal to be blocked, then the signal is unblocked upon return from the handler.

In the original Unix systems, when a handler was installed, the disposition was reset to SIG_DFL, did not block incoming signals of the same type, and then it ran the handler function. System V provided this, and the linux kernel does the same.

This means that, once the code is run on a linux system, once second exception is called, it will exit directly.

Now to the fun part. BSD tried to improve this behaviour. From the man pages again:

On BSD, when a signal handler is invoked, the signal disposition is not reset, and further instances of the signal are blocked from being delivered while the handler is executing.

And since mac osx is partly based on BSD, once the code is run on a mac osx, once second exception is called, it will be pending and wait for the handler of the first exception to exit. But since you will never exit, you have a deadlock.

Thats why one should use sigaction() instead and never signal().

Now to some tips:

Handlers should be short, and return quickly. If you are performing calculations and calling other functions you are probably doing something wrong. Signals are not a substitute for an event driven framework.

Calling functions that are not async-safe is bad. Consider what would happen if an exception happened during a call to fprintf, and inside the handler fprintf was called again. Both the signal handlers and the programs data could be corrupted since they operate on the stream itself.

Some more reading : "Do" and "Don't" inside A Signal Handler


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...