nginx源码分析--event事件驱动初始化

来源:互联网 发布:js img onload 编辑:程序博客网 时间:2024/06/05 10:59
1.在nginx.c中设置每个核心模块的index
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. ngx_max_module = 0;  
  2. for (i = 0; ngx_modules[i]; i++) {  
  3.     ngx_modules[i]->index = ngx_max_module++;  
  4. }  

2.进入函数ngx_init_cycle,调用每个核心模块的create_conf
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. for (i = 0; ngx_modules[i]; i++) {  
  2.         if (ngx_modules[i]->type != NGX_CORE_MODULE) {  
  3.             continue;  
  4.         }  
  5.   
  6.         module = ngx_modules[i]->ctx;  
  7.   
  8.         if (module->create_conf) {  
  9.             rv = module->create_conf(cycle);//  
  10.             if (rv == NULL) {  
  11.                 ngx_destroy_pool(pool);  
  12.                 return NULL;  
  13.             }  
  14.             cycle->conf_ctx[ngx_modules[i]->index] = rv;  
  15.         }  
  16.     }  

3.在函数ngx_init_cycle中调用函数ngx_conf_pararm创建一个解析配置信息用的临时buffer
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. ngx_conf_param(&conf)  

4.调用ngx_conf_param设置解析需要的关键字
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. enum {  
  2.         parse_file = 0,  
  3.         parse_block,  
  4.         parse_param  
  5.     } type;  

5.调用ngx_conf_parse(&conf, &cycle->conf_file)函数解析核心模块配置文件:
注意:这里的ngx_conf_parse函数确实仅仅处理了核心模块的配置文件.他每次读到一个token(ngx_conf_read_token),就解析一个token(ngx_conf_handler)
    
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1.   rc = ngx_conf_read_token(cf); //读取token  
  2.   
  3.          /* 返回值: 
  4.          * ngx_conf_read_token() may return 
  5.          * 
  6.          *    NGX_ERROR             there is error 
  7.          *    NGX_OK                the token terminated by ";" was found 
  8.          *    NGX_CONF_BLOCK_START  the token terminated by "{" was found 
  9.          *    NGX_CONF_BLOCK_DONE   the "}" was found 
  10.          *    NGX_CONF_FILE_DONE    the configuration file is done 
  11.          */  
  12.       
  13. rc = ngx_conf_handler(cf, rc); //处理token   

6.进入ngx_conf_handler中,看一下关键代码
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. .............  
  2. cmd = ngx_modules[i]->commands;  
  3. .........  
  4. rv = cmd->set(cf, cmd, conf);  
  5. ................  

7.为了弄懂这几句是干什么的,我们先来看一下ngx_modules是什么
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. struct ngx_module_s {  
  2.     ngx_uint_t            ctx_index;  
  3.     ngx_uint_t            index;  
  4. ............  
  5.     void                 *ctx;  
  6.     ngx_command_t        *commands;  
  7.     ngx_uint_t            type;  
  8.   .............  
  9. };  

8.我们以前讲过,每个模块都会实现自己的ngx_module_s 
那么我么再来看一下event是怎么具体实现的:
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. ngx_module_t  ngx_events_module = {  
  2.     NGX_MODULE_V1,  
  3.     &ngx_events_module_ctx,                /* module context */  
  4.     ngx_events_commands,                   /* module directives */  
  5.     NGX_CORE_MODULE,                       /* module type */  
  6. ....................  
  7. };  

9.我们再来看一下cmd是什么结构体:
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. struct ngx_command_s {  
  2.     ngx_str_t             name;  
  3.     ngx_uint_t            type;  
  4.     char               *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);  
  5.     ngx_uint_t            conf;  
  6.     ngx_uint_t            offset;  
  7.     void                 *post;  
  8. };  

