接下来剖析模块的指令。模块的指令在源码中是ngx_command_t结构的变量,ngx_command_t的声明在src/core/ngx_conf_file.h中:
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;
};
name是指令名称的字符串,不包含空格。
type是标识符集,标识指令在配置文件中的合法位置和指令的参数个数。这是一个至少有32bit的无符号整形,前16bit用于标识位置,后16bit用于标识参数。
先看看参数的标识,宏定义在src/core/ngx_conf_file.h中:
#define NGX_CONF_NOARGS 0x00000001 (没有参数)
#define NGX_CONF_TAKE1 0x00000002 (有1个参数)
#define NGX_CONF_TAKE2 0x00000004 (有2个参数)
#define NGX_CONF_TAKE3 0x00000008 (有3个参数)
#define NGX_CONF_TAKE4 0x00000010 (有4个参数)
#define NGX_CONF_TAKE5 0x00000020 (有5个参数)
#define NGX_CONF_TAKE6 0x00000040 (有6个参数)
#define NGX_CONF_TAKE7 0x00000080 (有7个参数)
#define NGX_CONF_MAX_ARGS 8
#define NGX_CONF_TAKE12 (NGX_CONF_TAKE1|NGX_CONF_TAKE2) (有1个或者有2个参数)
#define NGX_CONF_TAKE13 (NGX_CONF_TAKE1|NGX_CONF_TAKE3)
#define NGX_CONF_TAKE23 (NGX_CONF_TAKE2|NGX_CONF_TAKE3)
#define NGX_CONF_TAKE123 (NGX_CONF_TAKE1|NGX_CONF_TAKE2|NGX_CONF_TAKE3)
#define NGX_CONF_TAKE1234 (NGX_CONF_TAKE1|NGX_CONF_TAKE2|NGX_CONF_TAKE3 \
|NGX_CONF_TAKE4)
#define NGX_CONF_ARGS_NUMBER 0x000000ff
#define NGX_CONF_BLOCK 0x00000100 (块域,后面跟{...},例如:events {...})
#define NGX_CONF_FLAG 0x00000200 (有一个布尔型参数)
#define NGX_CONF_ANY 0x00000400
#define NGX_CONF_1MORE 0x00000800 (至多有1个参数)
#define NGX_CONF_2MORE 0x00001000 (至多有2个参数)
#define NGX_CONF_MULTI 0x00002000
再看看位置的标识,位置的标识宏定义在几个文件中:
src/core/ngx_conf_file.h:
#define NGX_DIRECT_CONF 0x00010000
#define NGX_MAIN_CONF 0x01000000
#define NGX_ANY_CONF 0x0F000000
src/event/ngx_event.h:
#define NGX_EVENT_CONF 0x02000000
src/http/ngx_http_config.h:
#define NGX_HTTP_MAIN_CONF 0x02000000
#define NGX_HTTP_SRV_CONF 0x04000000
#define NGX_HTTP_LOC_CONF 0x08000000
#define NGX_HTTP_UPS_CONF 0x10000000
#define NGX_HTTP_SIF_CONF 0x20000000
#define NGX_HTTP_LIF_CONF 0x40000000
#define NGX_HTTP_LMT_CONF 0x80000000
src/mail/ngx_mail.h:
#define NGX_MAIL_MAIN_CONF 0x02000000
#define NGX_MAIL_SRV_CONF 0x04000000
要理解上面所谓的合法位置的真正含义,就要了解一下nginx的配置文件了,这里就不累述了,不影响下面的分析,我会在很后面的时候分析一下nginx的配置文件,因为那是一个big topic。
set是一个函数指针,这个函数主要是从配置文件中把该指令的参数(存放在ngx_conf_t中)转换为合适的数据类型并将转换后的值保存到模块的配置结构体中(void *conf),这个配置结构体又是用void *指向的,应该可以料到这说明每个模块的配置结构体是不同的,这些结构体命名格式为:ngx__conf_t,至于要把转换后的值放到配置结构体的什么位置,就要依靠offset了,offset是调用了offsetof函数计算出的结构体中某个成员的偏移位置。
并不是所有的模块都要定义一个配置结构体,因为set也可能是一个简单的操作函数,它可能只是从配置中(ngx_conf_t)读取一些数据进行简单的操作,比如errlog模块的“error_log”指令就是调用ngx_error_log写一条日志,并不需要存储什么配置数据。
conf和offset,offset前面已经提到,它是配置结构体中成员的偏移。conf也是一个偏移值,不过它是配置文件结构体的(ngx_conf_t)成员ctx的成员的偏移,一般是用来把ctx中指定偏移位置的成员赋值给void *conf。
post指向模块读配置的时候需要的一些零碎变量。
从上面的分析可以看出,每个模块会映射到配置文件中的某个位置,全局位置的配置会被下一级的配置继承,比如http_main会被http_svr继承,http_svr会被http_loc继承,这些继承在源码中是调用模块上下文的合并配置的接口完成的。
ngx_command_t的set成员也可以作为一个回调函数,通过把自定义的操作函数赋值给set来注册一些操作。
到目前为止,已经了解不少回调函数了,这些回调函数用来注册模块的自定义操作,我有时称它为接口,有时称它为回调函数,有点混乱,接下来的分析文章中,进行一下统一,全部称为钩子(hook)。把现在已经分析过的钩子罗列一下:
ngx_module_t -> init_master
ngx_module_t -> init_module
ngx_module_t -> init_process
ngx_module_t -> init_thread
ngx_module_t -> exit_thread
ngx_module_t -> exit_process
ngx_module_t -> exit_master
ngx_command_t -> set
下一篇剖析模块上下文的时候,会有更多的钩子,这就是为什么要对c语言的指针深入理解的原因了,nginx中到处都是钩子,假如要自己写一个模块,可以通过这些钩子把自己的模块挂到nginx的处理流中,参与到nginx运行的每个特定阶段,当然,也不是随意的嵌入,要精确定义模块何时如何产生作用才是有意义的,这不是一件轻松的事情。
阅读(1223) | 评论(0) | 转发(0) |