Nginx source code analysis-event-driven Initialization

Source: Internet
Author: User
Tags epoll

Reprinted statement: This article can be reproduced at will, but the original address must be specified. Thank you!

 

The high performance of nginx should be an event-driven credit. The relevant code for nginx event processing is located in the src/event directory, and the event driver is the core of nginx, so the amount of code is relatively large. The event-driven initialization process consists of three steps.

 

 

Step 1: parse configuration file Initialization

During nginx startup initialization, ngx_conf_parse () will be called to parse the configuration file. This process will encounter configuration items similar to the following:

Events {
Worker_connections 20480;
}

The events here is a block command, and many other commands can be configured under it, such as worker_connections here. The commands that can be configured under events are defined in the ngx_event_core_commands array (in the src/event/ngx_event.c file. Each Command has its own callback function. The callback function of the events command is ngx_events_block () (located in the src/events/ngx_event.c file ), this callback function is called when the configuration file is parsed to the events command. The approximate analysis of this function is as follows:

 

Static char * <br/> ngx_events_block (ngx_conf_t * Cf, ngx_command_t * cmd, void * conf) <br/>{< br/> char * RV; <br/> void *** CTX; <br/> ngx_uint_t I; <br/> ngx_conf_t PCF; <br/> ngx_event_module_t * m; <br/>/* The English comments in the source code are clear. */<Br/>/* count the number of the event modules and set up their indices */<br/> ngx_event_max_module = 0; <br/> for (I = 0; ngx_modules [I]; I ++) {<br/> If (ngx_modules [I]-> type! = Ngx_event_module) {<br/> continue; <br/>}< br/> ngx_modules [I]-> ctx_index = ngx_event_max_module ++; <br/>}< br/> CTX = ngx_pcalloc (CF-> pool, sizeof (void *); <br/> If (CTX = NULL) {<br/> return ngx_conf_error; <br/>}< br/>/* assigns a pointer to each event module to save the address of the corresponding configuration structure. */<Br/> * CTX = ngx_pcalloc (CF-> pool, ngx_event_max_module * sizeof (void *); <br/> If (* CTX = NULL) {<br/> return ngx_conf_error; <br/>}< br/> * (void **) conf = CTX; <br/>/* call the create_conf function of each event module cyclically to create the Configuration Structure */<br/> for (I = 0; ngx_modules [I]; I ++) {<br/> If (ngx_modules [I]-> type! = Ngx_event_module) {<br/> continue; <br/>}< br/> M = ngx_modules [I]-> CTX; <br/> If (m-> create_conf) {<br/> (* CTX) [ngx_modules [I]-> ctx_index] = m-> create_conf (CF-> cycle); <br/> If (* CTX) [ngx_modules [I]-> ctx_index] = NULL) {<br/> return ngx_conf_error; <br/>}< br/> PCF = * Cf; <br/> CF-> CTX = CTX; <br/> CF-> module_type = ngx_event_module; <br/> CF-> cmd_type = ngx_event_conf; <br />/* Because events is a block command, many other commands can be configured in the events field. <br/> for example, use. Now, you can parse the commands in the events block, complete initialization. */<Br/> Rv = ngx_conf_parse (CF, null); <br/> * cf = PCF; <br/> If (RV! = Ngx_conf_ OK) <br/> return RV; <br/>/* execute the init_conf function of each event module cyclically and initialize the Configuration Structure */<br/> for (I = 0; ngx_modules [I]; I ++) {<br/> If (ngx_modules [I]-> type! = Ngx_event_module) {<br/> continue; <br/>}< br/> M = ngx_modules [I]-> CTX; <br/> If (m-> init_conf) {<br/> Rv = m-> init_conf (CF-> cycle, (* CTX) [ngx_modules [I]-> ctx_index]); <br/> If (RV! = Ngx_conf_ OK) {<br/> return RV; <br/>}< br/> return ngx_conf_ OK; <br/>}

 

The most important process in the ngx_events_block () function is to call ngx_conf_parse (CF, null). The function of calling ngx_conf_parse () Here is to parse the events {} block in the configuration file, the callback function of all the configuration commands under it is called to complete the initialization of the parsing configuration file.

 

Step 2: ngx_event_module_init

At the end of nginx startup initialization process (II), there is a text like this: "execute the init_module operation of all modules. It is called initialization of the module. Looking at the source code, we found that most modules, including several ngx_core_module modules, do not have this init callback function. Which modules use this callback interface? Using the search function, I finally found a module using this callback interface, which is ngx_event_core_module. Here, we will not tangle with this unique initialization function. When analyzing event-driven functions, let's look back ."; The title ngx_event_module_init is the callback function of the ngx_event_core_module module. The ngx_event_module_init code is analyzed as follows:

Static ngx_int_t <br/> ngx_event_module_init (ngx_cycle_t * cycle) <br/>{< br/> void *** CF; <br/> u_char * shared; <br/> size_t size, Cl; <br/> ngx_shm_t SHM; <br/> ngx_time_t * TP; <br/> ngx_core_conf_t * CCF; <br/> ngx_event_conf_t * ECF; </P> <p> CF = ngx_get_conf (cycle-> conf_ctx, ngx_events_module); <br/> If (cf = NULL) {<br/> return ngx_error; <br/>}< br/>/* obtain the Configuration Structure of the ngx_event_core_module module */<br/> ECF = (* Cf) [ngx_event_core_module.ctx_index]; <br/>/* obtain the Configuration Structure of the ngx_core_module */<br/> CCF = (ngx_core_conf_t *) ngx_get_conf (cycle-> conf_ctx, ngx_core_module); <br/>/* obtain the configuration parameter of the timer_resolution command from the Configuration Structure of the ngx_core_module */<br/> ngx_timer_resolution = CCF-> timer_resolution; <br/> .................... <Br/>/* If the master process is disabled, the following steps are not required. If the master process is disabled, it is <br/> A single process. The following steps are used to create shared memory implementation locks, which are not required by a single process. <Br/> */<br/> If (CCF-> master = 0) {<br/> return ngx_ OK; <br/>}< br/>/* The accept mutex already exists and does not need to be created again */<br/> If (ngx_accept_mutex_ptr) {<br/> return ngx_ OK; <br/>}< br/>/* Cl shoshould be equal or bigger than cache line size */<br/> Cl = 128; <br/>/* a size shared memory will be created later. The shared memory will be divided into three sections, <br/> ngx_accept_mutex, ngx_connection_counter, and ngx_temp_number <br/> respectively. <Br/> */<br/> size = Cl/* ngx_accept_mutex */<br/> + Cl/* ngx_connection_counter */<br/> + Cl; /* ngx_temp_number */<br/> ..................... <Br/>/* start to create shared memory. The size is size and the name is nginx_shared_zone */<br/> SHM. size = size; <br/> SHM. name. len = sizeof ("nginx_shared_zone"); <br/> SHM. name. data = (u_char *) "nginx_shared_zone"; <br/> SHM. log = Cycle-> log; <br/>/* creates the shared memory. The starting address of the shared memory is stored in SHM. ADDR */<br/> If (ngx_shm_alloc (& SHM )! = Ngx_ OK) {<br/> return ngx_error; <br/>}< br/>/* obtain the starting address of the shared memory */<br/> shared = SHM. ADDR; </P> <p>/* The accept mutex obtains the first cl size of the shared memory */<br/> ngx_accept_mutex_ptr = (ngx_atomic_t *) shared; </P> <p>/* Create an accept mutex. </P> <p> whether the implementation dependency of accept mutex supports atomic operations. If there is an atomic operation; <br/> the obtained shared memory is used to implement the accept mutex. Otherwise, the file <br/> lock is used to implement the accept mutex. </P> <p> the accept mutex is used to avoid group alarms and achieve load balancing of worker processes. <Br/> */<br/> If (ngx_shmtx_create (& ngx_accept_mutex, shared, cycle-> lock_file.data) <br/>! = Ngx_ OK) <br/>{< br/> return ngx_error; <br/>}< br/>/* ngx_connection_counter obtains the CL size of the second segment of shared memory */<br/> ngx_connection_counter = (ngx_atomic_t *) (shared + 1 * Cl); <br/> (void) ngx_atomic_cmp_set (ngx_connection_counter, 0, 1 ); </P> <p>/* ngx_temp_number get the CL size of the third segment of the shared memory */<br/> ngx_temp_number = (ngx_atomic_t *) (shared + 2 * Cl ); <br/> ...................... <Br/> return ngx_ OK; <br/>}

 

 

Step 3: ngx_event_process_init

In the analysis of the worker process, it is mentioned that the process initialization function customized by each module is called. The ngx_event_process_init callback function is the process initialization function customized by the ngx_event_core_commands module. Therefore, after the master process has created a worker process, the worker process first initializes the process, and then calls the ngx_event_process_init function. The ngx_event_process_init code is analyzed as follows:

Static ngx_int_t <br/> ngx_event_process_init (ngx_cycle_t * cycle) <br/>{< br/> ngx_uint_t m, I; <br/> ngx_event_t * Rev, * WEV; <br/> ngx_listening_t * ls; <br/> ngx_connection_t * C, * Next, * old; <br/> ngx_core_conf_t * CCF; <br/> ngx_event_conf_t * ECF; <br/> ngx_event_module_t * module; <br/>/* obtain the Configuration Structure of the corresponding module */<br/> CCF = (ngx_core_conf_t *) ngx_get_conf (cycle-> conf_ctx, ngx_core_module); <br/> ECF = ngx_e Vent_get_conf (cycle-> conf_ctx, ngx_event_core_module); <br/>/* When the master process is enabled, the number of worker processes is greater than 1, and accetp_mutex is configured (used by default) <br/>, to use the accept mutex. <Br/> */<br/> If (CCF-> master & CCF-> worker_processes> 1 & ECF-> accept_mutex) {<br/> ngx_use_accept_mutex = 1; /* 1 use the accept mutex, 0 do not use */<br/> ngx_accept_mutex_held = 0; /* ngx_accept_mutex_held indicates whether to obtain the accept mutex */<br/> ngx_accept_mutex_delay = ECF-> accept_mutex_delay;/* after an error occurred while obtaining the mutex, interval of next snatching */<br/>} else {<br/> ngx_use_accept_mutex = 0; <br/>}< br/>/* initialize the timer, A red-black image is created to maintain the timer. */<Br/> If (ngx_event_timer_init (cycle-> log) = ngx_error) {<br/> return ngx_error; <br/>}< br/> for (m = 0; ngx_modules [m]; m ++) {<br/> If (ngx_modules [m]-> type! = Ngx_event_module) {<br/> continue;/* Skip non-ngx_event_module */<br/>}< br/> If (ngx_modules [m]-> ctx_index! = ECF-> Use) {<br/> continue;/* skip a module that is not specified by the use configuration command, linux default epoll */<br/>}< br/> module = ngx_modules [m]-> CTX; <br/>/* calls the init function of the specific event module. </P> <p> nginx implements many event modules, such as epoll, poll, select, kqueue, AIO <br/> (these modules are located in the src/event/modules directory) and so on. Therefore, nginx abstracts the event module. <br/>, you can easily use different event models on different systems, and expand new event models. <br/>. From then on, we will focus on epoll. </P> <p> the init callback here actually calls the ngx_epoll_init function. Module-> actions structure <br/> encapsulates all epoll interface functions. Nginx registers epoll to the event abstraction layer through the actions structure. Actions is ngx_event_actions_t in src/event/ngx_event.h <br/> */<br/> If (module-> actions. INIT (cycle, ngx_timer_resolution )! = Ngx_ OK) {<br/>/* fatal */<br/> exit (2); <br/>}< br/> break;/* jump out of the loop, only a specific event model */<br/>}< br/> ..................... .... <Br/>/* create a connection array to maintain all connections. <br/> this process is already in the worker process, therefore, each worker has its own <br/> connection array. <Br/> */<br/> cycle-> connections = <br/> ngx_alloc (sizeof (ngx_connection_t) * cycle-> connection_n, cycle-> log ); <br/> If (cycle-> connections = NULL) {<br/> return ngx_error; <br/>}< br/> C = Cycle-> connections; <br/>/* Create a read event array */<br/> cycle-> read_events = ngx_alloc (sizeof (ngx_event_t) * cycle-> connection_n, <br/> cycle-> log); <br/> If (cycle-> read_events = NULL) {<br/> return ngx_error; <br/ >}< Br/> REV = Cycle-> read_events; <br/> for (I = 0; I <cycle-> connection_n; I ++) {<br/> rev [I]. closed = 1; <br/> rev [I]. instance = 1; <br/>}</P> <p>/* Create a write event array */<br/> cycle-> write_events = ngx_alloc (sizeof (ngx_event_t) * cycle-> connection_n, <br/> cycle-> log); <br/> If (cycle-> write_events = NULL) {<br/> return ngx_error; <br/>}< br/> WEV = Cycle-> write_events; <br/> for (I = 0; I <cycle-> Connection_n; I ++) {<br/> WEV [I]. closed = 1; <br/>}< br/> I = Cycle-> connection_n; <br/> next = NULL; </P> <p>/* initializes the entire connection array. The connection array is very clever. <br/> you can quickly obtain and release a connection structure. Next, draw a picture to see in detail <br/> this connection. <Br/> */<br/> do {<br/> I --; <br/> C [I]. data = next; <br/> C [I]. read = & cycle-> read_events [I]; <br/> C [I]. write = & cycle-> write_events [I]; <br/> C [I]. FD = (ngx_socket_t)-1; <br/> next = & C [I]; <br/>} while (I ); <br/> cycle-> free_connections = next; <br/> cycle-> free_connection_n = Cycle-> connection_n; <br/>/* for each listening socket */</P> <p>/* assign a connection to each listener socket from the connection array, that is, a slot */<br/> ls = Cycle-> listening. ELTs; <br/> for (I = 0; I <cycle-> listening. nelts; I ++) {<br/>/* Get a new connection slot from the connection */<br/> C = ngx_get_connection (LS [I]. FD, cycle-> log); <br/> If (C = NULL) {<br/> return ngx_error; <br/>}< br/> C-> log = & LS [I]. log; <br/> C-> listening = & LS [I]; <br/> ls [I]. connection = C; <br/> REV = C-> read; <br/> rev-> log = C-> log; <br/> rev-> Accept = 1; /* When a read event occurs, call accept */<br/> ..... ............... <Br/> # If (ngx_win32) <br/> ................... <Br/> # else <br/>/* registers the callback function ngx_event_accept */<br/> rev-> handler = ngx_event_accept; <br/>/* If accept_mutex is used, the listener socket is not put into epoll for the time being. <br/> instead, the worker waits until the accept mutex is obtained and then enters epoll, avoid the occurrence of <br/> surprise groups. <Br/> */<br/> If (ngx_use_accept_mutex) {<br/> continue; <br/>}< br/> If (ngx_event_flags & ngx_use_rtsig_event) {<br/> If (ngx_add_conn (c) = ngx_error) {<br/> return ngx_error; <br/>}< br/>} else {<br/>/* If the accept mutex is not used, put the listening socket in <br/> epoll. <Br/> */<br/> If (ngx_add_event (Rev, ngx_read_event, 0) = ngx_error) {<br/> return ngx_error; <br/>}< br/> # endif <br/>}< br/> return ngx_ OK; <br/>}

 

At this point, the three-step initialization process of event-driven is complete.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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.