nginx 중 epoll 모듈

18538 단어 nginx
1. epoll 모듈 에 대한 소개
nginx 에서 epoll 모듈 은 이벤트 모듈 의 중요 한 모듈 로 이 모듈 은 주로 네트워크 에 대한 것 입 니 다.
io 작업 진행, 기본 가장자리 트리거
     일반적으로 nginx 모듈 은 설정 부분 과 관련 된 commands 배열 이 있 습 니 다. 설정 파일 과 관련 된 설정 정보 부분 을 설정 하고 nginx 에서 전체 부분 에 다음 과 같은 설정 이 있 습 니 다.
이벤트 모듈 에 epoll 시간 배열 의 개 수 를 설정 하고 기본 값 을 사용 할 수 있 습 니 다.
static ngx_command_t  ngx_epoll_commands[] = {

 

    {ngx_string("epoll_events"),

     NGX_EVENT_CONF|NGX_CONF_TAKE1, //     events           

     ngx_conf_set_num_slot,//            

     0,

     offsetof(ngx_epoll_conf_t, events),

     NULL },

 

    {ngx_string("worker_aio_requests"),

     NGX_EVENT_CONF|NGX_CONF_TAKE1,

     ngx_conf_set_num_slot,

     0,

     offsetof(ngx_epoll_conf_t, aio_requests),

     NULL },

 

     ngx_null_command

};

 
2. 시간 모듈 의 관련 설정
typedef struct {

    ngx_str_t              *name; //      

   //       ,                  

    void                 *(*create_conf)(ngx_cycle_t*cycle);

   //         ,                   

    char                 *(*init_conf)(ngx_cycle_t*cycle, void *conf);

 

    ngx_event_actions_t     actions;//        ,            10     

} ngx_event_module_t;

그 중에서 가장 중요 한 것 은 10 개의 actions 함수 지침 이다.
 
다음은 ngxevent_actions_t 의 소개
 
typedefstruct {

         //      

    ngx_int_t (*add)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);

         //      

    ngx_int_t (*del)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);

 

   //      

    ngx_int_t (*enable)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);

   //      

    ngx_int_t (*disable)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);

 

    ngx_int_t (*add_conn)(ngx_connection_t *c);//          

    ngx_int_t (*del_conn)(ngx_connection_t *c, ngx_uint_t flags);//         

   

    ngx_int_t (*process_changes)(ngx_cycle_t *cycle, ngx_uint_t nowait);

 

         //        process_events    

    ngx_int_t (*process_events)(ngx_cycle_t *cycle, ngx_msec_t timer,

                   ngx_uint_t flags);

 

         //         

    ngx_int_t (*init)(ngx_cycle_t *cycle, ngx_msec_t timer);

         //            

    void      (*done)(ngx_cycle_t *cycle);

} ngx_event_actions_t;

 
다음은 epoll 모듈 상하 문 구조의 실현
ngx_event_module_t  ngx_epoll_module_ctx = {

    &epoll_name,

    ngx_epoll_create_conf,               /* create configuration */

    ngx_epoll_init_conf,                 /* init configuration */

 

    {

        ngx_epoll_add_event,             /* add an event */

        ngx_epoll_del_event,             /* delete an event */

        ngx_epoll_add_event,             /* enable an event */

        ngx_epoll_del_event,             /* disable an event */

        ngx_epoll_add_connection,        /* add an connection */

        ngx_epoll_del_connection,        /* delete an connection */

        NULL,                            /* process thechanges */

        ngx_epoll_process_events,        /* process the events */

        ngx_epoll_init,                  /* init the events */

        ngx_epoll_done,                  /* done the events */

    }

};

 
물론 모듈 의 가장 중요 한 부분 은 nginx 의 ngx 입 니 다.module_t 의 실현, 다음은 그 실현
ngx_module_t  ngx_epoll_module = {

    NGX_MODULE_V1,

    &ngx_epoll_module_ctx,               /* module context */

    ngx_epoll_commands,                  /* module directives */

    NGX_EVENT_MODULE,                    /* module type */

    NULL,                                /* init master*/

    NULL,                                /* init module*/

    NULL,                                /* init process*/

    NULL,                                /* init thread*/

    NULL,                                /* exit thread*/

    NULL,                                /* exit process */

    NULL,                                /* exit master*/

    NGX_MODULE_V1_PADDING

};

