【VS开发】程序如何捕捉signal函数参数中指定的信号

来源:互联网 发布:vivo手机mac地址修改 编辑:程序博客网 时间:2024/06/05 22:40
 当说到signal的功能时,我们都知道它会捕捉我们所指定的信号,然后调用我们所指定的信号处理函数。但它是如何捕捉我们指定的信号的呢?下面我就以msdn上关于signal的example为例,说明signal是如何捕捉信号的。
         程序如下:
[cpp] view plain copy
// crt_signal.c  
// compile with: /c  
// Use signal to attach a signal handler to the abort routine  
#include <stdio.h>  
#include <stdlib.h>  
#include <signal.h>  
#include <tchar.h>  
  
void SignalHandler(int signal)  
{  
    printf("Application aborting...\n");  
}  
  
int main()  
{  
    typedef void (*SignalHandlerPointer)(int);  
  
    SignalHandlerPointer previousHandler;  
    previousHandler = signal(SIGABRT, SignalHandler);  
      
    abort();  
}  
        先说一下signal函数的声明:void (*signal(int sig,void (*func)(int)))(int),它的返回值类型是函数指针,这个函数指针指向一个返回值为void类型,接受一个int参数的函数。实际上signal函数返回的是该函数调用前指定信号的处理函数的指针。
        回到程序中来,这个程序很简单,首先定义了一个信号处理函数SignalHandler,然后调用signal用SignalHandler处理所产生的中止信号(SIGABRT)。执行程序时,首先调用signal函数,signal函数的定义(winsig.c中)部分如下:
[cpp] view plain copy
_PHNDLR __cdecl signal(int signum,_PHNDLR sigact)  
{  
    //...  
    switch (signum) {  
            case SIGINT:  
                    //...  
                    break;  
            case SIGBREAK:  
                    //...  
                    break;  
            case SIGABRT:  
            case SIGABRT_COMPAT:  
                    oldsigact = (_PHNDLR) DecodePointer(abort_action);  
                    if(sigact!=SIG_GET)  
                    {  
                        abort_action = (_PHNDLR) EncodePointer(sigact);  
                    }  
                    break;  
            case SIGTERM:  
                    //...  
                    break;  
                }  
     //...  
}  
        我们可以看到,指定了SIGABRT,signal函数就会执行case SIGABRT下面的语句,将指向函数调用前的SIGABRT处理函数的指针赋给oldsigact,将新的处理函数编码后赋给abort_action,这一步非常重要,因为下面的abort()函数就是根据它来得到信号处理函数的。
        接下来执行abort函数,该函数会产生SIGABRT信号,其定义(abort.c中)如下:
[cpp] view plain copy
void __cdecl abort (  
        void  
        )  
{  
    _PHNDLR sigabrt_act = SIG_DFL;  
  
    //...  
  
    sigabrt_act = __get_sigabrt();  
    if (sigabrt_act != SIG_DFL)  
    {  
        raise(SIGABRT);  
    }  
    //...  
    _exit(3);  
}  
         该函数调用__get_sigabrt()取得信号处理函数sigabrt_act,然后调用raise(SIGABRT),在这个函数中调用信号处理函数。raise()的定义()如下:
[cpp] view plain copy
int __cdecl raise (  
        int signum  
        )  
{  
        _PHNDLR sigact;  
        _PHNDLR *psigact;  
        switch (signum) {  
  
                case SIGINT:  
                        sigact = *(psigact = &ctrlc_action);  
                        siglock++;  
                        break;  
  
                case SIGBREAK:  
                        sigact = *(psigact = &ctrlbreak_action);  
                        siglock++;  
                        break;  
  
                case SIGABRT:  
                case SIGABRT_COMPAT:  
                        sigact = *(psigact = &abort_action);  
                        siglock++;  
                        break;  
  
                case SIGTERM:  
                        sigact = *(psigact = &term_action);  
                        siglock++;  
                        break;  
  
                case SIGFPE:  
                case SIGILL:  
                case SIGSEGV:  
                        ptd = _getptd_noexit();  
                        if (!ptd)  
                            return (-1);  
                        sigact = *(psigact = &(siglookup( signum,  
                            ptd->_pxcptacttab )->XcptAction));  
                        goto decode_done;  
                        break;  
  
                default:  
                        /* 
                         * unsupported signal, return an error 
                         */  
                        _VALIDATE_RETURN(("Invalid signal or error", 0), EINVAL, -1);  
        }  
        sigact = (_PHNDLR) DecodePointer(sigact);  
  
decode_done:  
        /* 
         * If the current action is SIG_IGN, just return 
         */  
        if ( sigact == SIG_IGN )  
                return(0);  
  
        /* 
         * If the current action is SIG_DFL, take the default action 
         */  
        if ( sigact == SIG_DFL ) {  
                _exit(3);  
        }  
  
        //...  
                (*sigact)(signum);  
        return(0);  
}  
        在case SIGABRT中将abort_action的值即信号处理函数指针赋给sigact,在最后调用函数(*sigact)(signum)完成对SIGABRT信号的处理。程序对其他信号的捕捉过程也差不多是这样。
        在我这里说的只是一个大概的流程,其中还有很多代码的细节没有涉及到,比如说对预定义的信号处理函数的判断、异常的处理等,这些还有待深入理解和研究。

0 0
原创粉丝点击