10.我们再来看一下event是怎么实现command的:
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. static ngx_command_t  ngx_events_commands[] = {  
  2.     { ngx_string("events"),  
  3.       NGX_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,  
  4.       ngx_events_block,  
  5. ........  
  6. };  

11.我们在第六步中那几个语句,现在可以回头看一下,那几条语句做了什么是不是很清晰.好了我们在这里再讲一下第六步.
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. //将cmd指向command  
  2. cmd = ngx_modules[i]->commands;  
  3. //回调函数,对每个模块进行具体配置  
  4. rv = cmd->set(cf, cmd, conf);  

12.对于核心模块event,调用ngx_events_block钩子函数,我们开始解析一下这个函数都干了什么:
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. static char *  
  2.                  ngx_events_block(ngx_conf_t *cf , ngx_command_t *cmd, void *conf)  
  3. {  
  4.                  char                 * rv;  
  5.                  void               *** ctx;  
  6.                 ngx_uint_t            i;  
  7.                 ngx_conf_t            pcf;  
  8.                 ngx_event_module_t   * m;  
  9.   
  10.                  if (*(void **) conf) {  
  11.                                  return "is duplicate" ;  
  12.                 }  
  13.   
  14.                  /* count the number of the event modules and set up their indices */  
  15.                  //初始化所有事件模块的ctx_index  
  16.                 ngx_event_max_module = 0;  
  17.                  for (i = 0; ngx_modules[i]; i++) {  
  18.                                  if (ngx_modules[i ]->type != NGX_EVENT_MODULE) {  
  19.                                                  continue;  
  20.                                 }  
  21.   
  22.                                 ngx_modules[ i]->ctx_index = ngx_event_max_module++;  
  23.                 }  
  24.   
  25.                  //创建配置需要的结构体空间  
  26.                  ctx = ngx_pcalloc(cf ->pool, sizeofvoid *));  
  27.                  if (ctx == NULL) {  
  28.                                  return NGX_CONF_ERROR;  
  29.                 }  
  30.   
  31.                 * ctx = ngx_pcalloc(cf ->pool, ngx_event_max_module * sizeof(void *));  
  32.                  if (*ctx == NULL) {  
  33.                                  return NGX_CONF_ERROR;  
  34.                 }  
  35.   
  36.                 *( void **) conf = ctx;  
  37.   
  38.                  //调用所有事件模块的create_conf  
  39.                  for (i = 0; ngx_modules[i]; i++) {  
  40.                                  if (ngx_modules[i ]->type != NGX_EVENT_MODULE) {  
  41.                                                  continue;  
  42.                                 }  
  43.   
  44.                                  m = ngx_modules[i ]->ctx;  
  45.   
  46.                                  if (m ->create_conf) {  
  47.                                                 (* ctx)[ngx_modules[i ]->ctx_index] = m->create_conf (cf-> cycle);  
  48.                                                  if ((*ctx )[ngx_modules[i]-> ctx_index] == NULL ) {  
  49.                                                                  return NGX_CONF_ERROR;  
  50.                                                 }  
  51.                                 }  
  52.                 }  
  53.   
  54.                  pcf = *cf ;  
  55.                  cf->ctx = ctx;  
  56.                  cf->module_type = NGX_EVENT_MODULE;  
  57.                  cf->cmd_type = NGX_EVENT_CONF;  
  58.   
  59.                  //为模块event所有模块解析配置  
  60.                  rv = ngx_conf_parse(cf , NULL);  
  61.   
  62.                 * cf = pcf ;  
  63.   
  64.                  if (rv != NGX_CONF_OK)  
  65.                                  return rv ;  
  66.   
  67.                  //为event所有模块调用init_conf  
  68.                  for (i = 0; ngx_modules[i]; i++) {  
  69.                                  if (ngx_modules[i ]->type != NGX_EVENT_MODULE) {  
  70.                                                  continue;  
  71.                                 }  
  72.   
  73.                                  m = ngx_modules[i ]->ctx;  
  74.   
  75.                                  if (m ->init_conf) {  
  76.                                                  rv = m ->init_conf( cf->cycle , (*ctx)[ngx_modules[ i]->ctx_index ]);  
  77.                                                  if (rv != NGX_CONF_OK) {  
  78.                                                                  return rv ;  
  79.                                                 }  
  80.                                 }  
  81.                 }  
  82.   
  83.                  return NGX_CONF_OK;  
  84. }  

