Nginx event module Analysis

Source: Internet
Author: User
Tags epoll
Ngx_event_core_moduleModule: context: 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; // defines various abstract interfaces of the IO model (epoll, poll, select ).
} Ngx_event_module_t; The actions of ngx_event_core_module is empty, and the actions of ngx_event_epoll_module is working!

Init_module hook-- Ngx_event_module_init: the shared memory is initialized by calling in the master process. It contains an accept mutex lock, and some other status counts are global variables. Init_process hook-- Ngx_event_process_init: when the worker sub-process is initialized, the timer initialization (Red/black tree) is called to call the module of each event module-> actions. init actually only has one ngx_epoll_module -- call ngx_epoll_init to create cycle-> connections, cycle-> read_events, cycle-> write_events, and initialize it. assign a connection slot for each listening socket, set handlerngx_event_accept for the accept read event. If you do not use the accept lock, add the socket to the event listening (epoll). If you set ngx_use_rtsig_event, call ngx_add_conn; otherwise, call ngx_add_event. Do not understand the differences. Otherwise Ngx_process_events_and_timersAnd then add the listener. Ngx_epoll_moduleModule, no init_module/init_process hook, only working actions 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 * // What is the difference between add_connection and add_event?
Ngx_epoll_del_connection,/* Delete An connection */
Null,/* process the changes */
Ngx_epoll_process_events,/* process the events */
Ngx_epoll_init,/* init the events */
Ngx_epoll_done,/* done the events */
}

// Actions member variable
};

Ngx_epoll_init: 1. Create a global epoll handle, event_list 2. Set Ngx_event_actions= Ngx_epoll_module_ctx.actions; later, worker processes will use the ngx_event_actions global variable for event processing. Ngx_event_actions abstracts the IO event model (common interfaces such as epoll, poll, select, and kqueue) Ngx_process_events_and_timers(): The content is very important! Ngx_use_accept_mutex: whether to use the lock. When using the lock, the system will re-determine whether to participate in the accept lock competition. Ngx_accept_disabled: If the value is greater than 0 and the value is reduced by 1, the read/write events of the current connection socket are directly processed if the value is greater than 0 and does not compete in the accept lock. // Ngx_event_accept function to obtain a new connection socket
Ngx_accept_disabled = ngx_cycle-> connection_n/8-ngx_cycle-> free_connection_n; hold: whether to hold the lock. If the lock is obtained, the ngx_post_events flag is generated to put all events in a queue. Wait until the lock is released before processing the event. If the lock is not obtained, the read/write requests of the current connection socket are processed. Wait for a certain amount of time to compete for the accept lock. If the lock is obtained, the ngx_process_events function only saves the IO event to the queue. After the accept lock is released, the read/write events of the accept event and the connection socket are processed to avoid holding the lock for a long time. 1. determine the maximum wait time of epoll_wait; 2. If the accept mutex lock is used: If ngx_accept_disabled> 0, auto-decrease will go into 3; otherwise, the competition accept mutex lock ngx_trylock_accept_mutex, if the accept lock is obtained, add the listening socket to the epoll listener and set the ngx_post_events flag. If the accept lock is not obtained, call ngx_disable_accept_events to delete the accept-FD from epoll; reset epoll_wait maximum wait time 3. ngx_process_events: Get the event, put it in the queue (with a lock) or directly process it (without a lock ). 4. process all the accept events (generate a new connection socket). 5. Release the accept lock if it is obtained. 6. Process timer timeout events. 7. process the read/write events of the connection socket in the queue. Ngx_epoll_process_events () 1. Events = epoll_wait (Ep, event_list, (INT) nevents, timer); wait for the longest time. 2. If ngx_post_events is set to put into the queue (accept_event queue or common queue, because the accept event must be handled before the lock is released. The instance, active, and ready members in ngx_event_t do not know what it means. Ngx_epoll_add_event (ngx_event_t * eV, ngx_int_t event, ngx_uint_t flags)The active member indicates whether the Member is in the epoll listener.
Add the listening socket to epoll: init_process hook of the event_core module ngx_event_process_init REV = C-> read;
Rev-> log = C-> log;

Rev-> Accept = 1; 1. If the accept lock is not used, add it to epoll directly. Ngx_add_event (Rev, ngx_read_event, 0)// This function cannot be viewed. Add the listening socket read event to epoll and set the active flag of the read event. 2. If the accept lock is used: ngx_process_events_and_timers -- "ngx_trylock_accept_mutex --" ngx_enable_accept_events C
= Ls [I]. connection;
Ngx_add_event (c-> Read, ngx_read_event, 0)
The listening socket is deleted from epoll: ngx_trylock_accept_mutex. The competition lock fails. Call ngx_disable_accept_events to delete the accept-FD from epoll.

3. Listen for socket event processing -- read: The ngx_event_accept function calls accept to obtain the connection socket, assign it a connection_t slot, and initialize the connection_t object: C-> Recv = ngx_recv; c-> send = ngx_send;

C-> recv_chain = ngx_recv_chain;
C-> send_chain = ngx_send_chain;
Call ngx_http_init_connection to initialize the connection_t object and add it to the timer.REV = C-> read;
Rev-> handler = ngx_http_init_request; // you can specify the initial handler for a read event.
C-> write-> handler = ngx_http_empty_handler;
Call ngx_epoll_add_connection () to listen for the read/write events of the connection socket.
Ee. Events = epollin | epollout | epollet;
Ee. Data. PTR = (void *) (uintptr_t) c | C-> Read-> instance );
If (epoll_ctl (Ep, epoll_ctl_add, C-> FD, & ee) =-1 ){}
C-> Read-> active = 1;
C-> write-> active = 1;

