1. 進程工作
ngx是多進程模型:work進程,master進程,cache進程。
ngx還使用 upstream等模塊實現和 其他服務器通信

master和worker進程工作流程如下

可以看出 用戶使用信號控制 監控進程,監控進程 控制工作進程
監控進程主要處理 用戶的信號,

監控進程使用 sigsuspend 阻塞等待信號,信號處理函數設置旗標,根據旗標完成具體動作。
ngx_quit 會進行清理工作再退出。
ngx_terminate 使用 SIGKILL 讓自己退出
ngx_reconfigure 重新加載配置
工作進程主要處理和 客戶端和后端服務器 IO,使用 select epoll 等多路復用實現。

2. 進程通信
2.1 channel
-
父子通信

ngx使用 socketpair 分配 兩個互相連接的 Unix套接字,fork后,channel[0] <----> channel[1] 依舊連接,實現血緣關系進程通信。 -
兄弟通信
新的子進程會繼承老的子進程的已連接的套接字,但是 老的子進程沒有用於寫給新子進程的套接字,ngx利用 進程間套接字傳遞 實現兄弟通信。
進程間傳遞文件描述符,參考:
https://www.cnblogs.com/yangxinrui/p/16083105.html
- 總結
雖然 ngx 實現了 channel 機制,可以完成 父子兄弟互相通信,但只用 channel 進行 控制進程對工作進程的通信。
而子進程之間使用更好的通信方法,如共享內存。
2.2 共享內存
2.2.1 初始化
ngx的共享內存可以通過 用戶配置 動態申請,如

這里申請一個共享內存,10M,名稱為one,
ngx使用 ngx_shm_zone_s 描述內存塊信息。
16 typedef struct {
17 u_char *addr;
18 size_t size;
19 ngx_str_t name;
20 ngx_log_t *log;
21 ngx_uint_t exists; /* unsigned exists:1; */
22 } ngx_shm_t;
25 typedef struct ngx_shm_zone_s ngx_shm_zone_t;
26
27 typedef ngx_int_t (*ngx_shm_zone_init_pt) (ngx_shm_zone_t *zone, void *data);
28
29 struct ngx_shm_zone_s {
30 void *data;
31 ngx_shm_t shm;
32 ngx_shm_zone_init_pt init;
33 void *tag;
34 void *sync;
35 ngx_uint_t noreuse; /* unsigned noreuse:1; */
36 };
shm.shm.name 是內存塊名稱,是內存塊唯一鍵值
shm.tag 用於區分內存塊的創建和使用,如 模塊A 創建名稱為a的內存塊,之后模塊A再用名稱a從內存池中獲取內存塊,這是可行的,但是若模塊B也創建名稱為a的內存塊,若內存塊只有name做區分,則模塊B也能獲得內存塊a,但這導致沖突,所以需要tag屬性表明該內存塊的owner,如此模塊B再創建名稱為a的內存塊時,還會比較tag是否為模塊B,匹配失敗則報錯,模塊B只能重建其他名稱內存塊。
ngx解析完配置文件時,調用 shared_memory_add() 創建 ngx_shm_zone_s,ngx_shm_zone_s只是內存塊描述,不是真正的內存塊,並將ngx_shm_zone_s 加入 鏈表 cf->cycle->shared_memory ,檢查沖突后,遍歷鏈表 分配共享內存,並格式化內存塊。

ngx_shm_alloc 是對 系統調用的封裝,完成內存塊申請
ngx_init_zone_pool 對內存塊進行格式化
shm_zone[i].init 回調用戶的初始化方法
以 ngx_http_limit_req_module 的初始化方法為例

若舊數據可用(重加載配置情況),則直接返回,否則初始化模塊ctx,用slab方法申請內存。
以上完成內存塊初始化,關於內存塊的使用涉及 互斥和slab
2.2.2 互斥
互斥是使用鎖解決,ngx互斥鎖接口如下

2.2.3 slab
ngx實現的slab是二級頁表,支持分配和釋放內存。
在共享內存的頭部,有頭信息

一級頁表

page[] 是真實用於分配的內存塊,
ngx_slab_page_t[] ngx管理page使用的描述結構,ngx_slab_page_t 和 page 一一對應,獲得 ngx_slab_page_t 地址,就能求得page地址。

ngx 對 ngx_slab_page_t 的管理,是使用 鏈表,鏈表元素為數組。
ngx_slab_page_t 數組的首元素的 slab屬性,表示本數組的長度
當分配空間如下



釋放空間,回收內存塊


二級頁表,
每個 ngx_slab_page_t 的二級頁面粒度不同,對 其對應 page 進行划分。並用位圖方式描述使用情況。
如果粒度能用32bit表示,則使用 ngx_slab_page_t.slab屬性表示

如果粒度用不完32bit,則使用 ngx_slab_page_t.slab屬性的一部分bit位表示
如果粒度用32bit表示不完,則使用 page首部表示

3. 信號
ngx對信號聲明對象

靜態定義信號對象數組

其中涉及的C語言宏

在初始化時,完成信號處理的初始化

ngx處理信號時,根據盡量簡單的原則,只進行少量工作

信號處理完成后,根據旗標進行真正處理

