Nginx如何解决事件过期问题

来源:互联网 发布:利用淘宝双十一赚钱 编辑:程序博客网 时间:2024/05/19 02:28

详细解释请参考《Nginx模块开发与架构解析》的9.6.3节ngx_epoll_module模块的实现

nginx源码如下:

struct ngx_event_s {    ......    /* used to detect the stale events in kqueue, rtsig, and epoll */    /*    这个标志位用于区分当前事件是否过期,它仅仅是给事件驱动模块使用的,而事件消费模块可不用关心。    为什么需要这个标志位呢?当开始处理一批事件时,处理前面的事件可能会关闭一些连接,而这些连接有可能影响这批事件中还未处理到的后面的事件。    这时,可通过instance标志位来避免处理后面的已经过期的事件。    */    unsigned         instance:1;    ......};


static ngx_int_tngx_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;#if (NGX_READ_EVENT != EPOLLIN)        events = EPOLLIN;#endif    } else {        e = c->read;        prev = EPOLLIN;#if (NGX_WRITE_EVENT != EPOLLOUT)        events = EPOLLOUT;#endif    }    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);    //这里利用了指针的最后一位一定是0的特性(因为CPU地址一定是2的倍数),用最后一位保存添加事件时的instance。    ngx_log_debug3(NGX_LOG_DEBUG_EVENT, ev->log, 0,                   "epoll add event: fd:%d op:%d ev:%08XD",                   c->fd, op, ee.events);    if (epoll_ctl(ep, op, c->fd, &ee) == -1) {        ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,                      "epoll_ctl(%d, %d) failed", op, c->fd);        return NGX_ERROR;    }    ev->active = 1;    return NGX_OK;}


ngx_connection_t *ngx_get_connection(ngx_socket_t s, ngx_log_t *log){    ngx_uint_t         instance;    ngx_event_t       *rev, *wev;    ngx_connection_t  *c;    ......    ngx_memzero(rev, sizeof(ngx_event_t));    ngx_memzero(wev, sizeof(ngx_event_t));    rev->instance = !instance;    wev->instance = !instance;    rev->index = NGX_INVALID_INDEX;    wev->index = NGX_INVALID_INDEX;    rev->data = c;    wev->data = c;    wev->write = 1;    return c;}


static ngx_int_tngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags){    int                events;    uint32_t           revents;    ngx_int_t          instance, i;    ngx_uint_t         level;    ngx_err_t          err;    ngx_event_t       *rev, *wev, **queue;    ngx_connection_t  *c;    /* NGX_TIMER_INFINITE == INFTIM */    //一开始就是等待事件,最长等待时间为timer;nginx为事件专门用红黑树维护了一个计时器    events = epoll_wait(ep, event_list, (int) nevents, timer);    ......    ngx_mutex_lock(ngx_posted_events_mutex);    //循环开始处理收到的所有事件    for (i = 0; i < events; i++) {        c = event_list[i].data.ptr;        instance = (uintptr_t) c & 1;        c = (ngx_connection_t *) ((uintptr_t) c & (uintptr_t) ~1);        rev = c->read;        //判断事件是否过期        if (c->fd == -1 || rev->instance != instance) {            /*             * the stale event from a file descriptor             * that was just closed in this iteration             */            ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,                           "epoll: stale event %p", c);            continue;        }        //取得发生一个事件        revents = event_list[i].events;        //该事件是一个读事件,并该连接上注册的读事件是active的        if ((revents & (EPOLLERR|EPOLLHUP))             && (revents & (EPOLLIN|EPOLLOUT)) == 0)        {            /*             * if the error events were returned without EPOLLIN or EPOLLOUT,             * then add these flags to handle the events at least in one             * active handler             */            revents |= EPOLLIN|EPOLLOUT;        }        if ((revents & EPOLLIN) && rev->active) {            if ((flags & NGX_POST_THREAD_EVENTS) && !rev->accept) {                rev->posted_ready = 1;            } else {                rev->ready = 1;            }            //事件放入到相应的队列中            if (flags & NGX_POST_EVENTS) {                queue = (ngx_event_t **) (rev->accept ?                               &ngx_posted_accept_events : &ngx_posted_events);                ngx_locked_post_event(rev, queue);            } else {                rev->handler(rev);            }        }        wev = c->write;        if ((revents & EPOLLOUT) && wev->active) {            if (c->fd == -1 || wev->instance != instance) {                /*                 * the stale event from a file descriptor                 * that was just closed in this iteration                 */                ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,                               "epoll: stale event %p", c);                continue;            }            if (flags & NGX_POST_THREAD_EVENTS) {                wev->posted_ready = 1;            } else {                wev->ready = 1;            }            if (flags & NGX_POST_EVENTS) {                ngx_locked_post_event(wev, &ngx_posted_events);            } else {                wev->handler(wev);            }        }    }    ngx_mutex_unlock(ngx_posted_events_mutex);    return NGX_OK;}

0 0
原创粉丝点击