4. Add the connection socket to epoll: The ngx_event_accept function deletes the connection socket from epoll:
5. read/write handler in ngx_event_accept-ngx_http_init_connection
Ngx_http_init_request (): Sets the processing function of the socket read event to ngx_http_process_request_line to read all the request data.
Ngx_http_process_request_line: connects to the socket read event processing function to parse the request line.
(A) A read event is a timeout event. Close the connection.
(B) loop body (read and analyze data in the cache area cyclically ):
B1: ngx_http_read_request_header: Call ngx_unix_recv first, and then call ngx_handle_read_event (register the read event to epoll again. After each epoll_wait operation, the FD event type is cleared, you need to register a read/write event again. But I don't know where to set the active
= 0)
B2: ngx_http_parse_request_line () content: A piece of data parsed
B3: The ngx_http_parse_request_line function returns an error 400 directly to the client. If ngx_again is returned, check whether the buffer space is insufficient or the read data is insufficient. If the buffer size is insufficient, nginx will call the ngx_http_alloc_large_header_buffer function to allocate another large buffer. If the large buffer is not enough to hold the entire request line, nginx will return the 414 error to the client, otherwise, after a larger buffer zone is allocated and the previous data is copied, call the ngx_http_read_request_header function to read the data and process the data in the request line automatically until the request line resolution ends;
If ngx_ OK is returned, the request line is correctly parsed. At this time, the starting address and length of the request line are recorded, the path and parameters of the request URI are saved in the uri field of the request structure, and the start position and length of the request method are stored in the method_name field. the start position and length of the HTTP Version are recorded in the http_protocol field. The parameter and the extended name of the Request resource are also parsed from the URI and saved in The args and exten fields respectively. Rev-> handler = ngx_http_process_request_headers; // sets the read event processing function ngx_http_process_request_headers (REV) for the connection socket );
Ngx_http_process_request_headers: connects to the socket read event handler to parse the request header domain.
The ngx_http_read_request_header () function is called to read data. If there is no data in the current connection, the system returns the data directly and waits for the next read event. If some data is read, The ngx_http_parse_header_line () function is called () function parsing. The same resolution function is implemented as a finite state machine. The logic is very simple, but the request header is parsed Based on the HTTP protocol. Each call to this function can parse at most one request header, this function returns four different return values, indicating different resolution results.
Returns ngx_ OK, indicating that a request header is parsed.
If ngx_again is returned, it indicates that the received data is insufficient and the request header of a row is not over yet. You need to continue the next loop.
The returned ngx_http_parse_invalid_header indicates that an error is encountered during Request Header Parsing. Generally, the client sends a header that does not comply with the protocol specification, and nginx returns a 400 error;
Returns ngx_http_parse_header_done, indicating that all request headers have been successfully parsed.
Rc = ngx_http_process_request_header (R );If (RC! = Ngx_ OK ){

Return;
}

Ngx_http_process_request (r); // The request processing stage is coming soon.

Ngx_int_t
Ngx_handle_read_event (ngx_event_t * Rev, ngx_uint_t flags)
{
If (ngx_event_flags & ngx_use_clear_event) {// edge triggering

/* Kqueue, epoll */
If (! Rev-> active &&! Rev-> ready) {// ready = 0. The data has been read. eagain active = 0.
// Currently, it is found that only del_conn/del_event is used to set active to 0, but it does not need to be shown to call del_event.
If (ngx_add_event (Rev, ngx_read_event, ngx_clear_event) // ngx_clear_event = epollet
= Ngx_error)
{
Return ngx_error;
}
}
Return ngx_ OK;
}



Epoll data: http://blog.csdn.net/zys85/article/details/3710579

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.