nginx源碼分析—模塊及其初始化

Content

0. 序

1. nginx有哪些模塊?

2. nginx如何描述這些模塊?

2.1 模塊數據結構

2.1.1 ngx_module_t結構

2.1.2 ngx_command_t結構

2.2 模塊類圖

3. nginx如何組織這些模塊?

3.1 全局數組ngx_modules

3.2 模塊組織結構圖

4. nginx的模塊種類

5. nginx如何初始化這些模塊?

5.1 靜態初始化

5.2 動態初始化

5.2.1 index字段的初始化

5.2.2 ctx_index字段的初始化

5.2.3 其他初始化

6. 小結

  

0. 序

 

本文以nginx-1.0.4版本爲例,介紹nginx的模塊及其初始化。.表示nginx-1.0.4源代碼目錄,本文爲/usr/src/nginx-1.0.4。

 

1. nginx有哪些模塊?

 

要知道nginx有哪些模塊,一個快速的方法就是編譯nginx。編譯之後,會在源代碼根目錄下生成objs目錄,該目錄中包含有ngx_auto_config.h和ngx_auto_headers.h,以及ngx_modules.c文件,當然,還有Makefile文件等。

 

其中,生成的ngx_modules.c文件中,重新集中申明(使用extern關鍵字)了nginx配置的所有模塊,這些模塊可通過編譯前的configure命令進行配置,即設置哪些模塊需要編譯,哪些不被編譯。如下。

00001:
00002: #include <ngx_config.h>
00003: #include <ngx_core.h>
00004:
00005:
00006:
00007: extern ngx_module_t ngx_core_module;
00008: extern ngx_module_t ngx_errlog_module;
00009: extern ngx_module_t ngx_conf_module;
00010: extern ngx_module_t ngx_events_module;
00011: extern ngx_module_t ngx_event_core_module;
00012: extern ngx_module_t ngx_epoll_module;
00013: extern ngx_module_t ngx_http_module;
00014: extern ngx_module_t ngx_http_core_module;
00015: extern ngx_module_t ngx_http_log_module;
00016: extern ngx_module_t ngx_http_upstream_module;
00017: extern ngx_module_t ngx_http_static_module;
00018: extern ngx_module_t ngx_http_autoindex_module;
00019: extern ngx_module_t ngx_http_index_module;
00020: extern ngx_module_t ngx_http_auth_basic_module;
00021: extern ngx_module_t ngx_http_access_module;
00022: extern ngx_module_t ngx_http_limit_zone_module;
00023: extern ngx_module_t ngx_http_limit_req_module;
00024: extern ngx_module_t ngx_http_geo_module;
00025: extern ngx_module_t ngx_http_map_module;
00026: extern ngx_module_t ngx_http_split_clients_module;
00027: extern ngx_module_t ngx_http_referer_module;
00028: extern ngx_module_t ngx_http_rewrite_module;
00029: extern ngx_module_t ngx_http_proxy_module;
00030: extern ngx_module_t ngx_http_fastcgi_module;
00031: extern ngx_module_t ngx_http_uwsgi_module;
00032: extern ngx_module_t ngx_http_scgi_module;
00033: extern ngx_module_t ngx_http_memcached_module;
00034: extern ngx_module_t ngx_http_empty_gif_module;
00035: extern ngx_module_t ngx_http_browser_module;
00036: extern ngx_module_t ngx_http_upstream_ip_hash_module;
00037: extern ngx_module_t ngx_http_stub_status_module;
00038: extern ngx_module_t ngx_http_write_filter_module;
00039: extern ngx_module_t ngx_http_header_filter_module;
00040: extern ngx_module_t ngx_http_chunked_filter_module;
00041: extern ngx_module_t ngx_http_range_header_filter_module;
00042: extern ngx_module_t ngx_http_gzip_filter_module;
00043: extern ngx_module_t ngx_http_postpone_filter_module;
00044: extern ngx_module_t ngx_http_ssi_filter_module;
00045: extern ngx_module_t ngx_http_charset_filter_module;
00046: extern ngx_module_t ngx_http_userid_filter_module;
00047: extern ngx_module_t ngx_http_headers_filter_module;
00048: extern ngx_module_t ngx_http_copy_filter_module;
00049: extern ngx_module_t ngx_http_range_body_filter_module;
00050: extern ngx_module_t ngx_http_not_modified_filter_module;
00051:

很顯然,這些模塊均是在此處用extern進行申明,以表明其他模塊可以訪問,而對其本身的定義和初始化ngx_module_t結構在其對應的.c文件中進行。例如,ngx_core_module模塊便是在./src/core/nginx.c文件中定義並進行靜態初始化。實際上,ngx_core_module是一個全局的結構體對象,其他模塊類同。如下。