13.在第11步中,循环调用所有模块的command函数(set钩子),仅仅初始化每个核心模块的配置.然后每个核心模块在递归调用ngx_conf_parse函数,对子模块进行配置.对于event模块来说,必须先初始化ngx_events_module,然后初始化ngx_event_core_module,对于其他event模块就没有强烈的顺序要求.原因:第一个初始化ngx_events_module模块,会对event子模块进行配置,然后才可以使用子模块.但是为什么在event子模块中,必须先调用ngx_event_core_module模块呢?
我们来具体看一下ngx_event_core_module结构体中的ngx_event_core_commands结构:
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. static ngx_command_t  ngx_event_core_commands[] = {  
  2.      //连接池的大小,即每个worker进程中支持的最大连接数  
  3.      //他与下面的connections配置项的意义是重复的  
  4.     { ngx_string("worker_connections"),  
  5.       NGX_EVENT_CONF|NGX_CONF_TAKE1,  
  6.       ngx_event_connections,  
  7.       0,  
  8.       0,  
  9.       NULL },  
  10.   
  11. //连接池的大小,与上一项配置重复  
  12.     { ngx_string("connections"),  
  13.       NGX_EVENT_CONF|NGX_CONF_TAKE1,  
  14.       ngx_event_connections,  
  15.       0,  
  16.       0,  
  17.       NULL },  
  18.   
  19. //确定哪一个事件模块作为事件驱动机制  
  20.     { ngx_string("use"),  
  21.       NGX_EVENT_CONF|NGX_CONF_TAKE1,  
  22.       ngx_event_use,  
  23.       0,  
  24.       0,  
  25.       NULL },  
  26.   
  27.      //对于epoll事件驱动模式来说,当接收一个新链接事件时候,  
  28.      //调用accept尽可能多的接收连接  
  29.     { ngx_string("multi_accept"),  
  30.       NGX_EVENT_CONF|NGX_CONF_FLAG,  
  31.       ngx_conf_set_flag_slot,  
  32.       0,  
  33.       offsetof(ngx_event_conf_t, multi_accept),  
  34.       NULL },  
  35.   
  36.     //确定是否使用负载均衡锁,默认开启  
  37.     { ngx_string("accept_mutex"),  
  38.       NGX_EVENT_CONF|NGX_CONF_FLAG,  
  39.       ngx_conf_set_flag_slot,  
  40.       0,  
  41.       offsetof(ngx_event_conf_t, accept_mutex),  
  42.       NULL },  
  43.      //启动负载均衡锁以后,延迟accept_mutex_delay毫秒以后再进行连接  
  44.     { ngx_string("accept_mutex_delay"),  
  45.       NGX_EVENT_CONF|NGX_CONF_TAKE1,  
  46.       ngx_conf_set_msec_slot,  
  47.       0,  
  48.       offsetof(ngx_event_conf_t, accept_mutex_delay),  
  49.       NULL },  
  50.   
  51.      //对于来自指定ip的连接需要打印debug级别的日志.  
  52.     { ngx_string("debug_connection"),  
  53.       NGX_EVENT_CONF|NGX_CONF_TAKE1,  
  54.       ngx_event_debug_connection,  
  55.       0,  
  56.       0,  
  57.       NULL },  
  58.   
  59.       ngx_null_command  
  60. };  
     我们看到了ngx_event_core_commands定义了于配置相关的信息,他会选择各种机制进行相应配置,所以必须优先进行初始化才能保证模块的正常运行.

14.下面我们看一下该模块定义的用于存储配置项的结构体.每个event子模块的配置文件都会存储在一个叫做ngx_event_conf_t的结构体中.
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. typedef struct {  
  2.     //连接池大小  
  3.     ngx_uint_t    connections;  
  4.     //选用的事件模块在所有事件模块的编号,即ctx_index  
  5.     ngx_uint_t    use;  
  6.     //标志位,若为1,则在接收一个连接事件时候,一次性尽可能建立多个连接  
  7.     ngx_flag_t    multi_accept;  
  8.     //标志位,为1时候采用负载均衡锁  
  9.     ngx_flag_t    accept_mutex;  
  10.     //负载均衡锁会使有些worker进程在拿不到锁的时候延迟一段时间  
  11.     //这段时间就是用accept_mutex_delay表示的  
  12.     ngx_msec_t    accept_mutex_delay;  
  13.     //所选用的事件模块的名字,他与use是匹配的.  
  14.     u_char       *name;  
  15. } ngx_event_conf_t;  

