nginx_event_framework

Overview

Each connection(preallocated for fast) has two events, one for read, the other for write, after nginx adds connection(fd) EPOLLIN and EPOLLOUT to epoll instance(each worker has its own), when event is ready, call handler saved at proper event in epoll directly, or adds the event in post queue, after epoll quits, at last step call event->handler.

Event framework

event framework

Data Structure

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
struct ngx_event_s {
/* points to ngx_connection_s */
void *data;
unsigned write:1;
/* listen connection's read event set it */
unsigned accept:1;
/* active means add to epoll */
unsigned active:1;
/* data is ready to read or has buffer to write */
unsigned ready:1;
/* handler for event */
ngx_event_handler_pt handler;
}

struct ngx_connection_s {
/* next connection if in free connection list */
void *data;
ngx_event_t *read;
ngx_event_t *write;
ngx_socket_t fd;
}

Timer event

when struct ngx_event_s is used as timer event, most of its fields are not used, only few are useful for timer event. when user adds a timer event, nginx adds the event to timer RB tree, the key is absolute time(expire time), each epoll_wait() call, use the minimal value of timer tree as timeout parameter, after epoll_wait() returns, it could be data ready or timeout, then check the timer event in RB tree, to see if some of them expire or not.

if there is no timer, epoll_wait will block for ever, wake up only when there is event on socket like data ready, EOF, error, interrupt etc.

1
2
3
4
5
6
struct ngx_event_t {
unsigned timedout:1; /* timer expires or not */
unsigned timer_set:1; /* timer in rb tree or not */
ngx_event_handler_pt handler; /* handler for this timer event */
ngx_rbtree_node_t timer; /* timer event key(absolute time) */
}