사실, ngx 를 통 해epoll_module 는 nginx 모듈 을 통솔 할 수 있 습 니 다.
 
함수 설명
ngx_epoll_init 는 비교적 간단 합 니 다. 논 리 는 다음 과 같 습 니 다.
static ngx_int_t

ngx_epoll_init(ngx_cycle_t*cycle, ngx_msec_t timer)

{

    ngx_epoll_conf_t  *epcf;

   //  create_conf    ngx_epoll_conf_t   ,             

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

 

    if (ep == -1) {

                   //  epoll_create      epoll  

        ep =epoll_create(cycle->connection_n / 2);

 

        if (ep == -1) {

            ngx_log_error(NGX_LOG_EMERG,cycle->log, ngx_errno,

                          "epoll_create()failed");

            return NGX_ERROR;

        }

 

    }

 

    if (nevents < epcf->events) {

        if (event_list) {

            ngx_free(event_list);

        }

      //   event_list  。         epoll_events  

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

                               cycle->log);

       if (event_list == NULL) {

            return NGX_ERROR;

        }

    }

    //nevents     epoll_events  

    nevents = epcf->events;

    //    io  

    ngx_io = ngx_os_io;

    //  ngx_event_actions  

    ngx_event_actions =ngx_epoll_module_ctx.actions;

 

#if(NGX_HAVE_CLEAR_EVENT)

   //    ET     epoll,NGX_USE_CLEAR_EVENT       nginx  ET  

    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;

}

 
함수 ngxepoll_add_event
대체 논 리 는 다음 과 같다.
대응 코드:
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;

 

         //     data         ngx_connection_t  

    c = ev->data;

   //  event                 ,    events  EPOLLIN EPOLLOUT

    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) { //  active            ,              

        op = EPOLL_CTL_MOD;

        events |= prev;

 

    } else {

        op = EPOLL_CTL_ADD;

    }

   //  flags   events   

    ee.events = events | (uint32_t) flags;

         //ptr    ngx_connection_t  

         //

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

 

    ngx_log_debug3(NGX_LOG_DEBUG_EVENT,ev->log, 0,

                   "epoll add event: fd:%dop:%d ev:%08XD",

                   c->fd, op, ee.events);

    //  epoll_ctl   epoll       epoll     

    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;

    }

    //    active     1,          

    ev->active = 1;

#if 0

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

#endif

 

    return NGX_OK;

}

 
함수 ngxepoll_del_event
관련 코드
static ngx_int_t

ngx_epoll_del_event(ngx_event_t*ev, ngx_int_t event, ngx_uint_t flags)

{

    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 explicity the event

     * before the closing the file descriptor

     */

 

    if (flags & NGX_CLOSE_EVENT) {

        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;

}

 

  ngx_epoll_add_connections  

    

staticngx_int_t

ngx_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);

 

    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) {

        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;

}

 
함수 ngxepoll_del_connection
코드 는 다음 과 같다.
static ngx_int_t

ngx_epoll_del_connection(ngx_connection_t*c, ngx_uint_t flags)

