事件驱动机制 nginx中事件驱动机制涉及到的模块很清晰, 在linux中为ngx_event_module、ngx_event_core_module、 ngx_epoll_module三个模块。 其中ngx_event_module负责解析event{}中的配置,并且调度其 它两个模块。 ngx_event_core_module负责调度epoll模块(use配置字段) epoll模块负责具体的事件处理 ngx_event.c文件中。 定义的 ngx_event_module ngx_event_core_module ngx_module_t ngx_event_module = { .....; &ngx_events_module_ctx; ngx_events_commands; .....; NULL; .....; } ngx_events_moudle_ctx上下文没有create_conf函数。 ngx_events_commands中有一个解析命令函数。 ngx_events_commands []={ { ngx_string(“event”); NGX_MAIN_CONF|...; ngx_events_block; 0. ... } } 即这个ngx_event_block函数, 这个函数在ngx_init_cycle函数中解析配置文件时候 调用ngx_conf_parse时,遇到“event”字样的时候, 被调用的。 该函数用于解析event{}中所有的配置。 1,创建配置指针放入cycle->ctx数组中。 2,调用所有事件模块(这里一般就两个event_core和epoll)的 create_conf创建各自需要的配置结构体 3,开始解析event{}中的所有配置, 4,调用所有事件模块的init_conf为各个事件模块的配置结构体 做最后的赋值.(其实也只有两个,即上面的两个) 基本上ngx_event_moudle的工作就全部在ngx_event_block中了。 再看ngx_event_core_module ngx_module_t ngx_event_core_module = { NGX_MODULE_V1, &ngx_event_core_module_ctx, ngx_event_core_commands, ..., ngx_event_module_init, ngx_event_process_init, ..., } 和ngx_event_module不同的是,它里面已经有很多回调函数了 按照顺序的调用,看看函数的调用顺序。 先看它的上下文 ngx_event_module_t ngx_event_core_module_ctx = { &event_core_name, ngx_event_create_conf, ngx_event_init_conf, } 因为在ngx_event_block中会回调这里的create_conf函数的 (当然,同时回调的还有epoll模块的create_conf,这里暂且不看) ngx_event_create_conf函数的工作: 当然主要是生成配置结构体ngx_event_conf_t类型, 这个是存放event{}中的各个字段的。 配置结构体生成后,接着是解析event{}中的配置了 这其中就会调用到很多ngx_event_core_module的commands 中的set函数。 具体有 ngx_event_connections, ngx_event_use, ngx_conf_set_flag_slot, ngx_conf_set_flag_slot, ngx_event_debug_connection, 这些函数都从配置中把数据存放在生成的配置结构体中。 接着的函数是init_conf了,也即完成配置结构体的赋值。。 走到这里,以event{}驱动的地方就完成了。 然后是ngx_event_core_moudle模块的初始化函数 ngx_event_module_init(在ngx_init_cycle中调用的, 当时是对整个模块数组都调用这个函数,不过没几个模块实现了 这个方法) 这个函数起始没做多少事情,它主要初始化了一些变量,尤其是 ngx_http_stub_status_module统计模块使用的一些原子性的统计 变量。 接着,前面都都是在master进程中完成的,下面fork出子进程之后, 在子进程的ngx_worker_process_cycle(这个是子进程的执行函数) ngx_worker_process_cycle->ngx_worker_process_init 后面的这个函数会一次调用每个模块的init_process方法。 这时候ngx_event_core_module模块的init_process方法 就被回调了(也即ngx_event_process_init)(好像只有这个模块 才实现了这个方法) ngx_event_process_init这个函数完成了大部分的事件驱动机制的初 始化工作,也是在这个函数中连接到了epoll模块中去。 这里要回顾一下前面的ngx_event_block中 因为在此函数中调用了epoll模块的create_conf函数。 那么先来看看epoll模块的定义 ngx_module_t ngx_epoll_module={ NGX_MOUDLE_V1, &ngx_epoll_module_ctx, ngx_epoll_commands; .....; } 看看ctx ngx_event_module_t ngx_epoll_module_ctx ={ &epoll_name, ngx_epoll_create_conf, ngx_epoll_init_conf, { ngx_epoll_add_event, ngx_epoll_del_event, ....; ngx_epoll_add_connection, ngx_epoll_del_connection, NULL, ngx_epoll_process_events, ngx_epoll_init, ngx_epoll_done, }, } 所有,这里先create_conf,很简单,创建epoll模块管理的配置结构体 ngx_epoll_conf_t类型。 回到ngx_event_process_init中。 1,调用use配置项指定的事件驱动模块的init方法 这里假设调用epoll模块中的action.init方法。 module->actions.init 此init即为ngx_epoll_init函数。 这里先看看这个函数,因为对下面的有引用 ngx_epoll_init做了两件事 1,调用epoll_create创建了epoll对象 2,创建evet_list数组,用于进行epoll_wait调用 时传递到内核态的事件 并且,在这里还初始化了几个全局变量,其中较为重要的 是ngx_event_actions=ngx_epoll_module_ctx.atcions 即把ngx_event_actions指明为epoll的actions。 这样以后就很方便的引用事件操作方法了 而且,还设计了宏定义 #define ngx_add_event ngx_event_actions.add #define ngx_del_event ngx_event_actions.del #define ngx_add_conn ngx_event_actions.add_conn .... 更加方便同一了。 2,分配连接池,读事件,写事件,并把它们想关联起来。 3,为listening套接子获取连接池(有可能很几个 监听套接子同时在监听),这样每个监听套接子就有了 相应的读写事件域(因为和connection关联的), 并设置其读事件的方法为ngx_event_accept方法。 此方法不属于任何模块,是单独的。 4,将监听连接的事件添加到事件驱动模块中即调用了 ngx_add_event方法。 到这里,ngx_event_process_init方法基本完成,即驱动机制 初始化完成。 下面就是利用驱动机制开始处理事件了。 要回到子进程中去。(ngx_worker_process_cycle) 在ngx_worker_process_init子进程初始化完了后,有一个 for循环 ,主要是分发、处理事件。 其核心就是ngx_process_events_and_timers方法。 该函数是事件驱动机制的核心,比较复杂。 其主要操作有3个 1,调用所使用的事件驱动模块实现的process_event方法,处理网络事件 (如果这里是epoll模块的话,那么这个process_event方法 就是ngx_event_actions.process_events也即ngx_epoll_process_events 方法。 2,处理两个post事件队列中的事件 ngx_event_process_posted(cycle,&ngx_posted_accept_events); ngx_event_process_posted(cycle,&ngx_posted_events); 3,处理定时器事件,ngx_event_expire_timers; 还有一个重点没有涉及到的即ngx_event_accept方法,用来建立新连接的 在上面有讲到过,它被注册为监听套接子 读事件的处理方法
ngx事件驱动机制
最新推荐文章于 2019-04-23 16:02:00 发布