Nginx event核心模块之epoll模块详解(二)

Nginx event核心模块之epoll模块详解(二)

在ngx_epoll_module中关于创建侦听SOCKET以及进程的SPAWN这里就先不讨论了。

以下讨论下epoll模块中各个函数的作用以及关系。

主要是以下这几个函数:

static ngx_int_tngx_epoll_init(ngx_cycle_t *cycle, ngx_msec_t timer);//主要用于初始化epoll的基本信息,比如epoll_create函数就在这里有调用。

{

    ngx_epoll_conf_t  *epcf;

    epcf =ngx_event_get_conf(cycle->conf_ctx, ngx_epoll_module);

    if (ep == -1) {

        ep = epoll_create(cycle->connection_n /2);//创建一个epoll的句柄,cycle->connection_n / 2告诉内核这个监听的数目一共有多大,出错则返回-1,成功则放回epoll句柄。

       ……

    if (nevents < epcf->events) {

        if (event_list) {

            ngx_free(event_list);

        }

        event_list = ngx_alloc(sizeof(structepoll_event) * epcf->events,

                               cycle->log);//创建事件空间

        if (event_list == NULL) {

            return NGX_ERROR;

        }

    }

    nevents = epcf->events;//事件最大数量

    ngx_io = ngx_os_io;

    ngx_event_actions =ngx_epoll_module_ctx.actions;//定义在ngx_event.c中,用于决定event模块中到底是采用epoll还是select以及其他….

 

#if(NGX_HAVE_CLEAR_EVENT)

    ngx_event_flags = NGX_USE_CLEAR_EVENT

#else

    ngx_event_flags = NGX_USE_LEVEL_EVENT

#endif

                      |NGX_USE_GREEDY_EVENT

                      |NGX_USE_EPOLL_EVENT;

 

    return NGX_OK;

}

static void ngx_epoll_done(ngx_cycle_t*cycle)//关闭epoll

{

    if (close(ep) == -1) {//epoll结束的时候close

        ngx_log_error(NGX_LOG_ALERT,cycle->log, ngx_errno,

                      "epoll close()failed");

    }

    ep = -1;//设置为-1,避免再次调用

……..

#if(NGX_HAVE_FILE_AIO)

……

#endif

    ngx_free(event_list);//释放事件空间

 

    event_list = NULL;//并把指针致为空

    nevents = 0;//事件数量设置为0

}

static ngx_int_tngx_epoll_add_event(ngx_event_t *ev, ngx_int_t event,

ngx_uint_tflags)

{

    int                  op;//操作符EPOLL_CTL_ADD EPOLL_CTL_DEL,EPOLL_CTL_MOD,这里主用是用ADDMOD

    uint32_t             events, prev;

    ngx_event_t         *e;

    ngx_connection_t    *c;

    struct epoll_event   ee;

    c = ev->data;//程序中一般把ngx_event_t结构中的data部分设置为ngx_connection_t数据

    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

    }//根据event变量设置读写事件,但为什么这里读事件会是写,写会是读呢?

 

    if (e->active) {//查看事件是否accept之后

        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);//ngx_connection_t数据添加到epoll_event中去

 

    ngx_log_debug3(NGX_LOG_DEBUG_EVENT,ev->log, 0,

                   "epoll add event: fd:%dop:%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;

#if 0

    ev->oneshot = (flags &NGX_ONESHOT_EVENT) ? 1 : 0;

#endif

 

    return NGX_OK;

}

static ngx_int_tngx_epoll_del_event(ngx_event_t *ev, ngx_int_t event,

ngx_uint_tflags)

int                  op;

    uint32_t             prev;

    ngx_event_t         *e;

    ngx_connection_t    *c;

    struct epoll_event   ee;

 

    /*

     * when the file descriptor is closed, theepoll automatically deletes

     * it from its queue, so we do not need todelete explicitly the event

     * before the closing the file descriptor

     */

 

    if (flags & NGX_CLOSE_EVENT) {//close 半关闭状态

        ev->active = 0;

        return NGX_OK;

    }

 

    c = ev->data;//连接数据

 

    if (event == NGX_READ_EVENT) {//客户端读事件,从而服务器写

        e = c->write;

        prev = EPOLLOUT;

 

    } else {//反之

        e = c->read;

        prev = EPOLLIN;

    }

 

    if (e->active) {//如果连接活动的。则修改

        op = EPOLL_CTL_MOD;

        ee.events = prev | (uint32_t) flags;

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

 

    } else {//反之删除

        op = EPOLL_CTL_DEL;

        ee.events = 0;

        ee.data.ptr = NULL;

    }

 

    ngx_log_debug3(NGX_LOG_DEBUG_EVENT,ev->log, 0,

                   "epoll del event: fd:%dop:%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 = 0;//设置为不可用

 

    return NGX_OK;

}

static ngx_int_tngx_epoll_add_connection(ngx_connection_t *c)

{

    struct epoll_event  ee;

 

    ee.events = EPOLLIN|EPOLLOUT|EPOLLET;

    ee.data.ptr = (void *) ((uintptr_t) c |c->read->instance);//ptr部分一般指向的是ngx_connection_t数据

 

    ngx_log_debug2(NGX_LOG_DEBUG_EVENT,c->log, 0,

                   "epoll add connection:fd:%d ev:%08XD", c->fd, ee.events);

 

    if (epoll_ctl(ep, EPOLL_CTL_ADD, c->fd,&ee) == -1) {//添加新的文件描述符到epoll数组中

        ngx_log_error(NGX_LOG_ALERT, c->log,ngx_errno,

                     "epoll_ctl(EPOLL_CTL_ADD, %d) failed", c->fd);

        return NGX_ERROR;

    }

 

    c->read->active = 1;

    c->write->active = 1;//设置读写激活

 

    return NGX_OK;

}

static ngx_int_tngx_epoll_del_connection(ngx_connection_t *c,

ngx_uint_tflags)

{

    int                 op;

    struct epoll_event  ee;

 

    /*

     * when the file descriptor is closed theepoll automatically deletes

     * it from its queue so we do not need todelete explicitly the event

     * before the closing the file descriptor

     */

 

    if (flags & NGX_CLOSE_EVENT) {//close 半关闭状态

        c->read->active = 0;

        c->write->active = 0;

        return NGX_OK;

    }

 

    ngx_log_debug1(NGX_LOG_DEBUG_EVENT,c->log, 0,

                   "epoll del connection:fd:%d", c->fd);

 

    op = EPOLL_CTL_DEL;//设置为删除操作

    ee.events = 0;

    ee.data.ptr = NULL;

 

    if (epoll_ctl(ep, op, c->fd, &ee) ==-1) {//event数组中删除该文件描述符

        ngx_log_error(NGX_LOG_ALERT, c->log,ngx_errno,

                      "epoll_ctl(%d, %d) failed", op,c->fd);

        return NGX_ERROR;

    }

 

    c->read->active = 0;

    c->write->active = 0;//设置连接不可用

 

    return NGX_OK;

}

 

staticngx_int_t

ngx_epoll_process_events(ngx_cycle_t*cycle, ngx_msec_t timer, ngx_uint_t flags)

//该函数会调用epoll_wait函数,并且会在进程中循环调用,为epoll核心函数

{

    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 */

 

    ngx_log_debug1(NGX_LOG_DEBUG_EVENT,cycle->log, 0,

                   "epoll timer: %M",timer);

 

    events = epoll_wait(ep, event_list, (int)nevents, timer);//timer数据是根据红黑树的原理进行计算的。以后进行详细讨论

 

    err = (events == -1) ? ngx_errno : 0;//出错时errno获取

 

    if (flags & NGX_UPDATE_TIME ||ngx_event_timer_alarm) {//ngx_current_msec更新

        ngx_time_update();

    }

 

    if (err) {

        if (err == NGX_EINTR) {//中断信号EINTR

 

            if (ngx_event_timer_alarm) {

                ngx_event_timer_alarm = 0;

                return NGX_OK;

            }

 

            level = NGX_LOG_INFO;

 

        } else {//警告信号

            level = NGX_LOG_ALERT;

        }

 

        ngx_log_error(level, cycle->log,err, "epoll_wait() failed");

        return NGX_ERROR;

    }//出错退出

 

    if (events == 0) {//相应的事件个数为0,timer时间到

        if (timer != NGX_TIMER_INFINITE){//timer不为无限大

            return NGX_OK;

        }

 

        ngx_log_error(NGX_LOG_ALERT,cycle->log, 0,

                      "epoll_wait()returned no events without timeout");

        return NGX_ERROR;

    }

 

    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);//根据epoll_event.data.ptr获取连接信息

 

        rev = c->read;//客户读请求

 

        if (c->fd == -1 || rev->instance!= instance) {

 

            /*

             * the stale event from a filedescriptor

             * that was just closed in thisiteration

             */

 

            ngx_log_debug1(NGX_LOG_DEBUG_EVENT,cycle->log, 0,

                           "epoll: staleevent %p", c);

            continue;

        }

 

        revents = event_list[i].events;//事件信号,EPOLLIN,EPOLLOUT.....

 

        ngx_log_debug3(NGX_LOG_DEBUG_EVENT,cycle->log, 0,

                       "epoll: fd:%dev:%04XD d:%p",

                       c->fd, revents,event_list[i].data.ptr);

 

        if (revents & (EPOLLERR|EPOLLHUP)){//事件信号为错误或挂断

            ngx_log_debug2(NGX_LOG_DEBUG_EVENT,cycle->log, 0,

                           "epoll_wait()error on fd:%d ev:%04XD",

                           c->fd, revents);

        }

 

#if 0

        if (revents &~(EPOLLIN|EPOLLOUT|EPOLLERR|EPOLLHUP)) {

            ngx_log_error(NGX_LOG_ALERT,cycle->log, 0,

                          "strangeepoll_wait() events fd:%d ev:%04XD",

                          c->fd, revents);

        }

#endif

 

        if ((revents & (EPOLLERR|EPOLLHUP))

             && (revents &(EPOLLIN|EPOLLOUT)) == 0)//事件出错挂断和事级读写不同时出现,则设置事件为读写

        {

            /*

             * if the error events werereturned without EPOLLIN or EPOLLOUT,

             * then add these flags to handlethe events at least in one

             * active handler

             */

 

            revents |= EPOLLIN|EPOLLOUT;

        }

 

        if ((revents & EPOLLIN) &&rev->active) {//事件可用且可读,处理事件

 

            if ((flags &NGX_POST_THREAD_EVENTS) && !rev->accept) {//事件没有被accept,这个位设置在event_init阶段

                rev->posted_ready = 1;//设置为posted事件

 

            } else {

                rev->ready = 1;//否则准备接受事件,进行处理

            }

 

            if (flags & NGX_POST_EVENTS) {

                queue = (ngx_event_t **)(rev->accept ?

                              &ngx_posted_accept_events : &ngx_posted_events);//是否为acceptevent,如果是acceptevent,则在主循环中处理,普通的也是如此

 

                ngx_locked_post_event(rev,queue);//把rev添加到queue中

 

            } else {

                rev->handler(rev);//事件处理

            }

        }

 

        wev = c->write;//写事件

 

        if ((revents & EPOLLOUT) &&wev->active) {//事件可用且为EPOLLOUT

 

            if (c->fd == -1 ||wev->instance != instance) {//fd错误

 

                /*

                 * the stale event from a filedescriptor

                 * that was just closed in thisiteration

                 */

 

               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);//把wev添加到ngx_posted_events队列中

 

            } else {

                wev->handler(wev);//事件处理

            }

        }

    }

 

   ngx_mutex_unlock(ngx_posted_events_mutex);//释放锁

 

    return NGX_OK;

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值