每个事件模块上下文(ctx)都要会指向一个ngx_event_module_t结构体(即每个event模块都要实现一个ngx_event_module_t接口),用于具体定义该模块操作.
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. ngx_event_module_t  ngx_event_core_module_ctx = {  
  2.     &event_core_name,  
  3.     ngx_event_core_create_conf,            /* create configuration */  
  4.     ngx_event_core_init_conf,              /* init configuration */  
  5.   
  6.     { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }  
  7. };  

最后我们再来看一下ngx_event_core_module 的定义.
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. ngx_module_t  ngx_event_core_module = {  
  2.     NGX_MODULE_V1,  
  3.     &ngx_event_core_module_ctx,            /* module context */  
  4.     ngx_event_core_commands,               /* module directives */  
  5.     NGX_EVENT_MODULE,                      /* module type */  
  6.     NULL,                                  /* init master */  
  7.     ngx_event_module_init,                 /* init module */  
  8.     ngx_event_process_init,                /* init process */  
  9.     NULL,                                  /* init thread */  
  10.     NULL,                                  /* exit thread */  
  11.     NULL,                                  /* exit process */  
  12.     NULL,                                  /* exit master */  
  13.     NGX_MODULE_V1_PADDING  
  14. };  

15.在ngx_cycle_init函数中找到如下代码: 
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. //调用所有模块的init_module  
  2.  for (i = 0; ngx_modules[i]; i++) {  
  3.      if (ngx_modules[i]->init_module) {  
  4.          if (ngx_modules[i]->init_module(cycle) != NGX_OK) {  
  5.              /* fatal */  
  6.              exit(1);  
  7.          }  
  8.      }  
  9.  }  
