In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-31 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Servers >
Share
Shulou(Shulou.com)06/01 Report--
This article shares with you the content of an implementation example of a worker process loop in nginx. The editor thinks it is very practical, so share it with you as a reference and follow the editor to have a look.
When the worker process starts, it first initializes the environment it needs to run, and then enters a loop that constantly checks for events that need to be executed, and then handles the events. In this process, the worker process also needs to interact with the master process, what is more, the worker process, as a child process, can also receive command-line instructions (such as kill, etc.) for corresponding logical processing. So how does the worker process interact with master or command-line instructions? This article will first explain how the worker process interacts with the master process, and how the worker process handles command-line instructions, and then introduces the whole workflow of worker process interaction from the source code.
1. How worker interacts with master processes
The first thing to note here is that whether it is a master or an external command, nginx processes the corresponding instruction through flag bits, that is, when it receives an instruction (whether master or an external command), worker sets the flag bit corresponding to the instruction in its callback method, and then checks whether the flag bit is true after the worker process processes the event in its own loop. Yes, the corresponding logic is executed according to the function of the flag bit.
The interaction between the worker process and the master process is done through the socket pipeline. A ngx_process_t structure is declared in the ngx_process.h file, and here we focus on its channel property:
Typedef struct {/ / remaining properties. Ngx_socket_t channel [2];} ngx_process_t
The function of the ngx_process_t structure here is to store information about a process, such as pid, channel, status, and so on. There is a ngx_processes array in each process, and the array element is the ngx_process_t structure here, which means that each process holds the basic information of the other processes through the ngx_processes array. The statement is as follows:
/ / stores all the child process arrays in nginx, each with a corresponding ngx_process_t structure for marking
Extern ngx_process_t ngx_ processes[NGX _ MAX_PROCESSES]
Here we can see that each process has a corresponding channel array, which is 2 in length, which is a pipe flow that interacts with the master process. Before the master process creates each child process, a channel array is created by:
Int socketpair (int domain, int type, int protocol, int sv [2])
The main purpose of this method is to create an anonymous pair of connected sockets, that is, if you write data in one socket, you can receive the written data in another socket. In this way, if data is written to one side of the pipe in the parent process, the child process can receive the data on the other side, so that the data communication between the parent and child processes can be realized.
After the master process starts the child process, the child process retains the corresponding data in the master process, including the channel array here. In this way, the master process can communicate with the child process through the channel array.
2. Worker handles external commands
External commands are essentially processed by individual signals and callback methods defined in the signals array. When the master process initializes the base environment, the signal callback method specified in the signals array is set to the corresponding signal. Because the worker process inherits the basic environment of the master process, the worker process also calls the corresponding callback method after receiving the signal set here. The main logic of the callback method is simply to set the value of the corresponding flag bit. About how to set the corresponding flag bit after nginx receives the signal, you can refer to my previous article (nginx master work cycle hyperlink), which will not be repeated here.
3. Source code explanation
The master process starts each child process through the ngx_start_worker_processes () method, which is the source code of this method:
Start n worker child processes and set up the socket handle communication mechanism established by socketpair * system calls between each child process and the master parent process * / static void ngx_start_worker_processes (ngx_cycle_t * cycle, ngx_int_t n, ngx_int_t type) {ngx_int_t I; ngx_channel_t ch; ngx_memzero (& ch, sizeof (ngx_channel_t)) Ch.command = NGX_CMD_OPEN_CHANNEL; for (I = 0; I
< n; i++) { // spawn是产卵的意思,这里就是生成一个子进程的意思,而该子进程所进行的事件循环就是 // ngx_worker_process_cycle()方法,这里的ngx_worker_process_cycle是worker进程处理事件的循环, // worker进程在一个无限for循环中,不断的检查相应的事件模型中是否存在对应的事件, // 然后将accept事件和read、write事件分开放入两个队列中,最后在事件循环中不断的处理事件 ngx_spawn_process(cycle, ngx_worker_process_cycle, (void *) (intptr_t) i, "worker process", type); // 下面的这段代码的主要作用是将新建进程这个事件通知到其他的进程,上面的 // ch.command = NGX_CMD_OPEN_CHANNEL;中NGX_CMD_OPEN_CHANNEL表示的就是当前是新建了一个进程, // 而ngx_process_slot存储的就是该新建进程所存放的数组位置,这里需要进行广播的原因在于, // 每个子进程被创建后,其内存数据都是复制的父进程的,但是ngx_processes数组是每个进程都有一份的, // 因而数组中先创建的子进程是没有后创建的子进程的数据的,但是master进程是有所有子进程的数据的, // 因而这里master进程创建子进程之后,其就会向ngx_processes数组的每个进程的channel[0]上 // 写入当前广播的事件,也即这里的ch,通过这种方式,每个子进程接收到这个事件之后, // 都会尝试更新其所保存的ngx_processes数据信息 ch.pid = ngx_processes[ngx_process_slot].pid; ch.slot = ngx_process_slot; ch.fd = ngx_processes[ngx_process_slot].channel[0]; // 广播事件 ngx_pass_open_channel(cycle, &ch); }} 这里我们主要需要关注上面的启动子进程的方法调用,也即这里的ngx_spawn_process()方法,该方法的第二个参数是一个方法,在启动子进程之后,子进程就会进入该方法所指定的循环中。而在ngx_spawn_process()方法中,master进程会为当前新创建的子进程创建一个channel数组,以用于与当前子进程进行通信。如下是ngx_spawn_process()方法的源码: ngx_pid_t ngx_spawn_process(ngx_cycle_t *cycle, ngx_spawn_proc_pt proc, void *data, char *name, ngx_int_t respawn) { u_long on; ngx_pid_t pid; ngx_int_t s; if (respawn >= 0) {s = respawn;} else {/ / stores all the currently created processes in the ngx_processes array, and ngx_last_process is the index of the last / / process of the current record in the ngx_processes, except that some of the processes recorded in ngx_processes may have been invalidated. The current loop is to start from scratch to find out whether a process has failed, and if so, reuse the process location, / / otherwise directly use the location pointed to by ngx_last_process for (s = 0; s)
< ngx_last_process; s++) { if (ngx_processes[s].pid == -1) { break; } } // 这里说明所创建的进程数达到了最大限度 if (s == NGX_MAX_PROCESSES) { ngx_log_error(NGX_LOG_ALERT, cycle->Log, 0, "no more than% d processes can be spawned", NGX_MAX_PROCESSES); return NGX_INVALID_PID }} / / NGX_PROCESS_DETACHED flag indicates that the current fork process has nothing to do with the original parent process. For example, when upgrading nginx, the newly generated master process has nothing to do with the original master process. If (respawn! = NGX_PROCESS_DETACHED) {/ * Solaris 9 still has no AF_LOCAL * / the main function of the socketpair () method here is to generate a pair of socket streams. For communication between the main process and child processes, this pair of sockets / / is stored in ngx_ processes [s] .channel, which is essentially an integer array of length 2. Before the main process and the child process / / communicate, the main process shuts down one of them, while the child process closes the other, and then writes or reads data to another file descriptor that is not closed. / / AF_UNIX indicates that the socket address family in the form of a UNIX file is currently used. / / SOCK_STREAM specifies that the communication established by the current socket is a pipe flow, and that the pipe flow is bidirectional. / / that is, both sides of the pipeline can read and write / / the third parameter protocol must be 0 if (socketpair (AF_UNIX, SOCK_STREAM, 0, ngx_ processes [s] .channel) =-1) {ngx_log_error (NGX_LOG_ALERT, cycle- > log, ngx_errno, "socketpair () failed while spawning\"% s\ ", name). Return NGX_INVALID_PID;} ngx_log_debug2 (NGX_LOG_DEBUG_CORE, cycle- > log, 0, "channel% dvv% d", ngx_ processes [s] .channel [0], ngx_ processes [s] .channel [1]) / set ngx_ processes [s] .channel [0] to nonblocking mode if (ngx_nonblocking (ngx_ processes [s] .channel [0]) =-1) {ngx_log_error (NGX_LOG_ALERT, cycle- > log, ngx_errno, ngx_nonblocking_n "failed while spawning\"% s\ ", name); ngx_close_channel (ngx_ processes [s] .channel, cycle- > log) Return NGX_INVALID_PID;} / set ngx_ processes [s] .channel [1] to nonblocking mode if (ngx_nonblocking (ngx_ processes [s] .channel [1]) =-1) {ngx_log_error (NGX_LOG_ALERT, cycle- > log, ngx_errno, ngx_nonblocking_n "failed while spawning\"% s\ ", name) Ngx_close_channel (ngx_ processes [s] .channel, cycle- > log); return NGX_INVALID_PID;} on = 1 Set the ngx_ processes [s] .channel [0] socket pipeline to asynchronous mode if (ioctl (ngx_ processes [s] .channel [0], FIOASYNC, & on) = =-1) {ngx_log_error (NGX_LOG_ALERT, cycle- > log, ngx_errno, "ioctl (FIOASYNC) failed while spawning\"% s\ ", name); ngx_close_channel (ngx_ processes [s] .channel, cycle- > log); return NGX_INVALID_PID } / / is still in the main process. The ngx_pid here points to the process id of the main process. The current method is mainly used to set the operation permissions of / / ngx_ processes [s] .channel [0] to the main process. That is, the main process communicates with the child process by writing and reading data to / / ngx_ processes [s] .channel [0] (fcntl (ngx_ processes [s] .channel [0], F_SETOWN, ngx_pid) =-1) {ngx_log_error (NGX_LOG_ALERT, cycle- > log, ngx_errno, "fcntl (F_SETOWN) failed while spawning\"% s\ ", name). Ngx_close_channel (ngx_ processes [s] .channel, cycle- > log); return NGX_INVALID_PID } / / FD_CLOEXEC means that the currently specified socket pipe can be used in a child process, but if (fcntl (ngx_ processes [s] .channel [0], F_SETFD, FD_CLOEXEC) =-1) {ngx_log_error (NGX_LOG_ALERT, cycle- > log, ngx_errno, "fcntl (FD_CLOEXEC) failed while spawning\"% s\ ", name) is not available in programs executed by execl (). Ngx_close_channel (ngx_ processes [s] .channel, cycle- > log); return NGX_INVALID_PID } / / FD_CLOEXEC means that the currently specified socket pipe can be used in a child process, but if (fcntl (ngx_ processes [s] .channel [1], F_SETFD, FD_CLOEXEC) =-1) {ngx_log_error (NGX_LOG_ALERT, cycle- > log, ngx_errno, "fcntl (FD_CLOEXEC) failed while spawning\"% s\ ", name) is not available in programs executed by execl (). Ngx_close_channel (ngx_ processes [s] .channel, cycle- > log); return NGX_INVALID_PID } / / ngx_ processes [s] .channel [1] is used to listen for related events for child processes. When the parent process issues an event to / / ngx_ processes [s] .channel [0], the ngx_ processes [s] .channel [1] will receive / / the corresponding event and process ngx_channel = ngx_ processes [s] .channel [1] accordingly. } else {/ / if it is in NGX_PROCESS_DETACHED mode, it means that it is currently a new master process, so its pipeline values are all set to-1 ngx_ processes [s] .channel [0] =-1; ngx_ processes [s] .channel [1] =-1;} ngx_process_slot = s The / / fork () method produces a new process whose relationship with the parent process is that the memory data of the child process will completely copy that of the parent process. / / it should also be noted that the code executed by the child process from fork () starts after fork (). For the parent process, the return value of / / this method is the parent process id, while for the child process, the return value of this method is 0, so the parent process / / and the child process can call the subsequent different code fragments pid = fork () through the if-else statement. Switch (pid) {case-1: / / fork error ngx_log_error (NGX_LOG_ALERT, cycle- > log, ngx_errno, "fork () failed while spawning\"% s\ ", name); ngx_close_channel (ngx_ processes [s] .channel, cycle- > log); return NGX_INVALID_PID Case 0: / / the branch executed by the child process, where the proc () method is passed in externally, that is, the current method only creates a new process, / / specific process processing logic, and the ngx_getpid () method is handed over to the external code block to define the process id ngx_pid = ngx_getpid (); proc (cycle, data); break of the newly created child process. Default: / / the parent process will come here break;} ngx_log_error (NGX_LOG_NOTICE, cycle- > log, 0, "start% s% P", name, pid); / / the parent process will come here, and the current pid is the pid ngx_ processes [s] .pid = pid; ngx_ processes [s] .exportable = 0 of the newly created child processes obtained by the parent process after fork (); if (respawn > = 0) {return pid } / / sets the properties of the current process and stores them in the corresponding location in the ngx_processes array ngx_ processes [s] .proc = proc; ngx_ processes [s] .data = data; ngx_ processes [s] .name = name; ngx_ processes [s] .exiting = 0; switch (respawn) {case NGX_PROCESS_NORESPAWN: ngx_ processes [s] .respawn = 0; ngx_ processes [s] .just _ spawn = 0; ngx_ processes [s] .detached = 0 Break; case NGX_PROCESS_JUST_SPAWN: ngx_ processes [s] .respawn = 0; ngx_ processes [s] .just _ spawn = 1; ngx_ processes [s] .detached = 0; break; case NGX_PROCESS_RESPAWN: ngx_ processes [s] .respawn = 1; ngx_ processes [s] .just _ spawn = 0; ngx_ processes [s] .detached = 0; break; case NGX_PROCESS_JUST_RESPAWN: ngx_ processes [s] .respawn = 1 Ngx_ processes [s]. Just _ spawn = 1; ngx_ processes [s] .detached = 0; break; case NGX_PROCESS_DETACHED: ngx_ processes [s] .respawn = 0; ngx_ processes [s]. Just _ spawn = 0; ngx_ processes [s]. Detached = 1; break;} if (s = = ngx_last_process) {ngx_last_process++;} return pid;}
The ngx_spawn_process () method ends up fork () a child process to execute the callback method specified in its second parameter. But before we do that, we need to make it clear that its call to the socketpair () method creates an anonymous pair of socket and stores them in the channel array of the current process, thus completing the creation of the channel array.
After the worker process starts, the ngx_worker_process_cycle () method is executed, which first initializes the worker process, including the processing of the inherited channel array. Because both the master process and the worker process keep the socket descriptor referred to by the channel array, in essence, the master process and each worker process only need to keep the descriptor on one side of the array. So here the worker process closes its saved descriptor on the other side of the initialization process. In nginx, the master process uniformly retains the socket descriptor of bit 0 of the channel array and closes the socket descriptor of bit 1, while the worker process closes the socket descriptor of bit 0 and retains the descriptor of bit 1. In this way, when the master process needs to communicate with the worker process, it only needs to write data to the channel [0], while the worker process listens to the channel [1] and receives the data writes from the master process. Let's first take a look at the source code of the initialization method ngx_worker_process_init () of the worker process:
/ * the main purpose here is to initialize the current process, setting its priority and opening file limits and other parameters. * finally, a connection listening to channel [1] will be added to the current process to continuously read messages from the master process, thus processing the corresponding * / static void ngx_worker_process_init (ngx_cycle_t * cycle, ngx_int_t worker) {sigset_t set; ngx_int_t n; ngx_time_t * tp; ngx_uint_t I; ngx_cpuset_t * cpu_affinity; struct rlimit rlmt; ngx_core_conf_t * ccf Ngx_listening_t * ls; / / set time zone related information if (ngx_set_environment (cycle, NULL) = = NULL) {/ * fatal * / exit (2);} ccf = (ngx_core_conf_t *) ngx_get_conf (cycle- > conf_ctx, ngx_core_module) / / set the priority of the current process if (worker > = 0 & & ccf- > priority! = 0) {if (setpriority (PRIO_PROCESS, 0, ccf- > priority) = =-1) {ngx_log_error (NGX_LOG_ALERT, cycle- > log, ngx_errno, "setpriority (% d) failed", ccf- > priority) }} / / sets the number of file handles that can be opened by the current process if (ccf- > rlimit_nofile! = NGX_CONF_UNSET) {rlmt.rlim_cur = (rlim_t) ccf- > rlimit_nofile; rlmt.rlim_max = (rlim_t) ccf- > rlimit_nofile If (setrlimit (RLIMIT_NOFILE, & rlmt) =-1) {ngx_log_error (NGX_LOG_ALERT, cycle- > log, ngx_errno, "setrlimit (RLIMIT_NOFILE,% I) failed", ccf- > rlimit_nofile);}} / / Changes the limit on the largest size of a core file (RLIMIT_CORE) for worker processes. / / in short, set the maximum size if (ccf- > rlimit_core! = NGX_CONF_UNSET) {rlmt.rlim_cur = (rlim_t) ccf- > rlimit_core; rlmt.rlim_max = (rlim_t) ccf- > rlimit_core that the core file can use. If (setrlimit (RLIMIT_CORE, & rlmt) =-1) {ngx_log_error (NGX_LOG_ALERT, cycle- > log, ngx_errno, "setrlimit (RLIMIT_CORE,% O) failed", ccf- > rlimit_core) }} / / geteuid () returns the id of the user executing the current program, where 0 indicates whether it is a root user if (geteuid () = = 0) {/ / setgid () method is used to change the id if (setgid (ccf- > group) = =-1) {ngx_log_error (NGX_LOG_EMERG, cycle- > log, ngx_errno, "setgid (% d) failed", ccf- > group); / * fatal * / exit (2) } / / initgroups () is the id if that changes the attached group (initgroups (ccf- > username, ccf- > group) =-1) {ngx_log_error (NGX_LOG_EMERG, cycle- > log, ngx_errno, "initgroups (% s,% d) failed", ccf- > username, ccf- > group) } / / change the user's id if (setuid (ccf- > user) = =-1) {ngx_log_error (NGX_LOG_EMERG, cycle- > log, ngx_errno, "setuid (% d) failed", ccf- > user); / * fatal * / exit (2) }} / / it should be noted that for cache manager and cache loader processes, the worker passed in here is-1, / / indicates that the two processes do not need to set the nucleophilic if (worker > = 0) {/ / get the CPU nucleophilic cpu_affinity of the current worker = ngx_get_cpu_affinity (worker); if (cpu_affinity) {/ / set the worker's nucleophilic ngx_setaffinity (cpu_affinity, cycle- > log) } # if (NGX_HAVE_PR_SET_DUMPABLE) if (prctl (PR_SET_DUMPABLE, 1,0,0,0) =-1) {ngx_log_error (NGX_LOG_ALERT, cycle- > log, ngx_errno, "prctl (PR_SET_DUMPABLE) failed") } # endif if (ccf- > working_directory.len) {/ / chdir () is used to change the current working directory to the path if (chdir ((char *) ccf- > working_directory.data) =-1) {ngx_log_error (NGX_LOG_ALERT, cycle- > log, ngx_errno, "chdir (\"% s\ ") failed", ccf- > working_directory.data); / * fatal * / exit (2) }} / / initialize the empty set instruction set sigemptyset (& set); / / ◆ SIG_BLOCK: add the signal that the set parameter points to the signal set to the signal mask. / / ◆ SIG_UNBLOCK: removes the signal in the signal set pointed to by the set parameter from the signal mask. / / ◆ SIG_SETMASK: sets the set parameter to the signal set as the signal mask. / / this is the direct initialization of the signal set to be blocked. The default is empty set if (sigprocmask (SIG_SETMASK, & set, NULL) =-1) {ngx_log_error (NGX_LOG_ALERT, cycle- > log, ngx_errno, "sigprocmask () failed");} tp = ngx_timeofday (); srandom (unsigned) ngx_pid sec ^ tp- > msec); ls = cycle- > listening.elts; for (I = 0; I)
< cycle->Listening.nelts; iSuppli +) {ls[ I] .modules = NULL;} / / the init_process () method of each module is called here to initialize the process module for (I = 0; cycle- > modules [I]; iDiplus +) {if (cycle- > modules [I]-> init_process) {if (cycle- > modules [I]-> init_process (cycle) = = NGX_ERROR) {/ * fatal * / exit (2) } / / this is mainly to close the channel [1] pipe handle for (n = 0; n) of other processes in the current process
< ngx_last_process; n++) { if (ngx_processes[n].pid == -1) { continue; } if (n == ngx_process_slot) { continue; } if (ngx_processes[n].channel[1] == -1) { continue; } if (close(ngx_processes[n].channel[1]) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->Log, ngx_errno, "close () channel failed");}} / close the current process's channel [0] pipe handle if (close (ngx_ processes [NGX _ process_slot] .channel [0]) =-1) {ngx_log_error (NGX_LOG_ALERT, cycle- > log, ngx_errno, "close () channel failed");} # if 0 ngx_last_process = 0 # endif / / ngx_channel points to the channel [1] handle of the current process, that is, the handle that listens to messages sent by the master process. / / in the current method, a connection object is first created for the current handle and encapsulated as an event, and then the event is added to the corresponding event model queue to listen for the events of the current handle. The event processing logic is mainly carried out by the ngx_channel_handler () / / method here. The main processing logic of ngx_channel_handler here is to set some flag bits of the current process based on the messages currently received, / / or update some cached data, so that the real logic of processing in the event process is achieved by constantly checking these flag bits in the current event loop. Therefore, the processing efficiency of ngx_channel_handler here is very high if (ngx_add_channel_event (cycle, ngx_channel, NGX_READ_EVENT, ngx_channel_handler) = = NGX_ERROR) {/ * fatal * / exit (2);}}
The main purpose of this method is to initialize the worker process. Here, we mainly need to pay attention to the final traversal of the ngx_processes array, which stores the relevant information about each process in the current nginx. During traversal, the channel [1] handle of the remaining processes held by the current process is closed, while the channel [0] handle is retained, so that if the current process needs to communicate with other processes, it only needs to write data to the target process's channel [0]. After the traversal is complete, the current process closes its channel [0] handle, leaving the channel [1] handle. Finally, a listening event to channel [1] is added to the current process through the ngx_add_channel_event () method. Here, the second parameter passed in when calling the ngx_add_channel_event () method is ngx_channel, which is assigned in the previous ngx_spawn_process () method and points to the socket handle of the current process's channel [1].
With regard to the ngx_add_channel_event () method, the essence is to create an event of the ngx_event_t structure and then add it to the handle of the event model that is currently in use, such as epoll. The implementation source code for this method is not discussed here, but we need to focus on the callback method when the event is triggered, that is, the third parameter ngx_channel_handler () method passed in when the ngx_add_channel_event () method is called. The following is the source code of this method:
Static void ngx_channel_handler (ngx_event_t * ev) {ngx_int_t n; ngx_channel_t ch; ngx_connection_t * c; if (ev- > timedout) {ev- > timedout = 0; return;} c = ev- > data; for (;;) {/ / keep reading messages from the master process in an infinite for loop n = ngx_read_channel (c-> fd, & ch, sizeof (ngx_channel_t), ev- > log) / / if there is an error in reading the message, the current handle may be invalid, so you need to close the current connection if (n = = NGX_ERROR) {if (ngx_event_flags & NGX_USE_EPOLL_EVENT) {ngx_del_conn (c, 0);} ngx_close_connection (c); return } if (ngx_event_flags & NGX_USE_EVENTPORT_EVENT) {if (ngx_add_event (ev, NGX_READ_EVENT, 0) = = NGX_ERROR) {return;}} if (n = = NGX_AGAIN) {return;} / / A pair of sent messages to process switch (ch.command) {/ / if it is a quit message, set the quit flag case NGX_CMD_QUIT: ngx_quit = 1 Break; / / if terminate message, set terminate flag bit case NGX_CMD_TERMINATE: ngx_terminate = 1; break; / / if it is reopen message, set reopen flag bit case NGX_CMD_REOPEN: ngx_reopen = 1; break / / if it is a new process message, update the data at the corresponding location of the current ngx_processes array case NGX_CMD_OPEN_CHANNEL: ngx_ processes [ch.slot] .pid = ch.pid; ngx_ processes [ch.slot] .channel [0] = ch.fd; break / / if it is a message that closes channel, close the handle to the corresponding position of the ngx_processes array case NGX_CMD_CLOSE_CHANNEL: if (ngx_ processes [ch.slot] .channel [0]) =-1) {ngx_log_error (NGX_LOG_ALERT, ev- > log, ngx_errno, "close () channel failed");} ngx_ processes [ch.slot] .channel [0] =-1; break }}}
In the ngx_channel_handler () method, the main purpose is to read the data in the listening socket handle, and the data is carried in a ngx_channel_t structure, which is the structure used by nginx to communicate between master and the worker process, which specifies the type of event that is currently occurring and the process information in which the event occurs. The following is the declaration of the ngx_channel_t structure:
Typedef struct {/ / the current event type ngx_uint_t command; / / the pid ngx_pid_t pid; of the occurrence of the event / / the subscript ngx_int_t slot; / / the value of the channel [0] descriptor of the process of the occurrence of the event in the ngx_processes array
After reading the data of the ngx_channel_t structure from the channel [1] of the current process, the ngx_channel_handler () method updates the status of the corresponding flag bits according to the type of event that occurred, and updates the state information of the corresponding process in the ngx_processes array of the current process.
After handling the events sent by the master process, the worker process continues its loop, in which it checks the status of the flag bits it is interested in, and then executes the corresponding logic based on those states. The following is the source code for the loop that the worker process works on:
/ * enter the working cycle of the worker process * / static void ngx_worker_process_cycle (ngx_cycle_t * cycle, void * data) {ngx_int_t worker = (intptr_t) data; ngx_process = NGX_PROCESS_WORKER; ngx_worker = worker; / / initialize the worker process. The source code of this method is explained earlier: ngx_worker_process_init (cycle, worker); ngx_setproctitle ("worker process"); for ( ) {if (ngx_exiting) {/ / the main purpose here is to check whether any events are in a non-cancelable state, that is, whether all events have been cancelled. If cancelled, / / will return NGX_OK. The logic here can be understood as if it is marked as ngx_exiting, at this point, if there are any uncancelled / / events, then go to the following ngx_process_events_and_timers () method, so that the unfinished events are handled, / / and then go to this position again in the loop, and the final if condition is true. To perform the work of exiting the worker process if (ngx_event_no_timers_left () = = NGX_OK) {ngx_log_error (NGX_LOG_NOTICE, cycle- > log, 0, "exiting") Ngx_worker_process_exit (cycle);}} ngx_log_debug0 (NGX_LOG_DEBUG_EVENT, cycle- > log, 0, "worker cycle"); / / here, by checking whether there is a corresponding event in the corresponding event model, and then putting it into the queue for processing. / / here is the core method ngx_process_events_and_timers (cycle) of the worker process handling events. / / here ngx_terminate is the option to forcibly close nginx. If a forced shutdown nginx command is sent to nginx, the current process will directly exit if (ngx_terminate) {ngx_log_error (NGX_LOG_NOTICE, cycle- > log, 0, "exiting"); ngx_worker_process_exit (cycle);} / here ngx_quit is an elegant exit option. Here, the ngx_exiting is set to 1, which is used to indicate that the current process needs to exit. / / then the following three tasks will be performed: / / 1. Add an event to the event queue to handle the currently active connection, set its close flag position to 1, and execute the connection / / current processing method to complete the connection event as soon as possible; / / 2. Close the socket handle that is listening in the current cycle; / / 3. Mark the close status of all currently idle connections as 1, and then call their connection handling methods. If (ngx_quit) {ngx_quit = 0; ngx_log_error (NGX_LOG_NOTICE, cycle- > log, 0, "gracefully shutting down"); ngx_setproctitle ("worker process is shutting down"); if (! ngx_exiting) {ngx_exiting = 1; ngx_set_shutdown_timer (cycle); ngx_close_listening_sockets (cycle); ngx_close_idle_connections (cycle) }} / / ngx_reopen mainly reopens all files of nginx, such as switching nginx log files, etc. If (ngx_reopen) {ngx_reopen = 0; ngx_log_error (NGX_LOG_NOTICE, cycle- > log, 0, "reopening logs"); ngx_reopen_files (cycle,-1);}
As you can see, the worker process mainly deals with the flag bits related to whether nginx exits, as well as whether nginx rereads the flag bits of the configuration file.
Thank you for reading! This is the end of this article on "the implementation example of the worker process cycle in nginx". I hope the above content can be of some help to you, so that you can learn more knowledge. if you think the article is good, you can share it out for more people to see!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.