1. 程式人生 > >nginx程式碼學習_第一章守護程序

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('/'),切換工作目錄,防止解除安裝.