对于event来说则是调用ngx_event_module_init函数:
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. //src/event/ngx_event.c  
  2. static ngx_int_t  
  3. ngx_event_module_init(ngx_cycle_t *cycle)  
  4. {  
  5.     void              ***cf;  
  6.     u_char              *shared;  
  7.     size_t               size, cl;  
  8.     ngx_shm_t            shm;  
  9.     ngx_time_t          *tp;  
  10.     ngx_core_conf_t     *ccf;  
  11.     ngx_event_conf_t    *ecf;  
  12.       
  13.     //判断ngx_events_module是否调用过初始化conf操作  
  14.     cf = ngx_get_conf(cycle->conf_ctx, ngx_events_module);  
  15.   
  16.     if (cf == NULL) {  
  17.         ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,  
  18.                       "no \"events\" section in configuration");  
  19.         return NGX_ERROR;  
  20.     }  
  21.       
  22.     //获取ngx_event_core_module模块的配置结构  
  23.     ecf = (*cf)[ngx_event_core_module.ctx_index];  
  24.       
  25.     //查看是否是event中的模块,例如use 。。。。  
  26.     if (!ngx_test_config && ngx_process <= NGX_PROCESS_MASTER) {  
  27.         ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0,  
  28.                       "using the \"%s\" event method", ecf->name);  
  29.     }  
  30.     //获取ngx_core_module模块的配置结构  
  31.     ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);  
  32.       
  33.     //从ngx_core_module模块的配置结构中获取timer_resolution参数  
  34.     ngx_timer_resolution = ccf->timer_resolution;  
  35.   
  36. #if !(NGX_WIN32)  
  37.     {  
  38.     ngx_int_t      limit;  
  39.     struct rlimit  rlmt;  
  40.       
  41.     //获取当前进程能够打开的最大文件数     man getrlimit  
  42.     if (getrlimit(RLIMIT_NOFILE, &rlmt) == -1) {  
  43.         ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,  
  44.                       "getrlimit(RLIMIT_NOFILE) failed, ignored");  
  45.   
  46.     } else {  
  47.         //如果ngx_event_core_module模块连接数大于当前(软)限制  
  48.         //并且ngx_core_module最大连接数无限制  
  49.         //或者ngx_event_core_module连接数大于ngx_core_module最大连接数  
  50.         if (ecf->connections > (ngx_uint_t) rlmt.rlim_cur  
  51.             && (ccf->rlimit_nofile == NGX_CONF_UNSET  
  52.                 || ecf->connections > (ngx_uint_t) ccf->rlimit_nofile))  
  53.         {  
  54.             limit = (ccf->rlimit_nofile == NGX_CONF_UNSET) ?  
  55.                          (ngx_int_t) rlmt.rlim_cur : ccf->rlimit_nofile;  
  56.   
  57.             ngx_log_error(NGX_LOG_WARN, cycle->log, 0,  
  58.                           "%ui worker_connections are more than "  
  59.                           "open file resource limit: %i",  
  60.                           ecf->connections, limit);  
  61.         }  
  62.     }  
  63.     }  
  64. #endif /* !(NGX_WIN32) */  
  65.   
  66.     //如果关闭了master进程,就返回  
  67.     //因为关闭了master进程就是单进程工作方式,  
  68.     //之后的操作时创建共享内存实现锁等工作,单进程不需要。  
  69.     if (ccf->master == 0) {  
  70.         return NGX_OK;  
  71.     }  
  72.       
  73.     //如果已经存在accept互斥体了,不需要再重复创建了  
  74.     if (ngx_accept_mutex_ptr) {  
  75.         return NGX_OK;  
  76.     }  
  77.   
  78.   
  79.     /* cl should be equal or bigger than cache line size */  
  80.   
  81.     cl = 128;  
  82.     //这里创建size大小的共享内存,这块共享内存将被均分成三段  
  83.     size = cl            /* ngx_accept_mutex */  
  84.            + cl          /* ngx_connection_counter */  
  85.            + cl;         /* ngx_temp_number */  
  86.   
  87.     //准备共享内存,大小为size,命名nginx_shared_zone,  
  88.     shm.size = size;  
  89.     shm.name.len = sizeof("nginx_shared_zone");  
  90.     shm.name.data = (u_char *) "nginx_shared_zone";  
  91.     shm.log = cycle->log;  
  92.       
  93.     //创建共享内存,起始地址保存在shm.addr  
  94.     if (ngx_shm_alloc(&shm) != NGX_OK) {  
  95.         return NGX_ERROR;  
  96.     }  
  97.     //获取起始地址保存  
  98.     shared = shm.addr;  
  99.   
  100.     //accept互斥体取得共享内存的第一段cl大小内存  
  101.     ngx_accept_mutex_ptr = (ngx_atomic_t *) shared;  
  102.     ngx_accept_mutex.spin = (ngx_uint_t) -1;  
  103.     /*创建accept互斥体 
  104.      
  105.     accept互斥体的实现依赖是否支持原子操作,如果有相应的原子操作; 
  106.     就是用取得的这段共享内存来实现accept互斥体;否则,将使用文件锁 
  107.     来实现accept互斥体。 
  108.      
  109.     accept互斥体的作用是:避免惊群和实现worker进程的负载均衡。 
  110.      
  111.     */  
  112.     if (ngx_shmtx_create(&ngx_accept_mutex, shared, cycle->lock_file.data)  
  113.         != NGX_OK)  
  114.     {  
  115.         return NGX_ERROR;  
  116.     }  
  117.       
  118.     //获取内存的第二段cl大小的地址  
  119.     ngx_connection_counter = (ngx_atomic_t *) (shared + 1 * cl);  
  120.   
  121.     (void) ngx_atomic_cmp_set(ngx_connection_counter, 0, 1);  
  122.   
  123.     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,  
  124.                    "counter: %p, %d",  
  125.                    ngx_connection_counter, *ngx_connection_counter);  
  126.     //获取内存的第三段cl大小的地址  
  127.     ngx_temp_number = (ngx_atomic_t *) (shared + 2 * cl);  
  128.   
  129.     tp = ngx_timeofday();  
  130.   
  131.     ngx_random_number = (tp->msec << 16) + ngx_pid;  
  132.   
  133.     return NGX_OK;  
  134. }  

