博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
nginx事件模块 -- 第五篇 epoll add
阅读量:6266 次
发布时间:2019-06-22

本文共 4124 字,大约阅读时间需要 13 分钟。

微信公众号:

关注可了解更多的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; 4} else {
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; 6} epoll_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()方法中。我们随后会分析这个函数。


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

郑尔多斯

转载地址:http://yzjpa.baihongyu.com/

你可能感兴趣的文章
创建一个SimpleDlg
查看>>
使用XML生成菜单
查看>>
udp,tcp对于socket的写法
查看>>
第二周个人赛
查看>>
推断Windows版本号新方法
查看>>
2017-4-18 ADO.NET
查看>>
RSuite 一个基于 React.js 的 Web 组件库
查看>>
技术博客网址收藏
查看>>
python 金融分析学习
查看>>
授人以渔不如授人以鱼
查看>>
matlab练习程序(图像Haar小波变换)
查看>>
【Java】从域名得到ip
查看>>
Mysql索引会失效的几种情况分析
查看>>
LVM逻辑卷
查看>>
zoj3591 Nim(Nim博弈)
查看>>
canvas绘图
查看>>
poj - 3039 Margaritas on the River Walk
查看>>
bootstrap(5)关于导航
查看>>
Aptana插件在eclipse中安装
查看>>
jQuery-数据管理-删除事件
查看>>