nginx代碼學習_第一章守護進程

最近在學習linux的一些開源代碼,nginx是我想要學習的第一個目標,因爲它十分小巧相對於它的強大功能來說.

我使用過http服務端,文件目錄瀏覽.除此之外我知道的還有反向代理,負載均衡,等功能.最主要的還是他代碼量比較少,和我以前使用的項目結構相似有着一定的親切感.

我主要想了解的幾個主要功能模塊包括:內存池,守護進程變化,以及http業務解析等,今天先看到了守護進程的代碼比較少,先來了解這塊代碼.

二話不說上代碼

ngx_int_t ngx_daemon(ngx_log_t *log)
{
    int  fd;

    switch (fork()) {
    case -1:
        ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "fork() failed");
        return NGX_ERROR;

    case 0:          //子進程作爲守護進程
        break;

    default:
        exit(0);  //父進程退出
    }

    ngx_pid = ngx_getpid();

    if (setsid() == -1) {   //setsid創建一個新會話
        ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "setsid() failed");
        return NGX_ERROR;
    }

    umask(0);

    //打開文件/dev/null,使得其擁有守護進程的0,1,2。這樣防止守護進程在終端設備上顯示輸出
    fd = open("/dev/null", O_RDWR);
    if (fd == -1) {
        ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
                      "open(\"/dev/null\") failed");
        return NGX_ERROR;
    }

    if (dup2(fd, STDIN_FILENO) == -1) {
        ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "dup2(STDIN) failed");
        return NGX_ERROR;
    }

    if (dup2(fd, STDOUT_FILENO) == -1) {
        ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "dup2(STDOUT) failed");
        return NGX_ERROR;
    }

#if 0
    if (dup2(fd, STDERR_FILENO) == -1) {
        ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "dup2(STDERR) failed");
        return NGX_ERROR;
    }
#endif

    if (fd > STDERR_FILENO) {
        if (close(fd) == -1) {  //關閉不需要的文件描述符
            ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "close() failed");
            return NGX_ERROR;
        }
    }

    return NGX_OK;
}

在這段代碼裏面一開始的frok函數很好理解,創建子進程將會作爲守護進程使用,接下里是使用一個switch進行父進程退出.使子進程成爲孤兒進程,接着子進程調用setsid創建新的會話,保證在登錄會話斷掉之後,進程能夠一直存在.
在這塊有個細節,就是如果是以庫的形式提供這個函數的話,爲了保險起見一般來說會去frok兩次.原因是因爲作爲庫函數的代碼不知道接下來的代碼會不會有ioctl(TIOCSCTTY)這種調用,如果有的話那麼子進程就有當前的session,這時候調用setsid()是不會成功的,所以說這時候就算創建守護進程失敗了,但是由於是編寫的一整個程序,所以不會有上面之類的調用.

接下來脫離原進程文件權限使用umask,進程從創建它的父進程那裏繼承了文件創建掩模。它可能修改守護進程所創建的文件的存取位。爲防止這一點,將文件創建掩模清除.

然後將三個默認fd重定向到/dev/null上,分別爲標準輸入,標準輸出,錯誤輸出.

這樣nginx的守護進程就寫完了.但是這個不完全是一個完整的daemon的寫法,一個完整的daemon的寫法裏面還會包括chdir('/'),切換工作目錄,防止卸載.


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章