ngx_module_t  ngx_core_module = {
    NGX_MODULE_V1,
    &ngx_core_module_ctx,                  /* module context */
    ngx_core_commands,                     /* module directives */
    NGX_CORE_MODULE,                       /* module type */
    NULL,                                  /* init master */
    NULL,                                  /* init module */
    NULL,                                  /* init process */
    NULL,                                  /* init thread */
    NULL,                                  /* exit thread */
    NULL,                                  /* exit process */
    NULL,                                  /* exit master */
    NGX_MODULE_V1_PADDING
};

2. nginx如何描述這些模塊?

 

2.1 模塊數據結構

 

2.1.1 ngx_module_t結構

 

nginx的模塊化架構最基本的數據結構爲ngx_module_t,因此,此處,我們先分析這個結構,在./src/core/ngx_conf_file.h文件中定義。如下,//後的內容爲筆者加入的註釋。

00107: #define NGX_MODULE_V1    0, 0, 0, 0, 0, 0, 1         //該宏用來初始化前7個字段
00108: #define NGX_MODULE_V1_PADDING 0, 0, 0, 0, 0, 0, 0, 0 //該宏用來初始化最後8個字段
00109:
00110: struct ngx_module_s{
00111:    ngx_uint_t    ctx_index;  //分類模塊計數器
00112:    ngx_uint_t    index;      //模塊計數器
00113:
00114:    ngx_uint_t    spare0;
00115:    ngx_uint_t    spare1;
00116:    ngx_uint_t    spare2;
00117:    ngx_uint_t    spare3;
00118:
00119:    ngx_uint_t    version;    //版本
00120:
00121:    void          *ctx;       //該模塊的上下文,每個種類的模塊有不同的上下文
00122:    ngx_command_t *commands;  //該模塊的命令集,指向一個ngx_command_t結構數組
00123:    ngx_uint_t    type;       //該模塊的種類,爲core/event/http/mail中的一種
00124:    //以下是一些callback函數
00125:    ngx_uint_t    (*init_master)(ngx_log_t *log);      //初始化master
00126:
00127:    ngx_uint_t    (*init_module)(ngx_cycle_t *cycle);  //初始化模塊
00128:
00129:    ngx_uint_t    (*init_process)(ngx_cycle_t *cycle); //初始化工作進程
00130:    ngx_uint_t    (*init_thread)(ngx_cycle_t *cycle);  //初始化線程
00131:    void          (*exit_thread)(ngx_cycle_t *cycle);  //退出線程
00132:    void          (*exit_process)(ngx_cycle_t *cycle); //退出工作進程
00133:
00134:    void          (*exit_master)(ngx_cycle_t *cycle);  //退出master
00135:
00136:    uintptr_t     spare_hook0;  //這些字段貌似沒用過
00137:    uintptr_t     spare_hook1;
00138:    uintptr_t     spare_hook2;
00139:    uintptr_t     spare_hook3;
00140:    uintptr_t     spare_hook4;
00141:    uintptr_t     spare_hook5;
00142:    uintptr_t     spare_hook6;
00143:    uintptr_t     spare_hook7;
00144: };

其中,init_master, init_module, init_process, init_thread, exit_thread, exit_process, exit_master分別在初始化master、初始化模塊、初始化工作進程、初始化線程、退出線程、退出工作進程、退出master時被調用。

2.1.2 ngx_command_t結構

模塊的命令集commands指向一個ngx_command_t結構數組,在./src/core/ngx_conf_file.h文件中定義。如下,//後的內容爲筆者加入的註釋。

00077: struct ngx_command_s {
00078:    ngx_str_t     name;  //命令名
00079:    ngx_uint_t    type;  //命令類型
00080:    char          *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
00081:    ngx_uint_t    conf;
00082:    ngx_uint_t    offset;
00083:    void          *post;
00084: };
00085:
00086: #define ngx_null_command { ngx_null_string, 0, NULL, 0, 0, NULL }  //空命令

2.2 模塊類圖

 

nginx爲C語言開發的開源高性能web server,其代碼中大量使用了callback方式,例如模塊結構ngx_module_t中的init_master等。實際上,我們可以將ngx_module_t看作C++的一個類,其中的數據字段便是其屬性,而那些callback便是該類的操作。

 

——這應該就是nginx的模塊化思想。畫出的ngx_module_t的類圖如下。

3. nginx如何組織這些模塊?

 

