nginx源码分析(8)-模块化(3)

接下来剖析模块的指令。模块的指令在源码中是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_<module name>_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运行的每个特定阶段,当然,也不是随意的嵌入,要精确定义模块何时如何产生作用才是有意义的,这不是一件轻松的事情。

go on

你可能感兴趣的:(nginx,struct,Module,command,hook,events)