{

    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 explicity the event

     * before the closing the file descriptor

     */

 

    if (flags & NGX_CLOSE_EVENT) {

        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) {

        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;

}

 
 
함수 ngxepoll_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);

 

         // epoll_wait    。

    events = epoll_wait(ep, event_list, (int)nevents, timer);

 

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

   //nginx       。 flag           ,     

    if (flags & NGX_UPDATE_TIME ||ngx_event_timer_alarm) {

        ngx_time_update();

    }

 

    if (err) {

        if (err == NGX_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) {

        if (timer != NGX_TIMER_INFINITE) {

            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);

   //    epoll_wait         

    for (i = 0; i < events; i++) {

                   //        ngx_epoll_add_event

        c= event_list[i].data.ptr;

        //        , instance    

        instance = (uintptr_t) c & 1;

          // ngx_connection_t            

        c = (ngx_connection_t *) ((uintptr_t) c& (uintptr_t) ~1);

      //     

        rev = c->read;

        //              

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

         // fd       -1  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;

 

        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

        //        EPOLLIN  EPOLLOUT  ,     EPOLLIN、EPOLLOUT  

        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) {

          //flags     NGX_POST_EVENT           

            if ((flags &NGX_POST_THREAD_EVENTS) && !rev->accept) {

                rev->posted_ready = 1;

 

            } else {//      

                rev->ready = 1;

            }

 

            if (flags & NGX_POST_EVENTS){//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) {

           //                 ,  -1  instance   ,     

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

 

                /*

                 * the stale event from a file descriptor

                 * that was just closed in thisiteration

                 */

            // fd       -1  instance       ,          ,   

               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) {

                                     //        post       

                ngx_locked_post_event(wev,&ngx_posted_events);

 

            } else {

            //                     

                wev->handler(wev);

            }

        }

    }

 

    ngx_mutex_unlock(ngx_posted_events_mutex);

 

    return NGX_OK;

}

마지막 으로 몇 가지 문제 에 대한 연 구 를 한다.
1. ngx 에서epoll_add_이벤트 중 일부 코드 는 다음 과 같 습 니 다.
    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 문 구 는 읽 기 이벤트 인지 아 닌 지 를 판단 하 는 것 이 고 그 안에 실 행 된 쓰기 작업 에 관 한 정 보 를 실행 하 는 것 입 니 다. 마찬가지 로 else 에 서 는 읽 기 작업 의 일부 정보 (또는 정보 가 정확 하지 않다 고 말 합 니 다) 입 니 다. 왜 그 럴 까요?
if (e->active) {

op = EPOLL_CTL_MOD;  

events |= prev; 

} else {  

    op = EPOLL_CTL_ADD; 

}  

이 건 epollctl 을 추가 할 때 두 가지 조작 입 니 다. add 와 mod 는 첫 번 째 조작 이 라면 add 로 작 동 합 니 다. file descripter 가 epoll 에 있 으 면 mod 를 통 해 원래 의 모니터링 방식 을 바 꿀 수 있 습 니 다.
man 매 뉴 얼 의 epoll 부분 에 따 르 면,
    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  the  same
           epoll  instance.   This can be a useful technique for filtering events, if the duplicate file descriptors are registered with different

           events masks.

즉, fd 가 epoll 에 존재 한다 면 errno 는 EEXIST 입 니 다.
nginx 이 문 제 를 해결 하 는 것 은 바로 상술 한 방법 을 채택 하 는 것 이다
예 를 들 어 이벤트 가 읽 기 이벤트 라면 연 결 된 읽 기 이 벤트 를 변수 e 로 가리 키 고 flag 를 prev 로 기록 합 니 다. 아래 판단 e - > active 는 연결 이 epoll 에 존재 한다 고 가정 합 니 다. if (event = = NGX READ EVENT) 동작 이 없 으 면 epoll 을 호출 합 니 다.ctl 시 오류 가 발생 할 수 있 습 니 다. 오류 코드 는 EEXIST 입 니 다.
2. 주요 처리 함수 ngxepoll_process_events
언어 로 그 논 리 를 묘사 하 다.
 epoll_wait 획득 시간 수
 업데이트 시간
  반복 처리
    읽 기 이벤트 라면 읽 기 이벤트 리 셋 함수
    이 벤트 를 쓰 는 것 이 라면 쓰기 반전 함 수 를 호출 합 니 다.
이상 은 바로 epoll 모듈 의 대체 적 인 처리 절차 입 니 다. 처음으로 블 로 그 를 쓰 는 것 입 니 다. 잘못된 점 이나 의문 점 은 많이 지적 해 주 십시오.
참고 자료:
1. < 깊이 이해 nginx >
2、https://blog.csdn.net/brainkick/article/details/9080789
3、man epoll

좋은 웹페이지 즐겨찾기