nginx中父子進程工作的主體函數

來源:互聯網
上載者:User

標籤:c++   linux   nginx   

根據Nginx(0.7.67版本)的代碼,對Nginx基本的進程建立,進程主體以及事件處理進行了簡要的分析。
基本上,父進程(即主進程)一開始會初始化及讀取配置,並載入各模組的功能,然後fork()出N個子進程(即背景工作處理序),具有相同的工作邏輯和功能。父進程負責監聽訊號(如HUP,QUIT等),通過socket pair把訊號傳遞給子進程(子進程間一般不通訊)。子進程通過事件來處理父進程傳遞的訊號。因為每個子進程都共用服務監聽連接埠(如http 80),當使用者發送請求時,會觸發子進程的事件調用函數。因此在accept()請求的時候,需要用到mutex,保證只有一個背景工作處理序接受並處理請求。
Nginx主進程的入口是跟一般的程式一樣的main()函數,它的代碼是這樣的:int ngx_cdecl main(int argc, char *const *argv){/*...*/
//nginx 啟動的時候會嘗試從環境變數中讀取前次執行時候的監聽套介面的id,//並會建立對應數量的ngx_listening_t結構變數(存於 cycle->listening數組中),//然後調用這個介面通過getsockname,getsockopt等系統調用把原來套介面的屬性資訊和//設定參數讀取出來去設定那些新建立的ngx_listening_t結構變數,這樣就繼承了前次執行//時候的監聽套介面了,這個介面是在 ngx_init_cycle之前調用的
if (ngx_add_inherited_sockets(&init_cycle) != NGX_OK) { return 1; }
/*...*/
//ngx_modules數組在objs/ngx_modules.c定義ngx_max_module = 0;for (i = 0; ngx_modules[i]; i++) { ngx_modules[i]->index = ngx_max_module++; //將每個模組編號}
//ngx_init_cycle()函數,這是個比較重要的函數,被main, ngx_master_process_cycle//和ngx_single_process_cycle 調用, 其中後兩者是在reconfigure的時候被調用的。//它主要工作是,初始化cycle是基於舊有的cycle進行的;會繼承old cycle的很多屬性, //比如log等, 但是同時會對很多資源重新分配,比如pool, shared mem, file handler, //listening socket等,同時清除舊有的cycle的資源//讀取設定檔也是在這裡完成的cycle = ngx_init_cycle(&init_cycle);
if (ngx_process == NGX_PROCESS_SINGLE) { ngx_single_process_cycle(cycle); } else {//一般採用多進程處理請求ngx_master_process_cycle(cycle);}}
//主進程(即父進程)的主體//這個函數會啟動背景工作處理序幹活,並且會處理訊號量,處理的過程中會殺死或者建立新的進程void ngx_master_process_cycle(ngx_cycle_t *cycle){//把訊號加入到監聽集合set sigemptyset(&set);//sigemptyset()用來將參數set訊號集初始化並清空 sigaddset(&set, SIGCHLD);//sigaddset() 增加一個訊號至訊號集 sigaddset(&set, SIGALRM); sigaddset(&set, SIGIO); sigaddset(&set, SIGINT); sigaddset(&set, ngx_signal_value(NGX_RECONFIGURE_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_REOPEN_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_NOACCEPT_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_TERMINATE_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); sigaddset(&set, ngx_signal_value(NGX_CHANGEBIN_SIGNAL));
/*...*/
//按照ngx_core_conf_t中worker_processes數,啟動若干個work進程 ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_RESPAWN);
//後面一個迴圈對不同的狀態進行不同處理,而那些狀態多數是進程收到的不同訊號//ngx_signal_t signals[]數組定義訊號以及處理方法:ngx_signal_handler()//訊號在ngx_init_signals()裡面初始化//在ngx_signal_handler()裡,根據ngx_process來決定是master process還是//worker process的處理流程(即是說master和worker都調用ngx_signal_handler//來處理訊號)
for ( ;; ) {//掛起當前進程,等到有訊號,就會從掛起狀態退出,繼續執行//set記錄當前監聽的訊號 sigsuspend(&set);/*各種訊號的處理,如NGX_SHUTDOWN_SIGNAL,NGX_RECONFIGURE_SIGNAL等*//*省略*/}}

//ngx_start_worker_processes()函數,這個函數按指定數目n,以ngx_worker_process_cycle()函//數為參數調用ngx_spawn_process()建立work進程並初始化相關資源和屬性;//執行子進程的執行函數ngx_worker_process_cycle;向之前已經建立的所有worker廣播當前建立的//worker進程的資訊;每個進程開啟一個通道(ngx_pass_open_channel())//n是worker process的數目//type 即建立新進程式的方式,如NGX_PROCESS_RESPAWN, NGX_PROCESS_JUST_RESPAWNstatic void ngx_start_worker_processes(ngx_cycle_t *cycle, ngx_int_t n, ngx_int_t type){     ngx_int_t      i;ngx_channel_t  ch;
     ch.command = NGX_CMD_OPEN_CHANNEL;
     for (i = 0; i < n; i++) {//從config讀取CPU的分配         cpu_affinity = ngx_get_cpu_affinity(i);//ngx_spawn_process中設定ngx_process_slot為被分配到子進程的//空閑slot         ngx_spawn_process(cycle, ngx_worker_process_cycle, NULL,"worker process", type);         ch.pid = ngx_processes[ngx_process_slot].pid;         ch.slot = ngx_process_slot;         ch.fd = ngx_processes[ngx_process_slot].channel[0];//ngx_pass_open_channel 把這個worker的channel[0]和進程id//在進程表中的位移slot廣播(ngx_write_channel())給所有其他已經//建立的worker。//這樣,建立完所有進程之後,每個worker就獲得了所有其他worker的//channel[0]了         ngx_pass_open_channel(cycle, &ch);    }}

ngx_pid_t ngx_spawn_process(ngx_cycle_t *cycle, ngx_spawn_proc_pt proc, void *data, char *name, ngx_int_t respawn){/*...*///如果類型為NGX_PROCESS_DETACHED,則說明是熱代碼替換(熱代碼替換也是通過這//個函數進行處理的),因此不需要建立socketpair。if (respawn != NGX_PROCESS_DETACHED) {//建立socketpair //建立socketpair用於處理序間通訊,master進程為每個worker建立一對//socket, master進程空間開啟所有socketpair的channel[0],//channel[1]兩端控制代碼。 //當建立一個worker的時候,這個worker會繼承master當前已經建立並//開啟的所有socketpair。//這個worker初始化的時候(調用ngx_worker_process_init)會關閉//本進程對應socketpair的channel[0]和其他worker對應的//channel[1],保持開啟本進程對應socketpair的channel[1]和其他//worker對應的channel[0],並監聽本進程對應socketpair的//channel[1]的可讀事件。這樣,每個worker就擁有了其他worker的//channel[0],可以sendmsg(channel[0], ...)向其他worker發送訊息/*...*/}
/*...*///建立子進程pid = fork();switch (pid) {case -1:ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "fork() failed while spawning "%s"", name);ngx_close_channel(ngx_processes[s].channel, cycle->log);return NGX_INVALID_PID;//在子進程裡,執行傳遞進來的子進程的函數case 0:ngx_pid = ngx_getpid();//調用ngx_worker_process_cycle()//注意:這個函數中定義了子進程處理事件的迴圈,即子進程不會//執行這個函數之後的語句proc(cycle, data);break;default:break; }
}
//worker進程的主體static void ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data){//設定一些環境變數//調用所有模組的init_process鉤子函數//將其他進程的channel[1]關閉,自己的除外//子進程繼承了父進程的ngx_processes數組,但子進程只監聽自己的channel[1]//將自己的channel[0]關閉//因為自己的channel[0]是給其他子進程,用來發送訊息的sendmsg//調用ngx_add_channel_event()函數,給ngx_channel註冊一個讀事件處理函數。ngx_worker_process_init(cycle, 1);//主迴圈,處理事件for ( ;; ) {/*...*/
//調用epoll,周期性監聽事件//先接收串連(並不處理事件),以及處理進程間訊號(如有)//處理accept queue和event queue裡面的事件ngx_process_events_and_timers(cycle);
/*...*/}
/*...*/}

nginx中父子進程工作的主體函數

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.