如不做特殊说明,本博客所使用的 nginx 源码版本是 1.0.14,[] 中是代码所在的文件!

这一节我们分析ngx_start_worker_processes(),该函数代码比较少,因为它通过调用函数实现功能的,先贴出代码:

[os/unix/ngx_process_cycle.c]

 377 /* 这是 master 线程调用的、用来生成 worker 进程的入口 */
 378 static void
 379 ngx_start_worker_processes(ngx_cycle_t *cycle, ngx_int_t n, ngx_int_t type)
 380 {
 381     ngx_int_t      i;
 382     ngx_channel_t  ch;
 383 
 384     ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "start worker processes");
 385 
 386     ch.command = NGX_CMD_OPEN_CHANNEL;
 387 
 388     /* n 代表要创建多少个 worker 进程 --- 由配置文件中的 worker_process 的值决定的 */
 389     for (i = 0; i < n; i++) {
 390 
 391         /* 多 CPU 获取 CPU 的信息 */
 392         cpu_affinity = ngx_get_cpu_affinity(i);
 393         /* 创建进程函数              */
 394         /* ngx_spawn_process() 在 OS/ngx_process.h/c 文件中定义 ,ngx_worker_process_cycle() 是新建进程要执行的函数 */
 395         ngx_spawn_process(cycle, ngx_worker_process_cycle, NULL,
 396                           "worker process", type);
 397 
 398         ch.pid = ngx_processes[ngx_process_slot].pid;
 399         ch.slot = ngx_process_slot;
 400         ch.fd = ngx_processes[ngx_process_slot].channel[0];
 401 
 402         /* 用来干嘛? */
 403         ngx_pass_open_channel(cycle, &ch);
 404     }
 405 }

  1. 我们可以看到,该函数接受三个参数,分别是全局变量 cycle,要创建 worker 进程的个数 n, 要创建进程的类型 type,type有以下 5 个值。

    a. NGX_PROCESS_RESPAWN

    b. NGX_PROCESS_NORESPAWN

    c. NGX_PROCESS_JUST_SPAWN

    d. NGX_PROCESS_JUST_RESPAWN

    e. NGX_PROCESS_DETACHED

   type 的值将影响进程结构体 ngx_process_t 的 respawn、detached、just_spawn 标志位的值。

  2. 386 行设置 ngx_channerl_t 结构体 command 的变量为  NGX_CMD_OPEN_CHANNEL,暂时还没分析到这个 channel,我猜测是意味着打开 channel,开始进行父子进程间的通信了。

  3. 389-404 行通过 for 循环创建 n 个 worker 进程,其中最终要的就是 ngx_spawn_process() 函数了,该函数真正用来创建进程。我慢来看一些 ngx_spawn_process() 的代码:

