关于
nginx有一套设计良好的源码,以供分析,本文从ngx_module_t
结构体来分析nginx源码结构。ngx_module_t
是整个nginx的关键,它提供了整个nginx的模块化的基础。因此,看懂ngx_module_t
结构体才能开始入门nginx源码阅读。
ngx_module_t
结构体介绍
该结构体描述了整个模块的所有信息,为核心模块进行初始化和调用提供了接口,整个结构体的初始化源码如下:
struct ngx_module_s {
ngx_uint_t ctx_index;
ngx_uint_t index;
char *name;
ngx_uint_t spare0;
ngx_uint_t spare1;
ngx_uint_t version;
const char *signature;
void *ctx;
ngx_command_t *commands;
ngx_uint_t type;
ngx_int_t (*init_master)(ngx_log_t *log);
ngx_int_t (*init_module)(ngx_cycle_t *cycle);
ngx_int_t (*init_process)(ngx_cycle_t *cycle);
ngx_int_t (*init_thread)(ngx_cycle_t *cycle);
void (*exit_thread)(ngx_cycle_t *cycle);
void (*exit_process)(ngx_cycle_t *cycle);
void (*exit_master)(ngx_cycle_t *cycle);
uintptr_t spare_hook0;
uintptr_t spare_hook1;
uintptr_t spare_hook2;
uintptr_t spare_hook3;
uintptr_t spare_hook4;
uintptr_t spare_hook5;
uintptr_t spare_hook6;
uintptr_t spare_hook7;
};
ngx_module_s
的关键部分在于中间的几个函数指针,以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
};
关于NGX_MODULE_V1
和NGX_MODULE_V1_PADDING
2个关键字是2个宏定义,主要用于快速声明而已,剩下的属性可以分为4类:模块类型、模块命令、模块上下文、预留接口。我们可以先了解模块命令结构体(ngx_command_s)
模块命令结构体(ngx_command_s)
ngx_command_s
结构体是用来分析整个配置文件关键字的工具,源码如下:
struct ngx_command_s {
ngx_str_t name;
ngx_uint_t type;
char *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
ngx_uint_t conf;
ngx_uint_t offset;
void *post;
};
ngx_module_t
结构体接口位置
init_master
接口
字面意思是初始化master
进程时候进行调用,但是暂未找到接口位置。
init_module
接口
该接口是在模块初始化的时候调用,调用位置在于ngx_init_cycle>ngx_init_modules
的代码中:
ngx_int_t
ngx_init_modules(ngx_cycle_t *cycle)
{
ngx_uint_t i;
for (i = 0; cycle->modules[i]; i++) {
if (cycle->modules[i]->init_module) {
if (cycle->modules[i]->init_module(cycle) != NGX_OK) {
return NGX_ERROR;
}
}
}
return NGX_OK;
}
init_process
接口
该接口分别在ngx_worker_process_init
和ngx_single_process_cycle
,2者会在不同的模式下运行,所以只会初始化一次。我们以多进程模式为例,其路径在:ngx_master_process_cycle>ngx_start_worker_processes>ngx_worker_process_cycle
,关键代码如下:
static void
ngx_worker_process_init(ngx_cycle_t *cycle, ngx_int_t worker)
{
... ...
for (i = 0; cycle->modules[i]; i++) {
if (cycle->modules[i]->init_process) {
if (cycle->modules[i]->init_process(cycle) == NGX_ERROR) {
/* fatal */
exit(2);
}
}
}
... ...
}
init_thread
接口
字面意思是初始化线程进程时候进行调用,但是暂未找到接口位置。
exit_thread
接口
字面意思是退出线程进程时候进行调用,但是暂未找到接口位置。
exit_process
接口
该接口于init_process
接口对应,其路径在:ngx_master_process_cycle>ngx_start_worker_processes>ngx_worker_process_exit
,条件是在出现中断,或者没有时间片的时候退出线程并调用。关键代码如下:
static void
ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data)
{
ngx_int_t worker = (intptr_t) data;
ngx_process = NGX_PROCESS_WORKER;
ngx_worker = worker;
ngx_worker_process_init(cycle, worker);
ngx_setproctitle("worker process");
for ( ;; ) {
if (ngx_exiting) {
if (ngx_event_no_timers_left() == NGX_OK) {
ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting");
ngx_worker_process_exit(cycle);
}
}
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "worker cycle");
ngx_process_events_and_timers(cycle);
if (ngx_terminate) {
ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting");
ngx_worker_process_exit(cycle);
}
}
... ...
}
exit_master
接口
该接口是当master
进程退出时调用,其路径在:ngx_master_process_cycle>ngx_master_process_exit
,关键代码如下:
void
ngx_master_process_cycle(ngx_cycle_t *cycle)
{
... ...
for ( ;; ) {
... ...
if (!live && (ngx_terminate || ngx_quit)) {
ngx_master_process_exit(cycle);
}
... ...
}
}
等于当出现退出或中断信号,或者进程不再存活的时候,进行退出操作。
总结
初次阅读nginx
源码,先从结构体开始学习,开篇之作,再接再厉。