3.1 全局數組ngx_modules

 

由第1節,我們知道,nginx擁有幾十個模塊,那麼,這些模塊是如何組織的呢?

 

——保存在一個全局指針數組ngx_modules[]中,數組的每一個元素均爲一個全局ngx_module_t對象的指針。如下。請參考./objs/ngx_modules.c文件中的定義。

00052: ngx_module_t *ngx_modules[] = {
00053:    &ngx_core_module,
00054:    &ngx_errlog_module,
00055:    &ngx_conf_module,
00056:    &ngx_events_module,
00057:    &ngx_event_core_module,
00058:    &ngx_epoll_module,
00059:    &ngx_http_module,
00060:    &ngx_http_core_module,
00061:    &ngx_http_log_module,
00062:    &ngx_http_upstream_module,
00063:    &ngx_http_static_module,
00064:    &ngx_http_autoindex_module,
00065:    &ngx_http_index_module,
00066:    &ngx_http_auth_basic_module,
00067:    &ngx_http_access_module,
00068:    &ngx_http_limit_zone_module,
00069:    &ngx_http_limit_req_module,
00070:    &ngx_http_geo_module,
00071:    &ngx_http_map_module,
00072:    &ngx_http_split_clients_module,
00073:    &ngx_http_referer_module,
00074:    &ngx_http_rewrite_module,
00075:    &ngx_http_proxy_module,
00076:    &ngx_http_fastcgi_module,
00077:    &ngx_http_uwsgi_module,
00078:    &ngx_http_scgi_module,
00079:    &ngx_http_memcached_module,
00080:    &ngx_http_empty_gif_module,
00081:    &ngx_http_browser_module,
00082:    &ngx_http_upstream_ip_hash_module,
00083:    &ngx_http_stub_status_module,
00084:    &ngx_http_write_filter_module,
00085:    &ngx_http_header_filter_module,
00086:    &ngx_http_chunked_filter_module,
00087:    &ngx_http_range_header_filter_module,
00088:    &ngx_http_gzip_filter_module,
00089:    &ngx_http_postpone_filter_module,
00090:    &ngx_http_ssi_filter_module,
00091:    &ngx_http_charset_filter_module,
00092:    &ngx_http_userid_filter_module,
00093:    &ngx_http_headers_filter_module,
00094:    &ngx_http_copy_filter_module,
00095:    &ngx_http_range_body_filter_module,
00096:    &ngx_http_not_modified_filter_module,
00097:    NULL
00098: };


3.2 模塊組織結構圖

 

共44個模塊,這些模塊的組織結構圖如下所示,因模塊較多,圖中只畫出一部分有代表性的重要模塊。 

4. nginx的模塊種類

 

在對全局數組ngx_modules進行初始化時,即對每一個模塊進行了靜態初始化。其中對模塊的type字段的初始化是通過以下4個宏進行的。

 

(1) 文件./src/core/ngx_conf_file.h

#define NGX_CORE_MODULE      0x45524F43   /* "CORE" */
#define NGX_CONF_MODULE      0x464E4F43   /* "CONF" */

(2) 文件./src/event/ngx_event.h

#define NGX_EVENT_MODULE      0x544E5645  /* "EVNT" */
#define NGX_EVENT_MODULE      0x544E5645  /* "EVNT" */

(3) 文件./src/http/ngx_http_config.h

#define NGX_HTTP_MODULE       0x50545448  /* "HTTP" */

即模塊種類宏,定義爲一個十六進制的數,這個十六進制的數就是其類型對應的ASCII碼。因此,nginx共有4種類型的模塊,分別爲"CORE","CONF","EVNT","HTTP"。

實際上,如果在configure階段,使用了"--with-mail"參數,mail模塊將被編譯進來,其對應的宏如下。

#define NGX_MAIL_MODULE       0x4C49414D  /* "MAIL" */

因此,嚴格來講,nginx有5中類型的模塊,"CORE","CONF","EVNT","HTTP","MAIL"。

5. nginx如何初始化這些模塊?

5.1 靜態初始化

即編譯期間完成的數據成員初始化。記mname爲某個模塊的名字,其靜態初始化過程如下。

(1) 用宏NGX_MODULE_V1初始化前7個字段

(2) 用全局對象ngx_mname_module_ctx的地址初始化ctx指針

(3) 用全局數組ngx_mname_commands[]初始化commands指針

(4) 用宏NGX_CORE_MODULE等初始化type字段

(5) 初始化init_master等callback

(6) 用宏NGX_MODULE_V1_PADDING初始化最後8個字段

