Mercurial > hg > nginx-vendor-0-5
comparison src/os/unix/ngx_process_cycle.c @ 0:f0b350454894 NGINX_0_1_0
nginx 0.1.0
*) The first public version.
author | Igor Sysoev <http://sysoev.ru> |
---|---|
date | Mon, 04 Oct 2004 00:00:00 +0400 |
parents | |
children | cc9f381affaa |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:f0b350454894 |
---|---|
1 | |
2 /* | |
3 * Copyright (C) Igor Sysoev | |
4 */ | |
5 | |
6 | |
7 #include <ngx_config.h> | |
8 #include <ngx_core.h> | |
9 #include <ngx_event.h> | |
10 #include <ngx_channel.h> | |
11 | |
12 | |
13 static void ngx_start_worker_processes(ngx_cycle_t *cycle, ngx_int_t n, | |
14 ngx_int_t type); | |
15 static void ngx_signal_worker_processes(ngx_cycle_t *cycle, int signo); | |
16 static ngx_uint_t ngx_reap_childs(ngx_cycle_t *cycle); | |
17 static void ngx_master_exit(ngx_cycle_t *cycle, ngx_master_ctx_t *ctx); | |
18 static void ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data); | |
19 static void ngx_channel_handler(ngx_event_t *ev); | |
20 #if (NGX_THREADS) | |
21 static void ngx_wakeup_worker_threads(ngx_cycle_t *cycle); | |
22 static void *ngx_worker_thread_cycle(void *data); | |
23 #endif | |
24 | |
25 | |
26 ngx_uint_t ngx_process; | |
27 ngx_pid_t ngx_pid; | |
28 ngx_uint_t ngx_threaded; | |
29 | |
30 sig_atomic_t ngx_reap; | |
31 sig_atomic_t ngx_timer; | |
32 sig_atomic_t ngx_sigio; | |
33 sig_atomic_t ngx_terminate; | |
34 sig_atomic_t ngx_quit; | |
35 ngx_uint_t ngx_exiting; | |
36 sig_atomic_t ngx_reconfigure; | |
37 sig_atomic_t ngx_reopen; | |
38 | |
39 sig_atomic_t ngx_change_binary; | |
40 ngx_pid_t ngx_new_binary; | |
41 ngx_uint_t ngx_inherited; | |
42 ngx_uint_t ngx_daemonized; | |
43 | |
44 sig_atomic_t ngx_noaccept; | |
45 ngx_uint_t ngx_noaccepting; | |
46 ngx_uint_t ngx_restart; | |
47 | |
48 | |
49 #if (NGX_THREADS) | |
50 volatile ngx_thread_t ngx_threads[NGX_MAX_THREADS]; | |
51 ngx_int_t ngx_threads_n; | |
52 #endif | |
53 | |
54 | |
55 u_char master_process[] = "master process"; | |
56 | |
57 | |
58 void ngx_master_process_cycle(ngx_cycle_t *cycle, ngx_master_ctx_t *ctx) | |
59 { | |
60 char *title; | |
61 u_char *p; | |
62 size_t size; | |
63 ngx_int_t i; | |
64 sigset_t set; | |
65 struct timeval tv; | |
66 struct itimerval itv; | |
67 ngx_uint_t live; | |
68 ngx_msec_t delay; | |
69 ngx_core_conf_t *ccf; | |
70 | |
71 sigemptyset(&set); | |
72 sigaddset(&set, SIGCHLD); | |
73 sigaddset(&set, SIGALRM); | |
74 sigaddset(&set, SIGIO); | |
75 sigaddset(&set, SIGINT); | |
76 sigaddset(&set, ngx_signal_value(NGX_RECONFIGURE_SIGNAL)); | |
77 sigaddset(&set, ngx_signal_value(NGX_REOPEN_SIGNAL)); | |
78 sigaddset(&set, ngx_signal_value(NGX_NOACCEPT_SIGNAL)); | |
79 sigaddset(&set, ngx_signal_value(NGX_TERMINATE_SIGNAL)); | |
80 sigaddset(&set, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); | |
81 sigaddset(&set, ngx_signal_value(NGX_CHANGEBIN_SIGNAL)); | |
82 | |
83 if (sigprocmask(SIG_BLOCK, &set, NULL) == -1) { | |
84 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, | |
85 "sigprocmask() failed"); | |
86 } | |
87 | |
88 sigemptyset(&set); | |
89 | |
90 | |
91 size = sizeof(master_process); | |
92 | |
93 for (i = 0; i < ctx->argc; i++) { | |
94 size += ngx_strlen(ctx->argv[i]) + 1; | |
95 } | |
96 | |
97 title = ngx_palloc(cycle->pool, size); | |
98 | |
99 p = ngx_cpymem(title, master_process, sizeof(master_process) - 1); | |
100 for (i = 0; i < ctx->argc; i++) { | |
101 *p++ = ' '; | |
102 p = ngx_cpystrn(p, (u_char *) ctx->argv[i], size); | |
103 } | |
104 | |
105 ngx_setproctitle(title); | |
106 | |
107 | |
108 ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); | |
109 | |
110 ngx_start_worker_processes(cycle, ccf->worker_processes, | |
111 NGX_PROCESS_RESPAWN); | |
112 | |
113 ngx_new_binary = 0; | |
114 delay = 0; | |
115 live = 1; | |
116 | |
117 for ( ;; ) { | |
118 if (delay) { | |
119 delay *= 2; | |
120 | |
121 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, | |
122 "temination cycle: %d", delay); | |
123 | |
124 itv.it_interval.tv_sec = 0; | |
125 itv.it_interval.tv_usec = 0; | |
126 itv.it_value.tv_sec = delay / 1000; | |
127 itv.it_value.tv_usec = (delay % 1000 ) * 1000; | |
128 | |
129 if (setitimer(ITIMER_REAL, &itv, NULL) == -1) { | |
130 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, | |
131 "setitimer() failed"); | |
132 } | |
133 } | |
134 | |
135 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "sigsuspend"); | |
136 | |
137 sigsuspend(&set); | |
138 | |
139 ngx_gettimeofday(&tv); | |
140 ngx_time_update(tv.tv_sec); | |
141 | |
142 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "wake up"); | |
143 | |
144 if (ngx_reap) { | |
145 ngx_reap = 0; | |
146 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "reap childs"); | |
147 | |
148 live = ngx_reap_childs(cycle); | |
149 } | |
150 | |
151 if (!live && (ngx_terminate || ngx_quit)) { | |
152 ngx_master_exit(cycle, ctx); | |
153 } | |
154 | |
155 if (ngx_terminate) { | |
156 if (delay == 0) { | |
157 delay = 50; | |
158 } | |
159 | |
160 if (delay > 1000) { | |
161 ngx_signal_worker_processes(cycle, SIGKILL); | |
162 } else { | |
163 ngx_signal_worker_processes(cycle, | |
164 ngx_signal_value(NGX_TERMINATE_SIGNAL)); | |
165 } | |
166 | |
167 continue; | |
168 } | |
169 | |
170 if (ngx_quit) { | |
171 ngx_signal_worker_processes(cycle, | |
172 ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); | |
173 continue; | |
174 } | |
175 | |
176 if (ngx_timer) { | |
177 ngx_timer = 0; | |
178 ngx_start_worker_processes(cycle, ccf->worker_processes, | |
179 NGX_PROCESS_JUST_RESPAWN); | |
180 live = 1; | |
181 ngx_signal_worker_processes(cycle, | |
182 ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); | |
183 } | |
184 | |
185 if (ngx_reconfigure) { | |
186 ngx_reconfigure = 0; | |
187 | |
188 if (ngx_new_binary) { | |
189 ngx_log_error(NGX_LOG_INFO, cycle->log, 0, "start new workers"); | |
190 | |
191 ngx_start_worker_processes(cycle, ccf->worker_processes, | |
192 NGX_PROCESS_RESPAWN); | |
193 ngx_noaccepting = 0; | |
194 | |
195 continue; | |
196 } | |
197 | |
198 ngx_log_error(NGX_LOG_INFO, cycle->log, 0, "reconfiguring"); | |
199 | |
200 cycle = ngx_init_cycle(cycle); | |
201 if (cycle == NULL) { | |
202 cycle = (ngx_cycle_t *) ngx_cycle; | |
203 continue; | |
204 } | |
205 | |
206 ngx_cycle = cycle; | |
207 ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, | |
208 ngx_core_module); | |
209 ngx_start_worker_processes(cycle, ccf->worker_processes, | |
210 NGX_PROCESS_JUST_RESPAWN); | |
211 live = 1; | |
212 ngx_signal_worker_processes(cycle, | |
213 ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); | |
214 } | |
215 | |
216 if (ngx_restart) { | |
217 ngx_restart = 0; | |
218 ngx_start_worker_processes(cycle, ccf->worker_processes, | |
219 NGX_PROCESS_RESPAWN); | |
220 live = 1; | |
221 } | |
222 | |
223 if (ngx_reopen) { | |
224 ngx_reopen = 0; | |
225 ngx_log_error(NGX_LOG_INFO, cycle->log, 0, "reopening logs"); | |
226 ngx_reopen_files(cycle, ccf->user); | |
227 ngx_signal_worker_processes(cycle, | |
228 ngx_signal_value(NGX_REOPEN_SIGNAL)); | |
229 } | |
230 | |
231 if (ngx_change_binary) { | |
232 ngx_change_binary = 0; | |
233 ngx_log_error(NGX_LOG_INFO, cycle->log, 0, "changing binary"); | |
234 ngx_new_binary = ngx_exec_new_binary(cycle, ctx->argv); | |
235 } | |
236 | |
237 if (ngx_noaccept) { | |
238 ngx_noaccept = 0; | |
239 ngx_noaccepting = 1; | |
240 ngx_signal_worker_processes(cycle, | |
241 ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); | |
242 } | |
243 } | |
244 } | |
245 | |
246 | |
247 void ngx_single_process_cycle(ngx_cycle_t *cycle, ngx_master_ctx_t *ctx) | |
248 { | |
249 ngx_uint_t i; | |
250 | |
251 #if 0 | |
252 ngx_setproctitle("single worker process"); | |
253 #endif | |
254 | |
255 ngx_init_temp_number(); | |
256 | |
257 for (i = 0; ngx_modules[i]; i++) { | |
258 if (ngx_modules[i]->init_process) { | |
259 if (ngx_modules[i]->init_process(cycle) == NGX_ERROR) { | |
260 /* fatal */ | |
261 exit(2); | |
262 } | |
263 } | |
264 } | |
265 | |
266 for ( ;; ) { | |
267 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "worker cycle"); | |
268 | |
269 ngx_process_events(cycle); | |
270 | |
271 if (ngx_terminate || ngx_quit) { | |
272 ngx_master_exit(cycle, ctx); | |
273 } | |
274 | |
275 if (ngx_reconfigure) { | |
276 ngx_reconfigure = 0; | |
277 ngx_log_error(NGX_LOG_INFO, cycle->log, 0, "reconfiguring"); | |
278 | |
279 cycle = ngx_init_cycle(cycle); | |
280 if (cycle == NULL) { | |
281 cycle = (ngx_cycle_t *) ngx_cycle; | |
282 continue; | |
283 } | |
284 | |
285 ngx_cycle = cycle; | |
286 } | |
287 | |
288 if (ngx_reopen) { | |
289 ngx_reopen = 0; | |
290 ngx_log_error(NGX_LOG_INFO, cycle->log, 0, "reopening logs"); | |
291 ngx_reopen_files(cycle, (ngx_uid_t) -1); | |
292 } | |
293 } | |
294 } | |
295 | |
296 | |
297 static void ngx_start_worker_processes(ngx_cycle_t *cycle, ngx_int_t n, | |
298 ngx_int_t type) | |
299 { | |
300 ngx_int_t i; | |
301 ngx_channel_t ch; | |
302 struct itimerval itv; | |
303 | |
304 ngx_log_error(NGX_LOG_INFO, cycle->log, 0, "start worker processes"); | |
305 | |
306 ch.command = NGX_CMD_OPEN_CHANNEL; | |
307 | |
308 while (n--) { | |
309 ngx_spawn_process(cycle, ngx_worker_process_cycle, NULL, | |
310 "worker process", type); | |
311 | |
312 ch.pid = ngx_processes[ngx_process_slot].pid; | |
313 ch.slot = ngx_process_slot; | |
314 ch.fd = ngx_processes[ngx_process_slot].channel[0]; | |
315 | |
316 for (i = 0; i < ngx_last_process; i++) { | |
317 | |
318 if (i == ngx_process_slot | |
319 || ngx_processes[i].pid == -1 | |
320 || ngx_processes[i].channel[0] == -1) | |
321 { | |
322 continue; | |
323 } | |
324 | |
325 ngx_log_debug6(NGX_LOG_DEBUG_CORE, cycle->log, 0, | |
326 "pass channel s:%d pid:" PID_T_FMT | |
327 " fd:%d to s:%d pid:" PID_T_FMT " fd:%d", | |
328 ch.slot, ch.pid, ch.fd, | |
329 i, ngx_processes[i].pid, | |
330 ngx_processes[i].channel[0]); | |
331 | |
332 /* TODO: NGX_AGAIN */ | |
333 | |
334 ngx_write_channel(ngx_processes[i].channel[0], | |
335 &ch, sizeof(ngx_channel_t), cycle->log); | |
336 } | |
337 } | |
338 | |
339 /* | |
340 * we have to limit the maximum life time of the worker processes | |
341 * by 10 days because our millisecond event timer is limited | |
342 * by 24 days on 32-bit platforms | |
343 */ | |
344 | |
345 itv.it_interval.tv_sec = 0; | |
346 itv.it_interval.tv_usec = 0; | |
347 itv.it_value.tv_sec = 10 * 24 * 60 * 60; | |
348 itv.it_value.tv_usec = 0; | |
349 | |
350 if (setitimer(ITIMER_REAL, &itv, NULL) == -1) { | |
351 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, | |
352 "setitimer() failed"); | |
353 } | |
354 } | |
355 | |
356 | |
357 static void ngx_signal_worker_processes(ngx_cycle_t *cycle, int signo) | |
358 { | |
359 ngx_int_t i; | |
360 ngx_err_t err; | |
361 ngx_channel_t ch; | |
362 | |
363 | |
364 switch (signo) { | |
365 | |
366 case ngx_signal_value(NGX_SHUTDOWN_SIGNAL): | |
367 ch.command = NGX_CMD_QUIT; | |
368 break; | |
369 | |
370 case ngx_signal_value(NGX_TERMINATE_SIGNAL): | |
371 ch.command = NGX_CMD_TERMINATE; | |
372 break; | |
373 | |
374 case ngx_signal_value(NGX_REOPEN_SIGNAL): | |
375 ch.command = NGX_CMD_REOPEN; | |
376 break; | |
377 | |
378 default: | |
379 ch.command = 0; | |
380 } | |
381 | |
382 ch.fd = -1; | |
383 | |
384 | |
385 for (i = 0; i < ngx_last_process; i++) { | |
386 | |
387 ngx_log_debug7(NGX_LOG_DEBUG_EVENT, cycle->log, 0, | |
388 "child: %d " PID_T_FMT " e:%d t:%d d:%d r:%d j:%d", | |
389 i, | |
390 ngx_processes[i].pid, | |
391 ngx_processes[i].exiting, | |
392 ngx_processes[i].exited, | |
393 ngx_processes[i].detached, | |
394 ngx_processes[i].respawn, | |
395 ngx_processes[i].just_respawn); | |
396 | |
397 if (ngx_processes[i].detached || ngx_processes[i].pid == -1) { | |
398 continue; | |
399 } | |
400 | |
401 if (ngx_processes[i].just_respawn) { | |
402 ngx_processes[i].just_respawn = 0; | |
403 continue; | |
404 } | |
405 | |
406 if (ngx_processes[i].exiting | |
407 && signo == ngx_signal_value(NGX_SHUTDOWN_SIGNAL)) | |
408 { | |
409 continue; | |
410 } | |
411 | |
412 if (ch.command) { | |
413 if (ngx_write_channel(ngx_processes[i].channel[0], | |
414 &ch, sizeof(ngx_channel_t), cycle->log) == NGX_OK) | |
415 { | |
416 if (signo != ngx_signal_value(NGX_REOPEN_SIGNAL)) { | |
417 ngx_processes[i].exiting = 1; | |
418 } | |
419 | |
420 continue; | |
421 } | |
422 } | |
423 | |
424 ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0, | |
425 "kill (" PID_T_FMT ", %d)" , | |
426 ngx_processes[i].pid, signo); | |
427 | |
428 if (kill(ngx_processes[i].pid, signo) == -1) { | |
429 err = ngx_errno; | |
430 ngx_log_error(NGX_LOG_ALERT, cycle->log, err, | |
431 "kill(%d, %d) failed", | |
432 ngx_processes[i].pid, signo); | |
433 | |
434 if (err == NGX_ESRCH) { | |
435 ngx_processes[i].exited = 1; | |
436 ngx_processes[i].exiting = 0; | |
437 ngx_reap = 1; | |
438 } | |
439 | |
440 continue; | |
441 } | |
442 | |
443 if (signo != ngx_signal_value(NGX_REOPEN_SIGNAL)) { | |
444 ngx_processes[i].exiting = 1; | |
445 } | |
446 } | |
447 } | |
448 | |
449 | |
450 static ngx_uint_t ngx_reap_childs(ngx_cycle_t *cycle) | |
451 { | |
452 ngx_int_t i, n; | |
453 ngx_uint_t live; | |
454 ngx_channel_t ch; | |
455 | |
456 ch.command = NGX_CMD_CLOSE_CHANNEL; | |
457 ch.fd = -1; | |
458 | |
459 live = 0; | |
460 for (i = 0; i < ngx_last_process; i++) { | |
461 | |
462 ngx_log_debug7(NGX_LOG_DEBUG_EVENT, cycle->log, 0, | |
463 "child: %d " PID_T_FMT " e:%d t:%d d:%d r:%d j:%d", | |
464 i, | |
465 ngx_processes[i].pid, | |
466 ngx_processes[i].exiting, | |
467 ngx_processes[i].exited, | |
468 ngx_processes[i].detached, | |
469 ngx_processes[i].respawn, | |
470 ngx_processes[i].just_respawn); | |
471 | |
472 if (ngx_processes[i].pid == -1) { | |
473 continue; | |
474 } | |
475 | |
476 if (ngx_processes[i].exited) { | |
477 | |
478 if (!ngx_processes[i].detached) { | |
479 ngx_close_channel(ngx_processes[i].channel, cycle->log); | |
480 | |
481 ngx_processes[i].channel[0] = -1; | |
482 ngx_processes[i].channel[1] = -1; | |
483 | |
484 ch.pid = ngx_processes[i].pid; | |
485 ch.slot = i; | |
486 | |
487 for (n = 0; n < ngx_last_process; n++) { | |
488 if (ngx_processes[n].exited | |
489 || ngx_processes[n].pid == -1 | |
490 || ngx_processes[n].channel[0] == -1) | |
491 { | |
492 continue; | |
493 } | |
494 | |
495 ngx_log_debug3(NGX_LOG_DEBUG_CORE, cycle->log, 0, | |
496 "pass close channel s:%d pid:" PID_T_FMT | |
497 " to:" PID_T_FMT, ch.slot, ch.pid, ngx_processes[n].pid); | |
498 | |
499 /* TODO: NGX_AGAIN */ | |
500 | |
501 ngx_write_channel(ngx_processes[n].channel[0], | |
502 &ch, sizeof(ngx_channel_t), cycle->log); | |
503 } | |
504 } | |
505 | |
506 if (ngx_processes[i].respawn | |
507 && !ngx_processes[i].exiting | |
508 && !ngx_terminate | |
509 && !ngx_quit) | |
510 { | |
511 if (ngx_spawn_process(cycle, ngx_processes[i].proc, | |
512 ngx_processes[i].data, | |
513 ngx_processes[i].name, i) | |
514 == NGX_ERROR) | |
515 { | |
516 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, | |
517 "can not respawn %s", ngx_processes[i].name); | |
518 continue; | |
519 } | |
520 | |
521 live = 1; | |
522 | |
523 continue; | |
524 } | |
525 | |
526 if (ngx_processes[i].pid == ngx_new_binary) { | |
527 ngx_new_binary = 0; | |
528 if (ngx_noaccepting) { | |
529 ngx_restart = 1; | |
530 ngx_noaccepting = 0; | |
531 } | |
532 } | |
533 | |
534 if (i == ngx_last_process - 1) { | |
535 ngx_last_process--; | |
536 | |
537 } else { | |
538 ngx_processes[i].pid = -1; | |
539 } | |
540 | |
541 } else if (ngx_processes[i].exiting || !ngx_processes[i].detached) { | |
542 live = 1; | |
543 } | |
544 } | |
545 | |
546 return live; | |
547 } | |
548 | |
549 | |
550 static void ngx_master_exit(ngx_cycle_t *cycle, ngx_master_ctx_t *ctx) | |
551 { | |
552 ngx_delete_pidfile(cycle); | |
553 | |
554 ngx_log_error(NGX_LOG_INFO, cycle->log, 0, "exit"); | |
555 | |
556 ngx_destroy_pool(cycle->pool); | |
557 | |
558 exit(0); | |
559 } | |
560 | |
561 | |
562 static void ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data) | |
563 { | |
564 sigset_t set; | |
565 ngx_err_t err; | |
566 ngx_int_t n; | |
567 ngx_uint_t i; | |
568 struct timeval tv; | |
569 ngx_listening_t *ls; | |
570 ngx_core_conf_t *ccf; | |
571 ngx_connection_t *c; | |
572 | |
573 | |
574 ngx_gettimeofday(&tv); | |
575 | |
576 ngx_start_msec = (ngx_epoch_msec_t) tv.tv_sec * 1000 + tv.tv_usec / 1000; | |
577 ngx_old_elapsed_msec = 0; | |
578 ngx_elapsed_msec = 0; | |
579 | |
580 | |
581 ngx_process = NGX_PROCESS_WORKER; | |
582 | |
583 ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); | |
584 | |
585 if (ccf->group != (gid_t) NGX_CONF_UNSET) { | |
586 if (setgid(ccf->group) == -1) { | |
587 ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, | |
588 "setgid(%d) failed", ccf->group); | |
589 /* fatal */ | |
590 exit(2); | |
591 } | |
592 } | |
593 | |
594 if (ccf->user != (uid_t) NGX_CONF_UNSET) { | |
595 if (setuid(ccf->user) == -1) { | |
596 ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, | |
597 "setuid(%d) failed", ccf->user); | |
598 /* fatal */ | |
599 exit(2); | |
600 } | |
601 } | |
602 | |
603 #if (HAVE_PR_SET_DUMPABLE) | |
604 | |
605 /* allow coredump after setuid() in Linux 2.4.x */ | |
606 | |
607 if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) == -1) { | |
608 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, | |
609 "prctl(PR_SET_DUMPABLE) failed"); | |
610 } | |
611 | |
612 #endif | |
613 | |
614 sigemptyset(&set); | |
615 | |
616 if (sigprocmask(SIG_SETMASK, &set, NULL) == -1) { | |
617 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, | |
618 "sigprocmask() failed"); | |
619 } | |
620 | |
621 ngx_init_temp_number(); | |
622 | |
623 /* | |
624 * disable deleting previous events for the listening sockets because | |
625 * in the worker processes there are no events at all at this point | |
626 */ | |
627 ls = cycle->listening.elts; | |
628 for (i = 0; i < cycle->listening.nelts; i++) { | |
629 ls[i].remain = 0; | |
630 } | |
631 | |
632 for (i = 0; ngx_modules[i]; i++) { | |
633 if (ngx_modules[i]->init_process) { | |
634 if (ngx_modules[i]->init_process(cycle) == NGX_ERROR) { | |
635 /* fatal */ | |
636 exit(2); | |
637 } | |
638 } | |
639 } | |
640 | |
641 for (n = 0; n < ngx_last_process; n++) { | |
642 | |
643 if (ngx_processes[n].pid == -1) { | |
644 continue; | |
645 } | |
646 | |
647 if (n == ngx_process_slot) { | |
648 continue; | |
649 } | |
650 | |
651 if (ngx_processes[n].channel[1] == -1) { | |
652 continue; | |
653 } | |
654 | |
655 if (close(ngx_processes[n].channel[1]) == -1) { | |
656 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, | |
657 "close() failed"); | |
658 } | |
659 } | |
660 | |
661 if (close(ngx_processes[ngx_process_slot].channel[0]) == -1) { | |
662 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, | |
663 "close() failed"); | |
664 } | |
665 | |
666 #if 0 | |
667 ngx_last_process = 0; | |
668 #endif | |
669 | |
670 if (ngx_add_channel_event(cycle, ngx_channel, NGX_READ_EVENT, | |
671 ngx_channel_handler) == NGX_ERROR) | |
672 { | |
673 /* fatal */ | |
674 exit(2); | |
675 } | |
676 | |
677 ngx_setproctitle("worker process"); | |
678 | |
679 #if (NGX_THREADS) | |
680 | |
681 if (ngx_time_mutex_init(cycle->log) == NGX_ERROR) { | |
682 /* fatal */ | |
683 exit(2); | |
684 } | |
685 | |
686 if (ngx_threads_n) { | |
687 if (ngx_init_threads(ngx_threads_n, | |
688 ccf->thread_stack_size, cycle) == NGX_ERROR) | |
689 { | |
690 /* fatal */ | |
691 exit(2); | |
692 } | |
693 | |
694 err = ngx_thread_key_create(&ngx_core_tls_key); | |
695 if (err != 0) { | |
696 ngx_log_error(NGX_LOG_ALERT, cycle->log, err, | |
697 ngx_thread_key_create_n " failed"); | |
698 /* fatal */ | |
699 exit(2); | |
700 } | |
701 | |
702 for (n = 0; n < ngx_threads_n; n++) { | |
703 | |
704 if (!(ngx_threads[n].cv = ngx_cond_init(cycle->log))) { | |
705 /* fatal */ | |
706 exit(2); | |
707 } | |
708 | |
709 if (ngx_create_thread((ngx_tid_t *) &ngx_threads[n].tid, | |
710 ngx_worker_thread_cycle, | |
711 (void *) &ngx_threads[n], cycle->log) != 0) | |
712 { | |
713 /* fatal */ | |
714 exit(2); | |
715 } | |
716 } | |
717 } | |
718 | |
719 #endif | |
720 | |
721 for ( ;; ) { | |
722 if (ngx_exiting | |
723 && ngx_event_timer_rbtree == &ngx_event_timer_sentinel) | |
724 { | |
725 ngx_log_error(NGX_LOG_INFO, cycle->log, 0, "exiting"); | |
726 | |
727 | |
728 #if (NGX_THREADS) | |
729 ngx_terminate = 1; | |
730 | |
731 ngx_wakeup_worker_threads(cycle); | |
732 #endif | |
733 | |
734 /* | |
735 * we do not destroy cycle->pool here because a signal handler | |
736 * that uses cycle->log can be called at this point | |
737 */ | |
738 exit(0); | |
739 } | |
740 | |
741 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "worker cycle"); | |
742 | |
743 ngx_process_events(cycle); | |
744 | |
745 if (ngx_terminate) { | |
746 ngx_log_error(NGX_LOG_INFO, cycle->log, 0, "exiting"); | |
747 | |
748 #if (NGX_THREADS) | |
749 ngx_wakeup_worker_threads(cycle); | |
750 #endif | |
751 | |
752 /* | |
753 * we do not destroy cycle->pool here because a signal handler | |
754 * that uses cycle->log can be called at this point | |
755 */ | |
756 exit(0); | |
757 } | |
758 | |
759 if (ngx_quit) { | |
760 ngx_quit = 0; | |
761 ngx_log_error(NGX_LOG_INFO, cycle->log, 0, | |
762 "gracefully shutting down"); | |
763 ngx_setproctitle("worker process is shutting down"); | |
764 | |
765 if (!ngx_exiting) { | |
766 ngx_close_listening_sockets(cycle); | |
767 ngx_exiting = 1; | |
768 } | |
769 } | |
770 | |
771 if (ngx_reopen) { | |
772 ngx_reopen = 0; | |
773 ngx_log_error(NGX_LOG_INFO, cycle->log, 0, "reopen logs"); | |
774 ngx_reopen_files(cycle, -1); | |
775 } | |
776 } | |
777 } | |
778 | |
779 | |
780 static void ngx_channel_handler(ngx_event_t *ev) | |
781 { | |
782 ngx_int_t n; | |
783 ngx_channel_t ch; | |
784 ngx_connection_t *c; | |
785 | |
786 c = ev->data; | |
787 | |
788 ngx_log_debug0(NGX_LOG_DEBUG_CORE, ev->log, 0, "channel handler"); | |
789 | |
790 n = ngx_read_channel(c->fd, &ch, sizeof(ngx_channel_t), ev->log); | |
791 | |
792 ngx_log_debug1(NGX_LOG_DEBUG_CORE, ev->log, 0, "channel: %d", n); | |
793 | |
794 if (n <= 0) { | |
795 return; | |
796 } | |
797 | |
798 ngx_log_debug1(NGX_LOG_DEBUG_CORE, ev->log, 0, | |
799 "channel command: %d", ch.command); | |
800 | |
801 switch (ch.command) { | |
802 | |
803 case NGX_CMD_QUIT: | |
804 ngx_quit = 1; | |
805 break; | |
806 | |
807 case NGX_CMD_TERMINATE: | |
808 ngx_terminate = 1; | |
809 break; | |
810 | |
811 case NGX_CMD_REOPEN: | |
812 ngx_reopen = 1; | |
813 break; | |
814 | |
815 case NGX_CMD_OPEN_CHANNEL: | |
816 | |
817 ngx_log_debug3(NGX_LOG_DEBUG_CORE, ev->log, 0, | |
818 "get channel s:%d pid:" PID_T_FMT " fd:%d", | |
819 ch.slot, ch.pid, ch.fd); | |
820 | |
821 ngx_processes[ch.slot].pid = ch.pid; | |
822 ngx_processes[ch.slot].channel[0] = ch.fd; | |
823 break; | |
824 | |
825 case NGX_CMD_CLOSE_CHANNEL: | |
826 | |
827 ngx_log_debug4(NGX_LOG_DEBUG_CORE, ev->log, 0, | |
828 "close channel s:%d pid:" PID_T_FMT " our:" PID_T_FMT | |
829 " fd:%d", | |
830 ch.slot, ch.pid, ngx_processes[ch.slot].pid, | |
831 ngx_processes[ch.slot].channel[0]); | |
832 | |
833 if (close(ngx_processes[ch.slot].channel[0]) == -1) { | |
834 ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno, "close() failed"); | |
835 } | |
836 | |
837 ngx_processes[ch.slot].channel[0] = -1; | |
838 break; | |
839 } | |
840 } | |
841 | |
842 | |
843 #if (NGX_THREADS) | |
844 | |
845 static void ngx_wakeup_worker_threads(ngx_cycle_t *cycle) | |
846 { | |
847 ngx_int_t i; | |
848 ngx_uint_t live; | |
849 | |
850 for ( ;; ) { | |
851 | |
852 live = 0; | |
853 | |
854 for (i = 0; i < ngx_threads_n; i++) { | |
855 if (ngx_threads[i].state < NGX_THREAD_EXIT) { | |
856 ngx_cond_signal(ngx_threads[i].cv); | |
857 | |
858 if (ngx_threads[i].cv->tid == (ngx_tid_t) -1) { | |
859 ngx_threads[i].state = NGX_THREAD_DONE; | |
860 } else { | |
861 live = 1; | |
862 } | |
863 } | |
864 | |
865 if (ngx_threads[i].state == NGX_THREAD_EXIT) { | |
866 ngx_thread_join(ngx_threads[i].tid, NULL); | |
867 ngx_threads[i].state = NGX_THREAD_DONE; | |
868 } | |
869 } | |
870 | |
871 if (live == 0) { | |
872 ngx_log_debug0(NGX_LOG_DEBUG_CORE, cycle->log, 0, | |
873 "all worker threads are joined"); | |
874 | |
875 /* STUB */ | |
876 ngx_done_events(cycle); | |
877 ngx_mutex_destroy(ngx_event_timer_mutex); | |
878 ngx_mutex_destroy(ngx_posted_events_mutex); | |
879 | |
880 return; | |
881 } | |
882 | |
883 ngx_sched_yield(); | |
884 } | |
885 } | |
886 | |
887 | |
888 static void* ngx_worker_thread_cycle(void *data) | |
889 { | |
890 ngx_thread_t *thr = data; | |
891 | |
892 sigset_t set; | |
893 ngx_err_t err; | |
894 ngx_core_tls_t *tls; | |
895 ngx_cycle_t *cycle; | |
896 struct timeval tv; | |
897 | |
898 thr->cv->tid = ngx_thread_self(); | |
899 | |
900 cycle = (ngx_cycle_t *) ngx_cycle; | |
901 | |
902 sigemptyset(&set); | |
903 sigaddset(&set, ngx_signal_value(NGX_RECONFIGURE_SIGNAL)); | |
904 sigaddset(&set, ngx_signal_value(NGX_REOPEN_SIGNAL)); | |
905 sigaddset(&set, ngx_signal_value(NGX_CHANGEBIN_SIGNAL)); | |
906 | |
907 err = ngx_thread_sigmask(SIG_BLOCK, &set, NULL); | |
908 if (err) { | |
909 ngx_log_error(NGX_LOG_ALERT, cycle->log, err, | |
910 ngx_thread_sigmask_n " failed"); | |
911 return (void *) 1; | |
912 } | |
913 | |
914 ngx_log_debug1(NGX_LOG_DEBUG_CORE, cycle->log, 0, | |
915 "thread " TID_T_FMT " started", ngx_thread_self()); | |
916 | |
917 ngx_setthrtitle("worker thread"); | |
918 | |
919 if (!(tls = ngx_calloc(sizeof(ngx_core_tls_t), cycle->log))) { | |
920 return (void *) 1; | |
921 } | |
922 | |
923 err = ngx_thread_set_tls(ngx_core_tls_key, tls); | |
924 if (err != 0) { | |
925 ngx_log_error(NGX_LOG_ALERT, cycle->log, err, | |
926 ngx_thread_set_tls_n " failed"); | |
927 return (void *) 1; | |
928 } | |
929 | |
930 if (ngx_mutex_lock(ngx_posted_events_mutex) == NGX_ERROR) { | |
931 return (void *) 1; | |
932 } | |
933 | |
934 for ( ;; ) { | |
935 thr->state = NGX_THREAD_FREE; | |
936 | |
937 if (ngx_cond_wait(thr->cv, ngx_posted_events_mutex) == NGX_ERROR) { | |
938 return (void *) 1; | |
939 } | |
940 | |
941 if (ngx_terminate) { | |
942 thr->state = NGX_THREAD_EXIT; | |
943 | |
944 ngx_mutex_unlock(ngx_posted_events_mutex); | |
945 | |
946 ngx_log_debug1(NGX_LOG_DEBUG_CORE, cycle->log, 0, | |
947 "thread %d is done", ngx_thread_self()); | |
948 | |
949 return (void *) 0; | |
950 } | |
951 | |
952 thr->state = NGX_THREAD_BUSY; | |
953 | |
954 if (ngx_event_thread_process_posted(cycle) == NGX_ERROR) { | |
955 return (void *) 1; | |
956 } | |
957 | |
958 if (ngx_event_thread_process_posted(cycle) == NGX_ERROR) { | |
959 return (void *) 1; | |
960 } | |
961 | |
962 if (ngx_process_changes) { | |
963 if (ngx_process_changes(cycle, 1) == NGX_ERROR) { | |
964 return (void *) 1; | |
965 } | |
966 } | |
967 } | |
968 } | |
969 | |
970 #endif |