[os/unix/ngx_process.c]

 86 ngx_pid_t
 87 ngx_spawn_process(ngx_cycle_t *cycle, ngx_spawn_proc_pt proc, void *data,
 88     char *name, ngx_int_t respawn)
 89 {
 90     u_long     on;
 91     ngx_pid_t  pid;
 92 
 93     ngx_int_t  s;
 94 
 95 
 96     if (respawn >= 0) {
 97         s = respawn;
 98 
 99     } else {
100 
101         for (s = 0; s < ngx_last_process; s++) {
102             if (ngx_processes[s].pid == -1) {
103                 break;
104             }
105         }
106 
107 
108         if (s == NGX_MAX_PROCESSES) {
109             ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
110                           "no more than %d processes can be spawned",
111                           NGX_MAX_PROCESSES);
112             return NGX_INVALID_PID;
113         }
114     }
115 
116     if (respawn != NGX_PROCESS_DETACHED) {
117 
118         /* Solaris 9 still has no AF_LOCAL */
119         /* 创建一对 socket 描述符存放在变量 ngx_process[s].channel 中*/
120         if (socketpair(AF_UNIX, SOCK_STREAM, 0, ngx_processes[s].channel) == -1)
121         {
122             ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
123                           "socketpair() failed while spawning \"%s\"", name);
124             return NGX_INVALID_PID;
125         }
126 
127         ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0,
128                        "channel %d:%d",
129                        ngx_processes[s].channel[0],
130                        ngx_processes[s].channel[1]);
131 
132         /* 这里将 channel[0],channel[1] 看着是管道的两端 */
133         /* 将 channel[0] 设置为非阻塞 */
134         if (ngx_nonblocking(ngx_processes[s].channel[0]) == -1) {
135             ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
136                           ngx_nonblocking_n " failed while spawning \"%s\"",
137                           name);
138             ngx_close_channel(ngx_processes[s].channel, cycle->log);
139             return NGX_INVALID_PID;
140         }
141 
142         /* 将 channel[1] 设置为非阻塞 */
143         if (ngx_nonblocking(ngx_processes[s].channel[1]) == -1) {
144             ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
145                           ngx_nonblocking_n " failed while spawning \"%s\"",
146                           name);
147             ngx_close_channel(ngx_processes[s].channel, cycle->log);
148             return NGX_INVALID_PID;
149         }
150 
151         on = 1;
152         if (ioctl(ngx_processes[s].channel[0], FIOASYNC, &on) == -1) {
153             ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
154                           "ioctl(FIOASYNC) failed while spawning \"%s\"", name);
155             ngx_close_channel(ngx_processes[s].channel, cycle->log);
156             return NGX_INVALID_PID;
157         }
158 
159         /* F_SETOWN 设置接受 SIGIO 和 SIGURG 信号的进程 ID 或 进程组 ID */
160         if (fcntl(ngx_processes[s].channel[0], F_SETOWN, ngx_pid) == -1) {
161             ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
162                           "fcntl(F_SETOWN) failed while spawning \"%s\"", name);
163             ngx_close_channel(ngx_processes[s].channel, cycle->log);
164             return NGX_INVALID_PID;
165         }
166 
167         if (fcntl(ngx_processes[s].channel[0], F_SETFD, FD_CLOEXEC) == -1) {
168             ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
169                           "fcntl(FD_CLOEXEC) failed while spawning \"%s\"",
170                            name);
171             ngx_close_channel(ngx_processes[s].channel, cycle->log);
172             return NGX_INVALID_PID;
173         }
174 
175         if (fcntl(ngx_processes[s].channel[1], F_SETFD, FD_CLOEXEC) == -1) {
176             ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
177                           "fcntl(FD_CLOEXEC) failed while spawning \"%s\"",
178                            name);
179             ngx_close_channel(ngx_processes[s].channel, cycle->log);
180             return NGX_INVALID_PID;
181         }
182 
183         ngx_channel = ngx_processes[s].channel[1];
184 
185     } else {
186         ngx_processes[s].channel[0] = -1;
187         ngx_processes[s].channel[1] = -1;
188     }
189 
190     /* 设置工作进程的下标 */
191     ngx_process_slot = s;
192 
193     /* 创建进程 */
194     pid = fork();
195 
196     switch (pid) {
197 
198     /* 创建进程失败 */
199     case -1:
200         ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
201                       "fork() failed while spawning \"%s\"", name);
202         ngx_close_channel(ngx_processes[s].channel, cycle->log);
203         return NGX_INVALID_PID;
204     /* 如果是父进程 */
205     case 0:
206         ngx_pid = ngx_getpid();
207 
208         proc(cycle, data);
209         break;
210 
211     default:
212         break;
213     }
214 
215     ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "start %s %P", name, pid);
216 
217     ngx_processes[s].pid = pid;
218     ngx_processes[s].exited = 0;
219 
220     if (respawn >= 0) {
221         return pid;
222     }
223 
224     ngx_processes[s].proc = proc;
225     ngx_processes[s].data = data;
226     ngx_processes[s].name = name;
227     ngx_processes[s].exiting = 0;
228 
229     switch (respawn) {
230 
231     case NGX_PROCESS_NORESPAWN:
232         ngx_processes[s].respawn = 0;
233         ngx_processes[s].just_spawn = 0;
234         ngx_processes[s].detached = 0;
235         break;
236 
237     case NGX_PROCESS_JUST_SPAWN:
238         ngx_processes[s].respawn = 0;
239         ngx_processes[s].just_spawn = 1;
240         ngx_processes[s].detached = 0;
241         break;
242 
243     case NGX_PROCESS_RESPAWN:
244         ngx_processes[s].respawn = 1;
245         ngx_processes[s].just_spawn = 0;
246         ngx_processes[s].detached = 0;
247         break;
248 
249     case NGX_PROCESS_JUST_RESPAWN:
250         ngx_processes[s].respawn = 1;
251         ngx_processes[s].just_spawn = 1;
252         ngx_processes[s].detached = 0;
253         break;
254 
255     case NGX_PROCESS_DETACHED:
256         ngx_processes[s].respawn = 0;
257         ngx_processes[s].just_spawn = 0;
258         ngx_processes[s].detached = 1;
259         break;
260     }
261 
262     if (s == ngx_last_process) {
263         ngx_last_process++;
264     }
265 
266     return pid;
267 }
ngx_spawn_process()函数代码

相关文章:

  • 2022-01-17
  • 2021-04-09
  • 2021-12-27
猜你喜欢
  • 2021-11-16
  • 2021-07-14
  • 2021-09-21
  • 2022-12-23
  • 2021-04-16
  • 2022-12-23
  • 2022-02-08
相关资源
相似解决方案