nginx epoll 상세 설명
18457 단어 nginxepollepoll 비동기 이벤트 모델
nginx 는 비동기 적 이 고 효율 적 인 이벤트 구동 형 웹 서버 로 서 Liux 플랫폼 에서 시스템 이 epoll 을 지원 할 때 nginx 는 기본적으로 epoll 을 사용 하여 사건 을 효율적으로 처리 합 니 다.nginx 에서 ngx 사용event_t 구 조 는 하나의 사건 을 나타 내 고 먼저 ngx 를 소개 합 니 다.event_t 구조 체 에서 구성원 의 의미:
struct ngx_event_s {
void *data; // , ngx_connection_t
unsigned write:1; // ,1 tcp
unsigned accept:1;// 1 ,
/* used to detect the stale events in kqueue, rtsig, and epoll */
unsigned instance:1; //
/*
* the event was passed or would be passed to a kernel;
* in aio mode - operation was posted.
*/
unsigned active:1;// 1 , epoll
unsigned disabled:1;//epoll
/* the ready event; in aio mode 0 means that no operation can be posted */
unsigned ready:1; // ( )
unsigned oneshot:1;//epoll
/* aio operation is complete */
unsigned complete:1;//aio , aio (io_getevents )
unsigned eof:1;// 1 , recv 0, 1
unsigned error:1;// 1
unsigned timedout:1; // ,1: 。 ( http )
unsigned timer_set:1; // 1
unsigned delayed:1;// 1 ,
unsigned deferred_accept:1;// ,
/* the pending eof reported by kqueue, epoll or in aio chain operation */
unsigned pending_eof:1;// 1 TCP , epoll EPOLLRDHUP
#if !(NGX_THREADS)
unsigned posted_ready:1;// 1.5.5 ngx_epoll_process_events ,
#endif
#if (NGX_WIN32)
/* setsockopt(SO_UPDATE_ACCEPT_CONTEXT) was successful */
unsigned accept_context_updated:1;
#endif
#if (NGX_HAVE_KQUEUE)
unsigned kq_vnode:1;
/* the pending errno reported by kqueue */
int kq_errno;
#endif
/*
* kqueue only:
* accept: number of sockets that wait to be accepted
* read: bytes to read when event is ready
* or lowat when event is set with NGX_LOWAT_EVENT flag
* write: available space in buffer when event is ready
* or lowat when event is set with NGX_LOWAT_EVENT flag
*
* iocp: TODO
*
* otherwise:
* accept: 1 if accept many, 0 otherwise
*/
#if (NGX_HAVE_KQUEUE) || (NGX_HAVE_IOCP)
int available;
#else
unsigned available:1;// 1 accept TCP , multi_accept
#endif
ngx_event_handler_pt handler; //
#if (NGX_HAVE_AIO)
#if (NGX_HAVE_IOCP)
ngx_event_ovlp_t ovlp;
#else
struct aiocb aiocb;
#endif
#endif
ngx_uint_t index; //epoll
ngx_log_t *log; //ngx_log_t
ngx_rbtree_node_t timer;
unsigned closed:1; // 1
/* to test on worker exit */
unsigned channel:1;// ngx_add_channel_event ,
unsigned resolver:1; // resolver ?
#if (NGX_THREADS)
unsigned locked:1;
unsigned posted_ready:1;
unsigned posted_timedout:1;
unsigned posted_eof:1;
#if (NGX_HAVE_KQUEUE)
/* the pending errno reported by kqueue */
int posted_errno;
#endif
#if (NGX_HAVE_KQUEUE) || (NGX_HAVE_IOCP)
int posted_available;
#else
unsigned posted_available:1;
#endif
ngx_atomic_t *lock;
ngx_atomic_t *own_lock;
#endif
/* the links of the posted queue */
ngx_event_t *next;
ngx_event_t **prev;
#if 0
/* the threads support */
/*
* the event thread context, we store it here
* if $(CC) does not understand __thread declaration
* and pthread_getspecific() is too costly
*/
void *thr_ctx;
#if (NGX_EVENT_T_PADDING)
/* event should not cross cache line in SMP */
uint32_t padding[NGX_EVENT_T_PADDING];
#endif
#endif
};
#if (NGX_HAVE_FILE_AIO)
struct ngx_event_aio_s {
void *data;
ngx_event_handler_pt handler;
ngx_file_t *file;
ngx_fd_t fd;
#if (NGX_HAVE_EVENTFD)
int64_t res;
#if (NGX_TEST_BUILD_EPOLL)
ngx_err_t err;
size_t nbytes;
#endif
#else
ngx_err_t err;
size_t nbytes;
#endif
#if (NGX_HAVE_AIO_SENDFILE)
off_t last_offset;
#endif
ngx_aiocb_t aiocb;
ngx_event_t event;
};
#endif
nginx 에서 ngx 사용epoll_module 모듈 은 epoll 메커니즘 처리 사건 을 패키지 합 니 다. ngxepoll_module 모듈 은 두 개의 설정 항목 에 만 관심 이 있 습 니 다. 그 ngxcommand_t 구 조 는 다음 과 같다.
static ngx_command_t ngx_epoll_commands[] = {
{
/***epoll_events epoll_wait , ngx_epoll_init
epoll_events epoll_event **/
ngx_string("epoll_events"),
NGX_EVENT_CONF|NGX_CONF_TAKE1,
ngx_conf_set_num_slot,
0,
offsetof(ngx_epoll_conf_t, events),
NULL },
{
/***worker_aio_requests aio context , io_setup ***/
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
};
ngx_epoll_module 의 ngxevent_module_t 구 조 는 다음 과 같다.
ngx_event_module_t ngx_epoll_module_ctx = {
&epoll_name,
ngx_epoll_create_conf, /* create configuration */
ngx_epoll_init_conf, /* init configuration */
{
// epoll
ngx_epoll_add_event, /* add an event */
// epoll
ngx_epoll_del_event, /* delete an event */
/***epoll enable/disable , / ***/
ngx_epoll_add_event, /* enable an event */
ngx_epoll_del_event, /* disable an event */
// epoll tcp , tcp
ngx_epoll_add_connection, /* add an connection */
// epoll
ngx_epoll_del_connection, /* delete an connection */
NULL, /* process the changes */
// epoll
ngx_epoll_process_events, /* process the events */
//epoll
ngx_epoll_init, /* init the events */
//epoll
ngx_epoll_done, /* done the events */
}
};
ngx_epoll_create_conf 설정 항목 을 분석 하기 전에 설정 구 조 를 초기 화 하 는 데 사용 합 니 다. ngxepoll_init_conf 함 수 는 설정 항목 을 분석 한 후에 호출 합 니 다. 설정 파일 이 epoll 이 존재 하지 않 는 다 면.이벤트 또는 workeraio_requests 설정 항목, 기본적으로 epoll이벤트 설정 512, workeraio_requests 를 32 로 설정 합 니 다.ngx_epoll_module_ctx 구조 체 중 후 10 개 함 수 는 ngx 에 대응 합 니 다.event_actions_t 구조, 이벤트 모듈 만 의 구조 입 니 다.ngx_epoll_init 함 수 는 언제 호출 됩 니까? nginx 시작 과정 에서 모든 worker 프로 세 스 가 시 작 된 후에 호출 됩 니 다 (ngx event core module 의 ngx event process init 함수 에서 호출 됩 니 다).
ngx_epoll_module 소스 코드 분석
ngx_epoll_init 함수:
static ngx_int_t
ngx_epoll_init(ngx_cycle_t *cycle, ngx_msec_t timer)
{
ngx_epoll_conf_t *epcf;
// ngx_epoll_module
epcf = ngx_event_get_conf(cycle->conf_ctx, ngx_epoll_module);
if (ep == -1) {
// epoll, , -1
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;
}
/*** aio , aio***/
#if (NGX_HAVE_FILE_AIO)
ngx_epoll_aio_init(cycle, epcf);
#endif
}
/*** events epoll_event , epcf->events epoll_events , 512***/
if (nevents < epcf->events) {
if (event_list) {
ngx_free(event_list);
}
event_list = ngx_alloc(sizeof(struct epoll_event) * epcf->events,
cycle->log);
if (event_list == NULL) {
return NGX_ERROR;
}
}
nevents = epcf->events;
// I/O
ngx_io = ngx_os_io;
// ngx_event_actions , ngx_event_actions epoll
ngx_event_actions = ngx_epoll_module_ctx.actions;
/***nginx epoll NGX_HAVE_CLEAR_EVENT , NGX_USE_CLEAR_EVENT epoll ET ***/
#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;
}
ngx_epoll_add_이벤트 함수:
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;
//
c = ev->data;
events = (uint32_t) event;
/*** event ***/
if (event == NGX_READ_EVENT) {
e = c->write;
prev = EPOLLOUT;
#if (NGX_READ_EVENT != EPOLLIN|EPOLLRDHUP)
events = EPOLLIN|EPOLLRDHUP;
#endif
} else {
e = c->read;
prev = EPOLLIN|EPOLLRDHUP;
#if (NGX_WRITE_EVENT != EPOLLOUT)
events = EPOLLOUT;
#endif
}
/*** , active (
epoll )。***/
if (e->active) {
op = EPOLL_CTL_MOD;
events |= prev;
} else {
op = EPOLL_CTL_ADD;
}
// flags epoll
ee.events = events | (uint32_t) flags;
/*** ptr (ngx_connection_t*) ,
linux ***/
ee.data.ptr = (void *) ((uintptr_t) c | ev->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);
// 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;
}
//
ev->active = 1;
#if 0
ev->oneshot = (flags & NGX_ONESHOT_EVENT) ? 1 : 0;
#endif
return NGX_OK;
}
ngx_epoll_del_이벤트 함수:
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, the epoll automatically deletes
* it from its queue, so we do not need to delete explicitly the event
* before the closing the file descriptor
*/
/*** , ,epoll 。***/
if (flags & NGX_CLOSE_EVENT) {
ev->active = 0;
return NGX_OK;
}
//
c = ev->data;
/*** event ***/
if (event == NGX_READ_EVENT) {
e = c->write;
prev = EPOLLOUT;
} else {
e = c->read;
prev = EPOLLIN|EPOLLRDHUP;
}
/*** ngx_epoll_add_event ***/
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:%d op:%d ev:%08XD",
c->fd, op, ee.events);
// 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;
}
//
ev->active = 0;
return NGX_OK;
}
ngx_epoll_add_connection 및 ngxepoll_del_연결 함수
이 두 함수 의 실현 은 매우 간단 하 며, 또한 epoll 호출 을 통 해ctl 에 이 벤트 를 추가 합 니 다. 읽 기 / 쓰기 이 벤트 를 동시에 epoll 에 추가 할 뿐 원본 코드 를 표시 하지 않 습 니 다.
ngx_epoll_process_이벤트 함수:
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;
/***NGX_UPDATE_TIME timer_resolution epoll_wait 。
ngx_event_timer_alarm timer_resolution , timer_resolution
ngx_event_timer_alarm 1 。***/
if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) {
ngx_time_update();
}
//err epoll_wait
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);
/*** ***/
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;
/*** / instance ,
, fd -1 。***/
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;
ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
"epoll: fd:%d ev:%04XD d:%p",
c->fd, revents, event_list[i].data.ptr);
/*** ,EPOLLHUP RST 。 tcp
***/
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,
"strange epoll_wait() events fd:%d ev:%04XD",
c->fd, revents);
}
#endif
/*** EPOLLIN EPOLLOUT, EPOLLIN EPOLLOUT, /
。 EPOLLIN EPOLLOUT, /
。***/
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 (NGX_HAVE_EPOLLRDHUP)
//EPOLLRDHUP
if (revents & EPOLLRDHUP) {
rev->pending_eof = 1;
}
#endif
//NGX_POST_THREAD_EVENTS
if ((flags & NGX_POST_THREAD_EVENTS) && !rev->accept) {
rev->posted_ready = 1;
} else {
//
rev->ready = 1;
}
/***NGX_POST_EVENTS , 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;
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 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에 따라 라이센스가 부여됩니다.