Nginx Intro - ngx_epoll_add_event


http://blog.youkuaiyun.com/brainkick/article/details/9080789


  1. static ngx_int_t  
  2. ngx_epoll_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)  
  3. {  
  4.     int                  op;  
  5.     uint32_t             events, prev;  
  6.     ngx_event_t         *e;  
  7.     ngx_connection_t    *c;  
  8.     struct epoll_event   ee;  
  9.   
  10.     c = ev->data;  
  11.   
  12.     events = (uint32_t) event;  
  13.   
  14.     if (event == NGX_READ_EVENT) {  
  15.         e = c->write;  
  16.         prev = EPOLLOUT;  
  17.     } else {  
  18.         e = c->read;  
  19.         prev = EPOLLIN;  
  20.     }  
  21.   
  22.     if (e->active) {  
  23.         op = EPOLL_CTL_MOD;  
  24.         events |= prev;  
  25.     } else {  
  26.         op = EPOLL_CTL_ADD;  
  27.     }  
  28.   
  29.     ee.events = events | (uint32_t) flags;  
  30.     ee.data.ptr = (void *) ((uintptr_t) c | ev->instance);  
  31.   
  32.   
  33.     if (epoll_ctl(ep, op, c->fd, &ee) == -1) {  
  34.         return NGX_ERROR;  
  35.     }  
  36.   
  37.     ev->active = 1;  
  38.   
  39.     return NGX_OK;  
  40. }  
这就是那个在群里被问了无数遍的函数,在讨论它之前,可以先来看下这个 http://blog.youkuaiyun.com/dingyujie/article/details/8570764,在这篇文章中特别强调了两个重要变量(即active和ready)的用途。看过之后,再来看这个函数。大家的问题主要是围绕在函数的开头:

为什么明明处理的是NGX_READ_EVENT,即所谓的读事件,为什么要去管c->write?即代码:
[cpp]  view plain  copy
 print ?
  1. if (event == NGX_READ_EVENT) {   
  2.     e = c->write;  
  3.     prev = EPOLLOUT;  
  4. else {  
  5.     e = c->read;  
  6.     prev = EPOLLIN;  
  7. }  
其实答案就跟在后面:
[cpp]  view plain  copy
 print ?
  1. if (e->active) {  
  2.     op = EPOLL_CTL_MOD;  
  3.     events |= prev;  
  4. else {  
  5.     op = EPOLL_CTL_ADD;  
  6. }  
结合这两段代码,意图就很明显了(明显吗?既然明显,为什么还有不少人在这里被绊住了呢?)。在epoll中监控读写事件时,主要通过接口epoll_ctl来处理。注意使用时有两种操作add和mod,当一个fd第一次注册到epoll时,使用add方式。而如果之前已经添加过对该fd读写事件的监控,就要通过mod来修改原来的监控方式,告知epoll我们的需求。如果一个fd被重复执行add会报错。
 
[cpp]  view plain  copy
 print ?
  1. man epoll:  
  2. Q:  What  happens  if you register the same file descriptor on an epoll  
  3.     instance twice?  
  4.    
  5. A: You will probably get EEXIST.  However, it is  possible  to  add  a  
  6.     duplicate  (dup(2),  dup2(2),  fcntl(2)  F_DUPFD) descriptor to the  
  7.     same epoll instance.  This can be a useful technique for  filtering  
  8.     events,  if the duplicate file descriptors are registered with dif-  
  9.     ferent events masks.  
  10.    
所以nginx这里就是为了避免这种情况,当要在epoll中加入对一个fd读事件(即NGX_READ_EVENT)的监听时,nginx先看一下与这个fd相关的写事件的状态,即e=c->write,如果此时e->active为1,说明该fd之前已经以NGX_WRITE_EVENT方式被加到epoll中了,此时只需要使用mod方式,将我们的需求加进去,否则才使用add方式,将该fd注册到epoll中。反之处理NGX_WRITE_EVENT时道理是一样的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值