文章6:Nginx中的Epoll事件处理机制

本文详细介绍了Nginx中的Epoll事件处理机制,包括Epoll事件的初始化过程及事件处理流程。深入探讨了Epoll如何在Nginx中实现高效并发处理,以及关键函数如epoll_create、epoll_ctl和epoll_wait的具体应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

欢迎转载转载请注明出处 http://blog.csdn.net/yankai0219/article/details/8453313
0.序
1.Epoll事件初始化
2.Epoll事件处理

0.序
     在Linux下,Nginx默认的事件处理机制是Epoll事件处理机制。当然Nginx也可以使用select等事件处理机制,因此Nginx为了支持和开发具体的I/O模型,Nginx将事件处理机制抽象化。
     在ngx_epoll_module.c中,可以看到。

1.Epoll事件初始化
     从总图中来看,我们可以更好的明白Epoll事件初始化所牵涉的内容。
          主要看ngx_worker_process_init函数中内容
     1)ngx_epoll_init 通过epoll_create函数创建了epfd句柄,这是epoll的接口,之后所有的函数调用都要使用该epfd句柄。
     2)之后在ngx_event_process_init中,通过epoll_ctl将监听套接字和其对应的事件类型添加到epfd句柄中。
     通过这两步,就完成了epoll事件处理的三部曲中的前两部,接下来就是由epoll_wait等待事件的发生。

2.Epoll事件处理
     1)epoll_wait函数在ngx_epoll_process_events中,这个函数是由ngx_process_events_and_timers函数调用的。关于ngx_process_events_and_timers函数的介绍,详见文章4:Nginx源码分析-事件循环修改版。
     2)关于ngx_epoll_process_events的处理
static  ngx_int_t
ngx_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 */

    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                    "epoll timer: %M" , timer);
/* 等待事件发生。最长等待事件为timer;nginx通过红黑树专门维护了一个计时器*/
    events = epoll_wait(ep, event_list, (  int ) nevents, timer);

    err = (events == -1) ? ngx_errno : 0;

     if  (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) {
        ngx_time_update();
    }

     if  (err) {
      /*处理wait错误*/
    }

     if  (events == 0) {
         /*epoll_wait返回事件数为0,可能是timeout返回,也可能不是timeout返回。非timeout返回则是error*/
    }

    ngx_mutex_lock(ngx_posted_events_mutex); /*只有在使用线程时,该函数才有作用*/
/*处理wait的事件,wait的事件及其处理方式都在event_list数组中,个数为events个。*/
     for  (i = 0; i < events; i++) {
      ......
  /*取得发生的一个事件*/
        revents = event_list[i].events;
  /*处理wait的错误返回状态*/
         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  ((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;
        }
/* 该事件是一个读事件,并该连接上注册的读事件是active的 */
         if  ((revents & EPOLLIN) && rev->active) {

             if  ((flags & NGX_POST_THREAD_EVENTS) && !rev->accept) {
                rev->posted_ready = 1;

            }  else  {
                rev->ready = 1;
            }
/* 根据 文章8:Nginx accept互斥锁和文章和文章4:Nginx源码分析-事件循环修改版中所讲,抢到accept互斥体的进程A,进程A会对所发生的事件进行NGX_POST_EVENTS标记,先将事件存入ngx_posted_accept_events或ngx_posted_events数组中,之后在进程A解除accept互斥锁以后,才会处理这些事件。 */
             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;
}
参考文章
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值