nginx程式碼學習_第一章守護程序
阿新 • • 發佈:2019-01-04
最近在學習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('/'),切換工作目錄,防止解除安裝.