由此可見,在定義該模塊(全局結構對象)時,將其ctx_index和index均初始化爲0。因此,模塊的靜態初始化(數據成員初始化)實際上只是對模塊上下文、模塊命令集和模塊類型進行初始化。

 

5.2 動態初始化

 

即nginx運行(啓動)初期,對模塊本身的初始化。

 

5.2.1 index字段的初始化

 

對各個模塊的index字段的初始化是在main函數中進行的,如下。

00325:    ngx_max_module = 0;
00326:    for (i = 0; ngx_modules[i]; i++) {
00327:       ngx_modules[i]->index = ngx_max_module++;
00328:    }

可見,該for-loop執行後,每個模塊的index值便是其在ngx_modules[]數組中的下標值,且全局變量ngx_max_module爲模塊個數,對於本例來講,ngx_max_module=44。

 

5.2.2 ctx_index字段的初始化

 

(1) "EVNT"類型的模塊

00877: static char *
00878: ngx_events_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
00879: {
00880:    char    *rv;
00881:    void    ***ctx;
00882:    ngx_uint_t    i;
00883:    ngx_conf_t    pcf;
00884:    ngx_event_module_t *m;
00885:
00886:    /* count the number of the event modules and set up their indices */
00887:
00888:    ngx_event_max_module = 0;
00889:    for (i = 0; ngx_modules[i]; i++) {
00890:       if (ngx_modules[i]->type ! = NGX_EVENT_MODULE) {
00891:          continue;
00892:       }
00893:
00894:       ngx_modules[i]->ctx_index = ngx_event_max_module++;
00895:    }


(2) "HTTP"類型的模塊

00117: static char *
00118: ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
00119: {
00120:    char    *rv;
00121:    ngx_uint_t    mi, m, s;
00122:    ngx_conf_t    pcf;
00123:    ngx_http_module_t    *module;
00124:    ngx_http_conf_ctx_t    *ctx;
00125:    ngx_http_core_loc_conf_t    *clcf;
00126:    ngx_http_core_srv_conf_t **cscfp;
00127:    ngx_http_core_main_conf_t *cmcf;
00128:
00129:    /* the main http context */
00130:
00131:    ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
00132:    if (ctx == NULL) {
00133:       return NGX_CONF_ERROR;
00134:    }
00135:
00136:    *(ngx_http_conf_ctx_t **) conf = ctx;
00137:
00138:
00139:    /* count the number of the http modules and set up their indices */
00140:
00141:    ngx_http_max_module = 0;
00142:    for (m = 0; ngx_modules[m]; m++) {
00143:       if (ngx_modules[m]->type ! = NGX_HTTP_MODULE) {
00144:          continue;
00145:       }
00146:
00147:       ngx_modules[m]->ctx_index = ngx_http_max_module++;
00148:    }


(3) "MAIL"類型的模塊

00072: static char *
00073: ngx_mail_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
00074: {
00075:    char    *rv;
00076:    ngx_uint_t    i, m, mi, s;
00077:    ngx_conf_t    pcf;
00078:    ngx_array_t    ports;
00079:    ngx_mail_listen_t    *listen;
00080:    ngx_mail_module_t    *module;
00081:    ngx_mail_conf_ctx_t    *ctx;
00082:    ngx_mail_core_srv_conf_t **cscfp;
00083:    ngx_mail_core_main_conf_t *cmcf;
00084:
00085:    if (cmd->name.data[0] == 'i') {
00086:       ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
00087:          "the \"imap\" directive is deprecated, "
00088:          "use the \"mail\" directive instead");
00089:    }
00090:
00091:    /* the main mail context */
00092:
00093:    ctx = ngx_pcalloc(cf->pool, sizeof(ngx_mail_conf_ctx_t));
00094:    if (ctx == NULL) {
00095:       return NGX_CONF_ERROR;
00096:    }
00097:
00098:    *(ngx_mail_conf_ctx_t **) conf = ctx;
00099:
00100:    /* count the number of the http modules and set up their indices */
00101:
00102:    ngx_mail_max_module = 0;
00103:    for (m = 0; ngx_modules[m]; m++) {
00104:       if (ngx_modules[m]->type ! = NGX_MAIL_MODULE) {
00105:          continue;
00106:       }
00107:
00108:       ngx_modules[m]->ctx_index = ngx_mail_max_module++;
00109:    }

5.2.3 其他初始化

其他的初始化工作,將在nginx啓動及其進程啓動分析中介紹。

6. 小結

本文主要講述了nginx的模塊及其初始化,包括所有模塊的組織,及模塊的靜態初始化和部分動態初始化。

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