zoukankan      html  css  js  c++  java
  • 【VS开发】程序如何捕捉signal函数参数中指定的信号

     当说到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... ");  
    }  
      
    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信号的处理。程序对其他信号的捕捉过程也差不多是这样。
            在我这里说的只是一个大概的流程,其中还有很多代码的细节没有涉及到,比如说对预定义的信号处理函数的判断、异常的处理等,这些还有待深入理解和研究。

  • 相关阅读:
    ESLint规则整理与实际应用
    node vue 项目git 管理
    Node.js安装及环境配置之Windows篇
    Windows服务 --- SqlDependency的使用
    插槽
    报表菜单的配置
    HTTP 错误 500.21
    项目部署错误 HTTP Error 500.19
    Steup factory 面板介绍
    Steup Factory 操作注册表
  • 原文地址:https://www.cnblogs.com/huty/p/8517231.html
Copyright © 2011-2022 走看看