微信公众号:郑尔多斯
关注可了解更多的Nginx知识。任何问题或建议,请公众号留言;
关注公众号,有趣有内涵的文章第一时间送达!
剧情回顾
上一篇文章中我们详细介绍了Nginx
中事件模块的初始化过程。这里简单的回顾一下:Nginx
的worker
进程启动之后,会首先进行worker
的初始化,在初始化过程中将遍历调用所有模块的init_process
函数。与Nginx
事件机制相关的三个模块中,只有ngx_event_core_module
才实现了对应的钩子函数ngx_event_process_init
。上一篇文章我们已经比较详细的分析了这篇文章,但是还遗留了几个问题,比如,epoll
是如何初始化的,时间定时器是如何初始化的。本篇文章就分析一下epoll
是如何初始化的。
epoll初始化
首先观察ngx_event_process_init
下面的代码:
1for (m = 0; cycle->modules[m]; m++) {
2 if (cycle->modules[m]->type != NGX_EVENT_MODULE) {
3 continue;
4 }
5
6 if (cycle->modules[m]->ctx_index != ecf->use) {
7 continue;
8 }
9
10 module = cycle->modules[m]->ctx;
11
12 if (module->actions.init(cycle, ngx_timer_resolution) != NGX_OK) {
13 /* fatal */
14 exit(2);
15 }
16
17 break;
18 }
这部分代码就涵盖了epoll
的初始化过程,它是如何实现的呢?
遍历所有的模块,找到我们选择的事件处理模块,本例中就是
ngx_epoll
,然后调用时间模块的action.init()
方法。
下面我们看一下ngx_epoll
的源码:
1static ngx_event_module_t ngx_epoll_module_ctx = {
2 &epoll_name,
3 ngx_epoll_create_conf, /* create configuration */
4 ngx_epoll_init_conf, /* init configuration */
5
6 {
7 ngx_epoll_add_event, /* add an event */
8 ngx_epoll_del_event, /* delete an event */
9 ngx_epoll_add_event, /* enable an event */
10 ngx_epoll_del_event, /* disable an event */
11 ngx_epoll_add_connection, /* add an connection */
12 ngx_epoll_del_connection, /* delete an connection */
13#if (NGX_HAVE_EVENTFD)
14 ngx_epoll_notify, /* trigger a notify */
15#else
16 NULL, /* trigger a notify */
17#endif
18 ngx_epoll_process_events, /* process the events */
19 ngx_epoll_init, /* init the events */
20 ngx_epoll_done, /* done the events */
21 }
22};
从代码中可以看到,action.init()
对应于ngx_epoll_init()
,下面我们分析一下该函数
ngx_epoll_init
先看代码:
1static ngx_int_t
2ngx_epoll_init(ngx_cycle_t *cycle, ngx_msec_t timer)
3{
4 ngx_epoll_conf_t *epcf;
5
6 epcf = ngx_event_get_conf(cycle->conf_ctx, ngx_epoll_module);
7
8 if (ep == -1) {
9 ep = epoll_create(cycle->connection_n / 2);
10
11 if (ep == -1) {
12 ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
13 "epoll_create() failed");
14 return NGX_ERROR;
15 }
16
17#if (NGX_HAVE_EVENTFD)
18 if (ngx_epoll_notify_init(cycle->log) != NGX_OK) {
19 ngx_epoll_module_ctx.actions.notify = NULL;
20 }
21#endif
22
23#if (NGX_HAVE_FILE_AIO)
24 ngx_epoll_aio_init(cycle, epcf);
25#endif
26
27#if (NGX_HAVE_EPOLLRDHUP)
28 ngx_epoll_test_rdhup(cycle);
29#endif
30 }
31
32 if (nevents < epcf->events) {
33 if (event_list) {
34 ngx_free(event_list);
35 }
36
37 event_list = ngx_alloc(sizeof(struct epoll_event) * epcf->events,
38 cycle->log);
39 if (event_list == NULL) {
40 return NGX_ERROR;
41 }
42 }
43
44 nevents = epcf->events;
45
46 ngx_io = ngx_os_io;
47
48 ngx_event_actions = ngx_epoll_module_ctx.actions;
49
50#if (NGX_HAVE_CLEAR_EVENT)
51 ngx_event_flags = NGX_USE_CLEAR_EVENT
52#else
53 ngx_event_flags = NGX_USE_LEVEL_EVENT
54#endif
55 |NGX_USE_GREEDY_EVENT
56 |NGX_USE_EPOLL_EVENT;
57
58 return NGX_OK;
59}
这部分代码就是epoll
初始化的代码,我们可以清晰的理一下思路:
- 使用
epoll_create()
创建一个epoll
实例- 根据配置文件中
events
的数量创建对应数量的epoll_event
结构体- 设置一些全局变量的值,如
nevents
,ngx_io
,ngx_event_actions
- 这里有一个比较重要的变量就是
ngx_event_flags
,这个变量在后面经常使用到,通过调试发现该变量的值为:NGX_USE_CLEAR_EVENT | NGX_USE_GREEDY_EVENT | NGX_USE_EPOLL_EVENT
喜欢本文的朋友们,欢迎长按下图关注订阅号郑尔多斯,更多精彩内容第一时间送达