nginx事件模块 -- 第五篇 epoll add

微信公众号:郑尔多斯
关注可了解更多的Nginx知识。任何问题或建议,请公众号留言;
关注公众号,有趣有内涵的文章第一时间送达!

内容回顾

上一篇文章我们介绍了Nginxepoll初始化过程。从这一篇文章开始我们继续介绍ngx_epoll_module的源码,包括添加事件,删除事件,触发事件等。

ngx_epoll_module_ctx源码

 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};
复制代码

添加新事件

从上面的源码中我们可以知道,epoll添加事件的方法为ngx_epoll_add_event,源码如下:

 1static ngx_int_t
2ngx_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#if (NGX_READ_EVENT != EPOLLIN|EPOLLRDHUP)
18        events = EPOLLIN|EPOLLRDHUP;
19#endif
20
21    } else {
22        e = c->read;
23        prev = EPOLLIN|EPOLLRDHUP;
24#if (NGX_WRITE_EVENT != EPOLLOUT)
25        events = EPOLLOUT;
26#endif
27    }
28
29    if (e->active) {
30        op = EPOLL_CTL_MOD;
31        events |= prev;
32
33    } else {
34        op = EPOLL_CTL_ADD;
35    }
36
37#if (NGX_HAVE_EPOLLEXCLUSIVE && NGX_HAVE_EPOLLRDHUP)
38    if (flags & NGX_EXCLUSIVE_EVENT) {
39        events &= ~EPOLLRDHUP;
40    }
41#endif
42
43    ee.events = events | (uint32_t) flags;
44    ee.data.ptr = (void *) ((uintptr_t) c | ev->instance);
45
46    if (epoll_ctl(ep, op, c->fd, &ee) == -1) {
47        return NGX_ERROR;
48    }
49
50    ev->active = 1;
51    return NGX_OK;
52}
复制代码

该函数的三个参数功能如下:

ev:我们要添加的事件
event: 事件的类型,读事件或者写事件,我们这里分析read event,对于write event来说道理相同
flags: 添加事件的参数

我们这里只分析read event:
这里有一个问题,为什么添加read event的时候要判断c->write呢?

1 if (event == NGX_READ_EVENT) {
2        e = c->write;
3        prev = EPOLLOUT;
4#if (NGX_READ_EVENT != EPOLLIN|EPOLLRDHUP)
5        events = EPOLLIN|EPOLLRDHUP;
6#endif
7}
复制代码

其实结合后面的代码就很清楚了,我们看一下后面的代码:

1if (e->active) {
2        op = EPOLL_CTL_MOD;
3        events |= prev;
4else {
5        op = EPOLL_CTL_ADD;
6}
复制代码

因为往epoll中增加事件的时候,有两种方式,分别为 addmodify。当我们将某个fd添加read event的时候,如果该fdwrite event已经被添加到了epoll中,那么我们就不能继续add了,只能modify,所以这里要先判断一下write event的状态。
我们查看 man epoll手册,在Question and answers部分有下面一个Question,如下:

Q1 What happens if you register the same file descriptor on an epoll instance twice?
A1 You will probably get EEXIST. However, it is possible to add a duplicate (dup(2), dup2(2), fcntl(2) F_DUPFD) descriptor to t

这里有一点要注意,那就是我们添加的eventdata字段,我们先看一下epoll函数中event的结构:

 1 typedef union epoll_data {
2     void        *ptr;
3     int          fd;
4     uint32_t     u32;
5     uint64_t     u64;
6epoll_data_t;
7
8struct epoll_event {
9    uint32_t     events;      /* Epoll events */
10    epoll_data_t data;        /* User data variable */
11};
复制代码

ngx_epoll_add_event()函数中有下面一句话:

1ee.data.ptr = (void *) ((uintptr_t) c | ev->instance);
复制代码

这里会把 event->data->ptr指向当前事件对应的connection。这是一个很重要的特性。这样的话,当我们epoll_wait()获取到某个事件之后,就可以拿到这个事件对应的connection,然后进行各种操作。

这就是ngx_epoll_add_event()的处理流程,这里遗留了一个问题:
read event 或者 write eventdata字段是什么时候指向了connection呢?
其实是在 ngx_get_connection()方法中。我们随后会分析这个函数。


喜欢本文的朋友们,欢迎长按下图关注订阅号郑尔多斯,更多精彩内容第一时间送达

郑尔多斯
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值