16.进入master或者signal工作模式后才调用ngx_event_process_init函数
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. //src/event/ngx_event.c  
  2. static ngx_int_t  
  3. ngx_event_process_init(ngx_cycle_t *cycle)  
  4. {  
  5.     ngx_uint_t           m, i;  
  6.     ngx_event_t         *rev, *wev;  
  7.     ngx_listening_t     *ls;  
  8.     ngx_connection_t    *c, *next, *old;  
  9.     ngx_core_conf_t     *ccf;  
  10.     ngx_event_conf_t    *ecf;  
  11.     ngx_event_module_t  *module;  
  12.       
  13.     //和之前一样,获取响应模块的配置结构  
  14.     ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);  
  15.     ecf = ngx_event_get_conf(cycle->conf_ctx, ngx_event_core_module);  
  16.       
  17.     //master进程打开,worker进程大于1,已经创建了accept_mutex  
  18.     //才打开accept互斥体  
  19.     if (ccf->master && ccf->worker_processes > 1 && ecf->accept_mutex) {  
  20.         ngx_use_accept_mutex = 1; //使用互斥体  
  21.         ngx_accept_mutex_held = 0; //是否获得accept互斥体  
  22.         ngx_accept_mutex_delay = ecf->accept_mutex_delay;//争抢互斥体失败后,等待下次争抢时间间隔  
  23.   
  24.     } else {  
  25.         ngx_use_accept_mutex = 0;  
  26.     }  
  27.   
  28. #if (NGX_THREADS)  
  29.     //线程先不讲  
  30. #endif  
  31.     //初始化计数器,此处将会创建一颗红黑树,来维护计时器,之后会详细讲解  
  32.     if (ngx_event_timer_init(cycle->log) == NGX_ERROR) {  
  33.         return NGX_ERROR;  
  34.     }  
  35.   
  36.     for (m = 0; ngx_modules[m]; m++) {  
  37.         //这里之前讲过,跳过非NGX_EVENT_MODULE模块  
  38.         if (ngx_modules[m]->type != NGX_EVENT_MODULE) {  
  39.             continue;  
  40.         }  
  41.         //非use配置指令指定的模块跳过,linux默认epoll  
  42.         if (ngx_modules[m]->ctx_index != ecf->use) {  
  43.             continue;  
  44.         }  
  45.   
  46.         module = ngx_modules[m]->ctx;  
  47.         /*调用具体时间模块的init函数 
  48.          
  49.         由于nginx实现了很多事件模块,比如:epoll、poll、select、dqueue、aio 
  50.         (这些模块位于src/event/modules目录中),所以nginx对时间模块进行了一层抽象, 
  51.         方便了不同的系统使用不同的事件模型,也便于扩展新的时间模型,我们的重点应该 
  52.         放在epoll上。 
  53.          
  54.         此处的init回调,其实就是调用了ngx_epoll_init函数。module->actions结构封装了 
  55.         epoll的所有接口函数。nginx就是通过actions结构将epoll注册到事件抽象层中。 
  56.         actions的类型是ngx_event_action_t,位于src/event/ngx_event.h 
  57.          
  58.         这些具体的内容会在下一节中重点讲解。 
  59.          
  60.         */  
  61.         if (module->actions.init(cycle, ngx_timer_resolution) != NGX_OK) {  
  62.             /* fatal */  
  63.             exit(2);  
  64.         }  
  65.   
  66.         break;  
  67.     }  
  68. //此处省略部分内容  
  69.     //创建全局的ngx_connection_t数组,保存所有的connection  
  70.     //由于这个过程是在各个worker进程中执行的,所以每个worker都有自己的connection数组  
  71.     cycle->connections =  
  72.         ngx_alloc(sizeof(ngx_connection_t) * cycle->connection_n, cycle->log);  
  73.     if (cycle->connections == NULL) {  
  74.         return NGX_ERROR;  
  75.     }  
  76.   
  77.     c = cycle->connections;  
  78.       
  79.     //创建一个读事件数组  
  80.     cycle->read_events = ngx_alloc(sizeof(ngx_event_t) * cycle->connection_n,  
  81.                                    cycle->log);  
  82.     if (cycle->read_events == NULL) {  
  83.         return NGX_ERROR;  
  84.     }  
  85.   
  86.     rev = cycle->read_events;  
  87.     for (i = 0; i < cycle->connection_n; i++) {  
  88.         rev[i].closed = 1;  
  89.         rev[i].instance = 1;  
  90. #if (NGX_THREADS)  
  91.         rev[i].lock = &c[i].lock;  
  92.         rev[i].own_lock = &c[i].lock;  
  93. #endif  
  94.     }  
  95.     //创建一个写事件数组  
  96.     cycle->write_events = ngx_alloc(sizeof(ngx_event_t) * cycle->connection_n,  
  97.                                     cycle->log);  
  98.     if (cycle->write_events == NULL) {  
  99.         return NGX_ERROR;  
  100.     }  
  101.   
  102.     wev = cycle->write_events;  
  103.     for (i = 0; i < cycle->connection_n; i++) {  
  104.         wev[i].closed = 1;  
  105. #if (NGX_THREADS)  
  106.         wev[i].lock = &c[i].lock;  
  107.         wev[i].own_lock = &c[i].lock;  
  108. #endif  
  109.     }  
  110.   
  111.     i = cycle->connection_n;  
  112.     next = NULL;  
  113.     //初始化整个connection数组  
  114.     do {  
  115.         i--;  
  116.   
  117.         c[i].data = next;  
  118.         c[i].read = &cycle->read_events[i];  
  119.         c[i].write = &cycle->write_events[i];  
  120.         c[i].fd = (ngx_socket_t) -1;  
  121.   
  122.         next = &c[i];  
  123.   
  124. #if (NGX_THREADS)  
  125.         c[i].lock = 0;  
  126. #endif  
  127.     } while (i);  
  128.   
  129.     cycle->free_connections = next;  
  130.     cycle->free_connection_n = cycle->connection_n;  
  131.   
  132.     /* for each listening socket */  
  133.     //为每个监听套接字从connection数组中分配一个连接,即一个slot  
  134.     ls = cycle->listening.elts;  
  135.     for (i = 0; i < cycle->listening.nelts; i++) {  
  136.         //从conneciton中取得一个新的连接solt  
  137.         c = ngx_get_connection(ls[i].fd, cycle->log);  
  138.   
  139.         if (c == NULL) {  
  140.             return NGX_ERROR;  
  141.         }  
  142.   
  143.         c->log = &ls[i].log;  
  144.   
  145.         c->listening = &ls[i];  
  146.         ls[i].connection = c;  
  147.   
  148.         rev = c->read;  
  149.   
  150.         rev->log = c->log;  
  151.         rev->accept = 1; //读时间发生,调用accept  
  152.   
  153. #if (NGX_HAVE_DEFERRED_ACCEPT)  
  154.         //省略  
  155. #endif  
  156.   
  157.         if (!(ngx_event_flags & NGX_USE_IOCP_EVENT)) {  
  158.             if (ls[i].previous) {  
  159.   
  160.                 /* 
  161.                  * delete the old accept events that were bound to 
  162.                  * the old cycle read events array 
  163.                  */  
  164.   
  165.                 old = ls[i].previous->connection;  
  166.   
  167.                 if (ngx_del_event(old->read, NGX_READ_EVENT, NGX_CLOSE_EVENT)  
  168.                     == NGX_ERROR)  
  169.                 {  
  170.                     return NGX_ERROR;  
  171.                 }  
  172.   
  173.                 old->fd = (ngx_socket_t) -1;  
  174.             }  
  175.         }  
  176.   
  177.         //注册监听套接口毒事件的回调函数 ngx_event_accept  
  178.         rev->handler = ngx_event_accept;  
  179.           
  180.         //使用了accept_mutex,暂时不将监听套接字放入epoll中,而是  
  181.         //等到worker抢到accept互斥体后,再放入epoll,避免惊群的发生  
  182.         if (ngx_use_accept_mutex) {  
  183.             continue;  
  184.         }  
  185.           
  186.           
  187.         if (ngx_event_flags & NGX_USE_RTSIG_EVENT) {  
  188.             if (ngx_add_conn(c) == NGX_ERROR) {  
  189.                 return NGX_ERROR;  
  190.             }  
  191.   
  192.         } else {  
  193.             //没有使用accept互斥体,那么就将此监听套接字放入epoll中。  
  194.             if (ngx_add_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) {  
  195.                 return NGX_ERROR;  
  196.             }  
  197.         }  
  198.   
  199. #endif  
  200.   
  201.     }  
  202.   
  203.     return NGX_OK;  
  204. }  


转自:http://blog.csdn.net/yusiguyuan/article/details/24384577

0 0
原创粉丝点击