现在的位置: 首页 > 综合 > 正文

关于ngx_epoll_add_event的一些解释

2013年09月09日 ⁄ 综合 ⁄ 共 1605字 ⁄ 字号 评论关闭
static ngx_int_t
ngx_epoll_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
{
    int                  op;
    uint32_t             events, prev;
    ngx_event_t         *e;
    ngx_connection_t    *c;
    struct epoll_event   ee;

    c = ev->data;

    events = (uint32_t) event;

    if (event == NGX_READ_EVENT) {
        e = c->write;
        prev = EPOLLOUT;
    } else {
        e = c->read;
        prev = EPOLLIN;
    }

    if (e->active) {
        op = EPOLL_CTL_MOD;
        events |= prev;
    } else {
        op = EPOLL_CTL_ADD;
    }

    ee.events = events | (uint32_t) flags;
    ee.data.ptr = (void *) ((uintptr_t) c | ev->instance);


    if (epoll_ctl(ep, op, c->fd, &ee) == -1) {
        return NGX_ERROR;
    }

    ev->active = 1;

    return NGX_OK;
}
这就是那个在群里被问了无数遍的函数,在讨论它之前,可以先来看下这个http://blog.csdn.net/dingyujie/article/details/8570764,在这篇文章中特别强调了两个重要变量(即active和ready)的用途。看过之后,再来看这个函数。大家的问题主要是围绕在函数的开头:
为什么明明处理的是NGX_READ_EVENT,即所谓的读事件,为什么要去管c->write?即代码:
if (event == NGX_READ_EVENT) { 
    e = c->write;
    prev = EPOLLOUT;
} else {
    e = c->read;
    prev = EPOLLIN;
}
其实答案就跟在后面:
if (e->active) {
    op = EPOLL_CTL_MOD;
    events |= prev;
} else {
    op = EPOLL_CTL_ADD;
}
结合这两段代码,意图就很明显了(明显吗?既然明显,为什么还有不少人在这里被绊住了呢?)。在epoll中监控读写事件时,主要通过接口epoll_ctl来处理。注意使用时有两种操作add和mod,当一个fd第一次注册到epoll时,使用add方式。而如果之前已经添加过对该fd读写事件的监控,就要通过mod来修改原来的监控方式,告知epoll我们的需求。如果一个fd被重复执行add会报错。
 
man epoll:
Q:  What  happens  if you register the same file descriptor on an epoll
    instance twice?
 
A: You will probably get EEXIST.  However, it is  possible  to  add  a
    duplicate  (dup(2),  dup2(2),  fcntl(2)  F_DUPFD) descriptor to the
    same epoll instance.  This can be a useful technique for  filtering
    events,  if the duplicate file descriptors are registered with dif-
    ferent events masks.
 
所以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时道理是一样的。

抱歉!评论已关闭.