nginx 중 epoll 모듈
18538 단어 nginx
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
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
간단! Certbot을 사용하여 웹 사이트를 SSL(HTTPS)화하는 방법초보자가 인프라 주위를 정돈하는 것은 매우 어렵습니다. 이번은 사이트를 간단하게 SSL화(HTTP에서 HTTPS통신)로 변경하는 방법을 소개합니다! 이번에는 소프트웨어 시스템 Nginx CentOS7 의 환경에서 S...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.