区块链研习社

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

2017-12-21  本文已影响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();
};

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

上一篇下一篇

猜你喜欢

热点阅读