美文网首页区块链研习社
比特币源码阅读(五):初始化和启动(4)

比特币源码阅读(五):初始化和启动(4)

作者: 沙漠中的猴 | 来源:发表于2017-12-21 23:15 被阅读0次

    AppInitBasicSetup()

    函数定义的位置在src/init.cpp。由于函数较长并且是分步执行。所以将源代码拆分来看

    // src/init.cpp 
    
     // ********************************************************* Step 1: setup
        //如果是微软的VS环境就执行下面的内容
    #ifdef _MSC_VER
        // Turn off Microsoft heap dump noise
        //将warn级别的内容都输出到文件(注意dump的报告级别即为warning)
        _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE); 
        //设置输出文件句柄,设置为NUL表示对告警信息不做任何处理
        _CrtSetReportFile(_CRT_WARN, CreateFileA("NUL", GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, 0));
        // Disable confusing "helpful" text message on abort, Ctrl-C
        //指定当程序异常终止时要采取的操作。
        _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
    #endif
    

    通过_CrtSetReportMode函数讲Warn级别信息输出到文件,然后再通过_CrtSetReportFile函数来指定文件的输出位置。设置为NUL表示忽略该级别的告警信息。_set_abort_behavior函数指定当程序异常终止时要采取的动作。参考:https://msdn.microsoft.com/zh-cn/e631wekh

    // src/init.cpp
    
    #ifdef WIN32
        // Enable Data Execution Prevention (DEP)
        // Minimum supported OS versions: WinXP SP3, WinVista >= SP1, Win Server 2008
        // A failure is non-critical and needs no further attention!
    #ifndef PROCESS_DEP_ENABLE
        // We define this here, because GCCs winbase.h limits this to _WIN32_WINNT >= 0x0601 (Windows 7),
        // which is not correct. Can be removed, when GCCs winbase.h is fixed!
    #define PROCESS_DEP_ENABLE 0x00000001
    #endif
        typedef BOOL (WINAPI *PSETPROCDEPPOL)(DWORD);
        PSETPROCDEPPOL setProcDEPPol = (PSETPROCDEPPOL)GetProcAddress(GetModuleHandleA("Kernel32.dll"), "SetProcessDEPPolicy");
        if (setProcDEPPol != nullptr) setProcDEPPol(PROCESS_DEP_ENABLE);
    #endif
    

    数据执行保护 (DEP) 是一套软硬件技术,能够在内存上执行额外检查以帮助防止在系统上运行恶意代码。
    这段代码是针对WIN32位系统中对DEP部分进行的设置。DEP最小支持的系统版本是WinXP SP3, WinVista >= SP1, Win Server 2008。
    在这里定义的原因是winbase.h限制了必须满足_WIN32_WINNT >= 0x0601 (Windows 7)系统条件才会启用DEP,也就是说低版本不会启用DEP保护。
    启用方法是通过动态链接库Kernel32.dll来查找SetProcessDEPPolicy的函数地址,并将PROCESS_DEP_ENABLE设置成0x00000001。也就是表示该进程的生命周期内永久启用DEP保护。
    SetProcessDEPPolicy函数介绍参考:https://msdn.microsoft.com/en-us/library/bb736299(VS.85).aspx

    接下来初始化网络套接字,函数定义在/src/util.cpp

    bool SetupNetworking()
    {
    #ifdef WIN32
        // Initialize Windows Sockets
        WSADATA wsadata;
        int ret = WSAStartup(MAKEWORD(2,2), &wsadata);
        if (ret != NO_ERROR || LOBYTE(wsadata.wVersion ) != 2 || HIBYTE(wsadata.wVersion) != 2)
            return false;
    #endif
        return true;
    }
    

    如果是Windows系统就需要初始化一些参数,不是Windows系统就返回true

    // src/init.cpp
    #ifndef WIN32
        if (!gArgs.GetBoolArg("-sysperms", false)) {
            umask(077);
        }
    
        // Clean shutdown on SIGTERM
        //终止信号
        registerSignalHandler(SIGTERM, HandleSIGTERM);
        //来自键盘的中断信号
        registerSignalHandler(SIGINT, HandleSIGTERM);
    
        // Reopen debug.log on SIGHUP
        //挂起信号
        registerSignalHandler(SIGHUP, HandleSIGHUP);
    
        // Ignore SIGPIPE, otherwise it will bring the daemon down if the client closes unexpectedly
        signal(SIGPIPE, SIG_IGN);
    #endif
    

    这段代码先判断是否设置了-sysperms参数。如果设置了该参数就按照系统默认的权限创建新的文件。如果没有设置,则按照umask(077)来设置新文件的权限。umask(077)表示owner具有所有权限,group和other不对该文件具备任何权限
    下面三行代码分别注册了终止信号、中断信号和挂起信号的处理函数,也就是把相应变量设置成true。代码如下所示

    // src/init.cpp
    /**
     * Signal handlers are very limited in what they are allowed to do.
     * The execution context the handler is invoked in is not guaranteed,
     * so we restrict handler operations to just touching variables:
     */
    static void HandleSIGTERM(int)
    {
        fRequestShutdown = true;
    }
    
    static void HandleSIGHUP(int)
    {
        fReopenDebugLog = true;
    }
    

    接下来的signal(SIGPIPE, SIG_IGN) 表示忽略管道断开信号。作用是防止client通过socket连接到daemon之后client断开导致daemon终止的问题。signal相关内容可以参考http://www.cplusplus.com/reference/csignal/signal/

    我们来看最后一行代码 :
    std::set_new_handler(new_handler_terminate);
    参考:https://www.cnblogs.com/zhuyf87/archive/2013/04/04/2999916.html
    当operator new 不能满足一个内存分配请求的时候,会抛出一个异常。而set_new_handler()函数的作用就是用来捕获这个异常,并且进行处理。

    
    [[noreturn]] static void new_handler_terminate()
    {
        // Rather than throwing std::bad-alloc if allocation fails, terminate
        // immediately to (try to) avoid chain corruption.
        // Since LogPrintf may itself allocate memory, set the handler directly
        // to terminate first.
        std::set_new_handler(std::terminate);
        LogPrintf("Error: Out of memory. Terminating.\n");
    
        // The log was successful, terminate now.
        std::terminate();
    };
    

    代码显示直接终止进程,避免冲突。

    相关文章

      网友评论

        本文标题:比特币源码阅读(五):初始化和启动(4)

        本文链接:https://www.haomeiwen.com/subject/lcoebxtx.html