Annotation of embedaddon/nginx/src/os/unix/ngx_process_cycle.c, revision 1.1.1.1
1.1 misho 1:
2: /*
3: * Copyright (C) Igor Sysoev
4: * Copyright (C) Nginx, Inc.
5: */
6:
7:
8: #include <ngx_config.h>
9: #include <ngx_core.h>
10: #include <ngx_event.h>
11: #include <ngx_channel.h>
12:
13:
14: static void ngx_start_worker_processes(ngx_cycle_t *cycle, ngx_int_t n,
15: ngx_int_t type);
16: static void ngx_start_cache_manager_processes(ngx_cycle_t *cycle,
17: ngx_uint_t respawn);
18: static void ngx_pass_open_channel(ngx_cycle_t *cycle, ngx_channel_t *ch);
19: static void ngx_signal_worker_processes(ngx_cycle_t *cycle, int signo);
20: static ngx_uint_t ngx_reap_children(ngx_cycle_t *cycle);
21: static void ngx_master_process_exit(ngx_cycle_t *cycle);
22: static void ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data);
23: static void ngx_worker_process_init(ngx_cycle_t *cycle, ngx_int_t worker);
24: static void ngx_worker_process_exit(ngx_cycle_t *cycle);
25: static void ngx_channel_handler(ngx_event_t *ev);
26: #if (NGX_THREADS)
27: static void ngx_wakeup_worker_threads(ngx_cycle_t *cycle);
28: static ngx_thread_value_t ngx_worker_thread_cycle(void *data);
29: #endif
30: static void ngx_cache_manager_process_cycle(ngx_cycle_t *cycle, void *data);
31: static void ngx_cache_manager_process_handler(ngx_event_t *ev);
32: static void ngx_cache_loader_process_handler(ngx_event_t *ev);
33:
34:
35: ngx_uint_t ngx_process;
36: ngx_pid_t ngx_pid;
37: ngx_uint_t ngx_threaded;
38:
39: sig_atomic_t ngx_reap;
40: sig_atomic_t ngx_sigio;
41: sig_atomic_t ngx_sigalrm;
42: sig_atomic_t ngx_terminate;
43: sig_atomic_t ngx_quit;
44: sig_atomic_t ngx_debug_quit;
45: ngx_uint_t ngx_exiting;
46: sig_atomic_t ngx_reconfigure;
47: sig_atomic_t ngx_reopen;
48:
49: sig_atomic_t ngx_change_binary;
50: ngx_pid_t ngx_new_binary;
51: ngx_uint_t ngx_inherited;
52: ngx_uint_t ngx_daemonized;
53:
54: sig_atomic_t ngx_noaccept;
55: ngx_uint_t ngx_noaccepting;
56: ngx_uint_t ngx_restart;
57:
58:
59: #if (NGX_THREADS)
60: volatile ngx_thread_t ngx_threads[NGX_MAX_THREADS];
61: ngx_int_t ngx_threads_n;
62: #endif
63:
64:
65: static u_char master_process[] = "master process";
66:
67:
68: static ngx_cache_manager_ctx_t ngx_cache_manager_ctx = {
69: ngx_cache_manager_process_handler, "cache manager process", 0
70: };
71:
72: static ngx_cache_manager_ctx_t ngx_cache_loader_ctx = {
73: ngx_cache_loader_process_handler, "cache loader process", 60000
74: };
75:
76:
77: static ngx_cycle_t ngx_exit_cycle;
78: static ngx_log_t ngx_exit_log;
79: static ngx_open_file_t ngx_exit_log_file;
80:
81:
82: void
83: ngx_master_process_cycle(ngx_cycle_t *cycle)
84: {
85: char *title;
86: u_char *p;
87: size_t size;
88: ngx_int_t i;
89: ngx_uint_t n, sigio;
90: sigset_t set;
91: struct itimerval itv;
92: ngx_uint_t live;
93: ngx_msec_t delay;
94: ngx_listening_t *ls;
95: ngx_core_conf_t *ccf;
96:
97: sigemptyset(&set);
98: sigaddset(&set, SIGCHLD);
99: sigaddset(&set, SIGALRM);
100: sigaddset(&set, SIGIO);
101: sigaddset(&set, SIGINT);
102: sigaddset(&set, ngx_signal_value(NGX_RECONFIGURE_SIGNAL));
103: sigaddset(&set, ngx_signal_value(NGX_REOPEN_SIGNAL));
104: sigaddset(&set, ngx_signal_value(NGX_NOACCEPT_SIGNAL));
105: sigaddset(&set, ngx_signal_value(NGX_TERMINATE_SIGNAL));
106: sigaddset(&set, ngx_signal_value(NGX_SHUTDOWN_SIGNAL));
107: sigaddset(&set, ngx_signal_value(NGX_CHANGEBIN_SIGNAL));
108:
109: if (sigprocmask(SIG_BLOCK, &set, NULL) == -1) {
110: ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
111: "sigprocmask() failed");
112: }
113:
114: sigemptyset(&set);
115:
116:
117: size = sizeof(master_process);
118:
119: for (i = 0; i < ngx_argc; i++) {
120: size += ngx_strlen(ngx_argv[i]) + 1;
121: }
122:
123: title = ngx_pnalloc(cycle->pool, size);
124:
125: p = ngx_cpymem(title, master_process, sizeof(master_process) - 1);
126: for (i = 0; i < ngx_argc; i++) {
127: *p++ = ' ';
128: p = ngx_cpystrn(p, (u_char *) ngx_argv[i], size);
129: }
130:
131: ngx_setproctitle(title);
132:
133:
134: ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
135:
136: ngx_start_worker_processes(cycle, ccf->worker_processes,
137: NGX_PROCESS_RESPAWN);
138: ngx_start_cache_manager_processes(cycle, 0);
139:
140: ngx_new_binary = 0;
141: delay = 0;
142: sigio = 0;
143: live = 1;
144:
145: for ( ;; ) {
146: if (delay) {
147: if (ngx_sigalrm) {
148: sigio = 0;
149: delay *= 2;
150: ngx_sigalrm = 0;
151: }
152:
153: ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
154: "termination cycle: %d", delay);
155:
156: itv.it_interval.tv_sec = 0;
157: itv.it_interval.tv_usec = 0;
158: itv.it_value.tv_sec = delay / 1000;
159: itv.it_value.tv_usec = (delay % 1000 ) * 1000;
160:
161: if (setitimer(ITIMER_REAL, &itv, NULL) == -1) {
162: ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
163: "setitimer() failed");
164: }
165: }
166:
167: ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "sigsuspend");
168:
169: sigsuspend(&set);
170:
171: ngx_time_update();
172:
173: ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
174: "wake up, sigio %i", sigio);
175:
176: if (ngx_reap) {
177: ngx_reap = 0;
178: ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "reap children");
179:
180: live = ngx_reap_children(cycle);
181: }
182:
183: if (!live && (ngx_terminate || ngx_quit)) {
184: ngx_master_process_exit(cycle);
185: }
186:
187: if (ngx_terminate) {
188: if (delay == 0) {
189: delay = 50;
190: }
191:
192: if (sigio) {
193: sigio--;
194: continue;
195: }
196:
197: sigio = ccf->worker_processes + 2 /* cache processes */;
198:
199: if (delay > 1000) {
200: ngx_signal_worker_processes(cycle, SIGKILL);
201: } else {
202: ngx_signal_worker_processes(cycle,
203: ngx_signal_value(NGX_TERMINATE_SIGNAL));
204: }
205:
206: continue;
207: }
208:
209: if (ngx_quit) {
210: ngx_signal_worker_processes(cycle,
211: ngx_signal_value(NGX_SHUTDOWN_SIGNAL));
212:
213: ls = cycle->listening.elts;
214: for (n = 0; n < cycle->listening.nelts; n++) {
215: if (ngx_close_socket(ls[n].fd) == -1) {
216: ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno,
217: ngx_close_socket_n " %V failed",
218: &ls[n].addr_text);
219: }
220: }
221: cycle->listening.nelts = 0;
222:
223: continue;
224: }
225:
226: if (ngx_reconfigure) {
227: ngx_reconfigure = 0;
228:
229: if (ngx_new_binary) {
230: ngx_start_worker_processes(cycle, ccf->worker_processes,
231: NGX_PROCESS_RESPAWN);
232: ngx_start_cache_manager_processes(cycle, 0);
233: ngx_noaccepting = 0;
234:
235: continue;
236: }
237:
238: ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reconfiguring");
239:
240: cycle = ngx_init_cycle(cycle);
241: if (cycle == NULL) {
242: cycle = (ngx_cycle_t *) ngx_cycle;
243: continue;
244: }
245:
246: ngx_cycle = cycle;
247: ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx,
248: ngx_core_module);
249: ngx_start_worker_processes(cycle, ccf->worker_processes,
250: NGX_PROCESS_JUST_RESPAWN);
251: ngx_start_cache_manager_processes(cycle, 1);
252:
253: /* allow new processes to start */
254: ngx_msleep(100);
255:
256: live = 1;
257: ngx_signal_worker_processes(cycle,
258: ngx_signal_value(NGX_SHUTDOWN_SIGNAL));
259: }
260:
261: if (ngx_restart) {
262: ngx_restart = 0;
263: ngx_start_worker_processes(cycle, ccf->worker_processes,
264: NGX_PROCESS_RESPAWN);
265: ngx_start_cache_manager_processes(cycle, 0);
266: live = 1;
267: }
268:
269: if (ngx_reopen) {
270: ngx_reopen = 0;
271: ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reopening logs");
272: ngx_reopen_files(cycle, ccf->user);
273: ngx_signal_worker_processes(cycle,
274: ngx_signal_value(NGX_REOPEN_SIGNAL));
275: }
276:
277: if (ngx_change_binary) {
278: ngx_change_binary = 0;
279: ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "changing binary");
280: ngx_new_binary = ngx_exec_new_binary(cycle, ngx_argv);
281: }
282:
283: if (ngx_noaccept) {
284: ngx_noaccept = 0;
285: ngx_noaccepting = 1;
286: ngx_signal_worker_processes(cycle,
287: ngx_signal_value(NGX_SHUTDOWN_SIGNAL));
288: }
289: }
290: }
291:
292:
293: void
294: ngx_single_process_cycle(ngx_cycle_t *cycle)
295: {
296: ngx_uint_t i;
297:
298: if (ngx_set_environment(cycle, NULL) == NULL) {
299: /* fatal */
300: exit(2);
301: }
302:
303: for (i = 0; ngx_modules[i]; i++) {
304: if (ngx_modules[i]->init_process) {
305: if (ngx_modules[i]->init_process(cycle) == NGX_ERROR) {
306: /* fatal */
307: exit(2);
308: }
309: }
310: }
311:
312: for ( ;; ) {
313: ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "worker cycle");
314:
315: ngx_process_events_and_timers(cycle);
316:
317: if (ngx_terminate || ngx_quit) {
318:
319: for (i = 0; ngx_modules[i]; i++) {
320: if (ngx_modules[i]->exit_process) {
321: ngx_modules[i]->exit_process(cycle);
322: }
323: }
324:
325: ngx_master_process_exit(cycle);
326: }
327:
328: if (ngx_reconfigure) {
329: ngx_reconfigure = 0;
330: ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reconfiguring");
331:
332: cycle = ngx_init_cycle(cycle);
333: if (cycle == NULL) {
334: cycle = (ngx_cycle_t *) ngx_cycle;
335: continue;
336: }
337:
338: ngx_cycle = cycle;
339: }
340:
341: if (ngx_reopen) {
342: ngx_reopen = 0;
343: ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reopening logs");
344: ngx_reopen_files(cycle, (ngx_uid_t) -1);
345: }
346: }
347: }
348:
349:
350: static void
351: ngx_start_worker_processes(ngx_cycle_t *cycle, ngx_int_t n, ngx_int_t type)
352: {
353: ngx_int_t i;
354: ngx_channel_t ch;
355:
356: ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "start worker processes");
357:
358: ch.command = NGX_CMD_OPEN_CHANNEL;
359:
360: for (i = 0; i < n; i++) {
361:
362: ngx_spawn_process(cycle, ngx_worker_process_cycle,
363: (void *) (intptr_t) i, "worker process", type);
364:
365: ch.pid = ngx_processes[ngx_process_slot].pid;
366: ch.slot = ngx_process_slot;
367: ch.fd = ngx_processes[ngx_process_slot].channel[0];
368:
369: ngx_pass_open_channel(cycle, &ch);
370: }
371: }
372:
373:
374: static void
375: ngx_start_cache_manager_processes(ngx_cycle_t *cycle, ngx_uint_t respawn)
376: {
377: ngx_uint_t i, manager, loader;
378: ngx_path_t **path;
379: ngx_channel_t ch;
380:
381: manager = 0;
382: loader = 0;
383:
384: path = ngx_cycle->paths.elts;
385: for (i = 0; i < ngx_cycle->paths.nelts; i++) {
386:
387: if (path[i]->manager) {
388: manager = 1;
389: }
390:
391: if (path[i]->loader) {
392: loader = 1;
393: }
394: }
395:
396: if (manager == 0) {
397: return;
398: }
399:
400: ngx_spawn_process(cycle, ngx_cache_manager_process_cycle,
401: &ngx_cache_manager_ctx, "cache manager process",
402: respawn ? NGX_PROCESS_JUST_RESPAWN : NGX_PROCESS_RESPAWN);
403:
404: ch.command = NGX_CMD_OPEN_CHANNEL;
405: ch.pid = ngx_processes[ngx_process_slot].pid;
406: ch.slot = ngx_process_slot;
407: ch.fd = ngx_processes[ngx_process_slot].channel[0];
408:
409: ngx_pass_open_channel(cycle, &ch);
410:
411: if (loader == 0) {
412: return;
413: }
414:
415: ngx_spawn_process(cycle, ngx_cache_manager_process_cycle,
416: &ngx_cache_loader_ctx, "cache loader process",
417: respawn ? NGX_PROCESS_JUST_SPAWN : NGX_PROCESS_NORESPAWN);
418:
419: ch.command = NGX_CMD_OPEN_CHANNEL;
420: ch.pid = ngx_processes[ngx_process_slot].pid;
421: ch.slot = ngx_process_slot;
422: ch.fd = ngx_processes[ngx_process_slot].channel[0];
423:
424: ngx_pass_open_channel(cycle, &ch);
425: }
426:
427:
428: static void
429: ngx_pass_open_channel(ngx_cycle_t *cycle, ngx_channel_t *ch)
430: {
431: ngx_int_t i;
432:
433: for (i = 0; i < ngx_last_process; i++) {
434:
435: if (i == ngx_process_slot
436: || ngx_processes[i].pid == -1
437: || ngx_processes[i].channel[0] == -1)
438: {
439: continue;
440: }
441:
442: ngx_log_debug6(NGX_LOG_DEBUG_CORE, cycle->log, 0,
443: "pass channel s:%d pid:%P fd:%d to s:%i pid:%P fd:%d",
444: ch->slot, ch->pid, ch->fd,
445: i, ngx_processes[i].pid,
446: ngx_processes[i].channel[0]);
447:
448: /* TODO: NGX_AGAIN */
449:
450: ngx_write_channel(ngx_processes[i].channel[0],
451: ch, sizeof(ngx_channel_t), cycle->log);
452: }
453: }
454:
455:
456: static void
457: ngx_signal_worker_processes(ngx_cycle_t *cycle, int signo)
458: {
459: ngx_int_t i;
460: ngx_err_t err;
461: ngx_channel_t ch;
462:
463: #if (NGX_BROKEN_SCM_RIGHTS)
464:
465: ch.command = 0;
466:
467: #else
468:
469: switch (signo) {
470:
471: case ngx_signal_value(NGX_SHUTDOWN_SIGNAL):
472: ch.command = NGX_CMD_QUIT;
473: break;
474:
475: case ngx_signal_value(NGX_TERMINATE_SIGNAL):
476: ch.command = NGX_CMD_TERMINATE;
477: break;
478:
479: case ngx_signal_value(NGX_REOPEN_SIGNAL):
480: ch.command = NGX_CMD_REOPEN;
481: break;
482:
483: default:
484: ch.command = 0;
485: }
486:
487: #endif
488:
489: ch.fd = -1;
490:
491:
492: for (i = 0; i < ngx_last_process; i++) {
493:
494: ngx_log_debug7(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
495: "child: %d %P e:%d t:%d d:%d r:%d j:%d",
496: i,
497: ngx_processes[i].pid,
498: ngx_processes[i].exiting,
499: ngx_processes[i].exited,
500: ngx_processes[i].detached,
501: ngx_processes[i].respawn,
502: ngx_processes[i].just_spawn);
503:
504: if (ngx_processes[i].detached || ngx_processes[i].pid == -1) {
505: continue;
506: }
507:
508: if (ngx_processes[i].just_spawn) {
509: ngx_processes[i].just_spawn = 0;
510: continue;
511: }
512:
513: if (ngx_processes[i].exiting
514: && signo == ngx_signal_value(NGX_SHUTDOWN_SIGNAL))
515: {
516: continue;
517: }
518:
519: if (ch.command) {
520: if (ngx_write_channel(ngx_processes[i].channel[0],
521: &ch, sizeof(ngx_channel_t), cycle->log)
522: == NGX_OK)
523: {
524: if (signo != ngx_signal_value(NGX_REOPEN_SIGNAL)) {
525: ngx_processes[i].exiting = 1;
526: }
527:
528: continue;
529: }
530: }
531:
532: ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0,
533: "kill (%P, %d)" , ngx_processes[i].pid, signo);
534:
535: if (kill(ngx_processes[i].pid, signo) == -1) {
536: err = ngx_errno;
537: ngx_log_error(NGX_LOG_ALERT, cycle->log, err,
538: "kill(%P, %d) failed", ngx_processes[i].pid, signo);
539:
540: if (err == NGX_ESRCH) {
541: ngx_processes[i].exited = 1;
542: ngx_processes[i].exiting = 0;
543: ngx_reap = 1;
544: }
545:
546: continue;
547: }
548:
549: if (signo != ngx_signal_value(NGX_REOPEN_SIGNAL)) {
550: ngx_processes[i].exiting = 1;
551: }
552: }
553: }
554:
555:
556: static ngx_uint_t
557: ngx_reap_children(ngx_cycle_t *cycle)
558: {
559: ngx_int_t i, n;
560: ngx_uint_t live;
561: ngx_channel_t ch;
562: ngx_core_conf_t *ccf;
563:
564: ch.command = NGX_CMD_CLOSE_CHANNEL;
565: ch.fd = -1;
566:
567: live = 0;
568: for (i = 0; i < ngx_last_process; i++) {
569:
570: ngx_log_debug7(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
571: "child: %d %P e:%d t:%d d:%d r:%d j:%d",
572: i,
573: ngx_processes[i].pid,
574: ngx_processes[i].exiting,
575: ngx_processes[i].exited,
576: ngx_processes[i].detached,
577: ngx_processes[i].respawn,
578: ngx_processes[i].just_spawn);
579:
580: if (ngx_processes[i].pid == -1) {
581: continue;
582: }
583:
584: if (ngx_processes[i].exited) {
585:
586: if (!ngx_processes[i].detached) {
587: ngx_close_channel(ngx_processes[i].channel, cycle->log);
588:
589: ngx_processes[i].channel[0] = -1;
590: ngx_processes[i].channel[1] = -1;
591:
592: ch.pid = ngx_processes[i].pid;
593: ch.slot = i;
594:
595: for (n = 0; n < ngx_last_process; n++) {
596: if (ngx_processes[n].exited
597: || ngx_processes[n].pid == -1
598: || ngx_processes[n].channel[0] == -1)
599: {
600: continue;
601: }
602:
603: ngx_log_debug3(NGX_LOG_DEBUG_CORE, cycle->log, 0,
604: "pass close channel s:%i pid:%P to:%P",
605: ch.slot, ch.pid, ngx_processes[n].pid);
606:
607: /* TODO: NGX_AGAIN */
608:
609: ngx_write_channel(ngx_processes[n].channel[0],
610: &ch, sizeof(ngx_channel_t), cycle->log);
611: }
612: }
613:
614: if (ngx_processes[i].respawn
615: && !ngx_processes[i].exiting
616: && !ngx_terminate
617: && !ngx_quit)
618: {
619: if (ngx_spawn_process(cycle, ngx_processes[i].proc,
620: ngx_processes[i].data,
621: ngx_processes[i].name, i)
622: == NGX_INVALID_PID)
623: {
624: ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
625: "could not respawn %s",
626: ngx_processes[i].name);
627: continue;
628: }
629:
630:
631: ch.command = NGX_CMD_OPEN_CHANNEL;
632: ch.pid = ngx_processes[ngx_process_slot].pid;
633: ch.slot = ngx_process_slot;
634: ch.fd = ngx_processes[ngx_process_slot].channel[0];
635:
636: ngx_pass_open_channel(cycle, &ch);
637:
638: live = 1;
639:
640: continue;
641: }
642:
643: if (ngx_processes[i].pid == ngx_new_binary) {
644:
645: ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx,
646: ngx_core_module);
647:
648: if (ngx_rename_file((char *) ccf->oldpid.data,
649: (char *) ccf->pid.data)
650: == NGX_FILE_ERROR)
651: {
652: ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
653: ngx_rename_file_n " %s back to %s failed "
654: "after the new binary process \"%s\" exited",
655: ccf->oldpid.data, ccf->pid.data, ngx_argv[0]);
656: }
657:
658: ngx_new_binary = 0;
659: if (ngx_noaccepting) {
660: ngx_restart = 1;
661: ngx_noaccepting = 0;
662: }
663: }
664:
665: if (i == ngx_last_process - 1) {
666: ngx_last_process--;
667:
668: } else {
669: ngx_processes[i].pid = -1;
670: }
671:
672: } else if (ngx_processes[i].exiting || !ngx_processes[i].detached) {
673: live = 1;
674: }
675: }
676:
677: return live;
678: }
679:
680:
681: static void
682: ngx_master_process_exit(ngx_cycle_t *cycle)
683: {
684: ngx_uint_t i;
685:
686: ngx_delete_pidfile(cycle);
687:
688: ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exit");
689:
690: for (i = 0; ngx_modules[i]; i++) {
691: if (ngx_modules[i]->exit_master) {
692: ngx_modules[i]->exit_master(cycle);
693: }
694: }
695:
696: ngx_close_listening_sockets(cycle);
697:
698: /*
699: * Copy ngx_cycle->log related data to the special static exit cycle,
700: * log, and log file structures enough to allow a signal handler to log.
701: * The handler may be called when standard ngx_cycle->log allocated from
702: * ngx_cycle->pool is already destroyed.
703: */
704:
705: ngx_exit_log_file.fd = ngx_cycle->log->file->fd;
706:
707: ngx_exit_log = *ngx_cycle->log;
708: ngx_exit_log.file = &ngx_exit_log_file;
709:
710: ngx_exit_cycle.log = &ngx_exit_log;
711: ngx_exit_cycle.files = ngx_cycle->files;
712: ngx_exit_cycle.files_n = ngx_cycle->files_n;
713: ngx_cycle = &ngx_exit_cycle;
714:
715: ngx_destroy_pool(cycle->pool);
716:
717: exit(0);
718: }
719:
720:
721: static void
722: ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data)
723: {
724: ngx_int_t worker = (intptr_t) data;
725:
726: ngx_uint_t i;
727: ngx_connection_t *c;
728:
729: ngx_process = NGX_PROCESS_WORKER;
730:
731: ngx_worker_process_init(cycle, worker);
732:
733: ngx_setproctitle("worker process");
734:
735: #if (NGX_THREADS)
736: {
737: ngx_int_t n;
738: ngx_err_t err;
739: ngx_core_conf_t *ccf;
740:
741: ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
742:
743: if (ngx_threads_n) {
744: if (ngx_init_threads(ngx_threads_n, ccf->thread_stack_size, cycle)
745: == NGX_ERROR)
746: {
747: /* fatal */
748: exit(2);
749: }
750:
751: err = ngx_thread_key_create(&ngx_core_tls_key);
752: if (err != 0) {
753: ngx_log_error(NGX_LOG_ALERT, cycle->log, err,
754: ngx_thread_key_create_n " failed");
755: /* fatal */
756: exit(2);
757: }
758:
759: for (n = 0; n < ngx_threads_n; n++) {
760:
761: ngx_threads[n].cv = ngx_cond_init(cycle->log);
762:
763: if (ngx_threads[n].cv == NULL) {
764: /* fatal */
765: exit(2);
766: }
767:
768: if (ngx_create_thread((ngx_tid_t *) &ngx_threads[n].tid,
769: ngx_worker_thread_cycle,
770: (void *) &ngx_threads[n], cycle->log)
771: != 0)
772: {
773: /* fatal */
774: exit(2);
775: }
776: }
777: }
778: }
779: #endif
780:
781: for ( ;; ) {
782:
783: if (ngx_exiting) {
784:
785: c = cycle->connections;
786:
787: for (i = 0; i < cycle->connection_n; i++) {
788:
789: /* THREAD: lock */
790:
791: if (c[i].fd != -1 && c[i].idle) {
792: c[i].close = 1;
793: c[i].read->handler(c[i].read);
794: }
795: }
796:
797: if (ngx_event_timer_rbtree.root == ngx_event_timer_rbtree.sentinel)
798: {
799: ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting");
800:
801: ngx_worker_process_exit(cycle);
802: }
803: }
804:
805: ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "worker cycle");
806:
807: ngx_process_events_and_timers(cycle);
808:
809: if (ngx_terminate) {
810: ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting");
811:
812: ngx_worker_process_exit(cycle);
813: }
814:
815: if (ngx_quit) {
816: ngx_quit = 0;
817: ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0,
818: "gracefully shutting down");
819: ngx_setproctitle("worker process is shutting down");
820:
821: if (!ngx_exiting) {
822: ngx_close_listening_sockets(cycle);
823: ngx_exiting = 1;
824: }
825: }
826:
827: if (ngx_reopen) {
828: ngx_reopen = 0;
829: ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reopening logs");
830: ngx_reopen_files(cycle, -1);
831: }
832: }
833: }
834:
835:
836: static void
837: ngx_worker_process_init(ngx_cycle_t *cycle, ngx_int_t worker)
838: {
839: sigset_t set;
840: uint64_t cpu_affinity;
841: ngx_int_t n;
842: ngx_uint_t i;
843: struct rlimit rlmt;
844: ngx_core_conf_t *ccf;
845: ngx_listening_t *ls;
846:
847: if (ngx_set_environment(cycle, NULL) == NULL) {
848: /* fatal */
849: exit(2);
850: }
851:
852: ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
853:
854: if (worker >= 0 && ccf->priority != 0) {
855: if (setpriority(PRIO_PROCESS, 0, ccf->priority) == -1) {
856: ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
857: "setpriority(%d) failed", ccf->priority);
858: }
859: }
860:
861: if (ccf->rlimit_nofile != NGX_CONF_UNSET) {
862: rlmt.rlim_cur = (rlim_t) ccf->rlimit_nofile;
863: rlmt.rlim_max = (rlim_t) ccf->rlimit_nofile;
864:
865: if (setrlimit(RLIMIT_NOFILE, &rlmt) == -1) {
866: ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
867: "setrlimit(RLIMIT_NOFILE, %i) failed",
868: ccf->rlimit_nofile);
869: }
870: }
871:
872: if (ccf->rlimit_core != NGX_CONF_UNSET) {
873: rlmt.rlim_cur = (rlim_t) ccf->rlimit_core;
874: rlmt.rlim_max = (rlim_t) ccf->rlimit_core;
875:
876: if (setrlimit(RLIMIT_CORE, &rlmt) == -1) {
877: ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
878: "setrlimit(RLIMIT_CORE, %O) failed",
879: ccf->rlimit_core);
880: }
881: }
882:
883: #ifdef RLIMIT_SIGPENDING
884: if (ccf->rlimit_sigpending != NGX_CONF_UNSET) {
885: rlmt.rlim_cur = (rlim_t) ccf->rlimit_sigpending;
886: rlmt.rlim_max = (rlim_t) ccf->rlimit_sigpending;
887:
888: if (setrlimit(RLIMIT_SIGPENDING, &rlmt) == -1) {
889: ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
890: "setrlimit(RLIMIT_SIGPENDING, %i) failed",
891: ccf->rlimit_sigpending);
892: }
893: }
894: #endif
895:
896: if (geteuid() == 0) {
897: if (setgid(ccf->group) == -1) {
898: ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
899: "setgid(%d) failed", ccf->group);
900: /* fatal */
901: exit(2);
902: }
903:
904: if (initgroups(ccf->username, ccf->group) == -1) {
905: ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
906: "initgroups(%s, %d) failed",
907: ccf->username, ccf->group);
908: }
909:
910: if (setuid(ccf->user) == -1) {
911: ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
912: "setuid(%d) failed", ccf->user);
913: /* fatal */
914: exit(2);
915: }
916: }
917:
918: if (worker >= 0) {
919: cpu_affinity = ngx_get_cpu_affinity(worker);
920:
921: if (cpu_affinity) {
922: ngx_setaffinity(cpu_affinity, cycle->log);
923: }
924: }
925:
926: #if (NGX_HAVE_PR_SET_DUMPABLE)
927:
928: /* allow coredump after setuid() in Linux 2.4.x */
929:
930: if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) == -1) {
931: ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
932: "prctl(PR_SET_DUMPABLE) failed");
933: }
934:
935: #endif
936:
937: if (ccf->working_directory.len) {
938: if (chdir((char *) ccf->working_directory.data) == -1) {
939: ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
940: "chdir(\"%s\") failed", ccf->working_directory.data);
941: /* fatal */
942: exit(2);
943: }
944: }
945:
946: sigemptyset(&set);
947:
948: if (sigprocmask(SIG_SETMASK, &set, NULL) == -1) {
949: ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
950: "sigprocmask() failed");
951: }
952:
953: /*
954: * disable deleting previous events for the listening sockets because
955: * in the worker processes there are no events at all at this point
956: */
957: ls = cycle->listening.elts;
958: for (i = 0; i < cycle->listening.nelts; i++) {
959: ls[i].previous = NULL;
960: }
961:
962: for (i = 0; ngx_modules[i]; i++) {
963: if (ngx_modules[i]->init_process) {
964: if (ngx_modules[i]->init_process(cycle) == NGX_ERROR) {
965: /* fatal */
966: exit(2);
967: }
968: }
969: }
970:
971: for (n = 0; n < ngx_last_process; n++) {
972:
973: if (ngx_processes[n].pid == -1) {
974: continue;
975: }
976:
977: if (n == ngx_process_slot) {
978: continue;
979: }
980:
981: if (ngx_processes[n].channel[1] == -1) {
982: continue;
983: }
984:
985: if (close(ngx_processes[n].channel[1]) == -1) {
986: ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
987: "close() channel failed");
988: }
989: }
990:
991: if (close(ngx_processes[ngx_process_slot].channel[0]) == -1) {
992: ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
993: "close() channel failed");
994: }
995:
996: #if 0
997: ngx_last_process = 0;
998: #endif
999:
1000: if (ngx_add_channel_event(cycle, ngx_channel, NGX_READ_EVENT,
1001: ngx_channel_handler)
1002: == NGX_ERROR)
1003: {
1004: /* fatal */
1005: exit(2);
1006: }
1007: }
1008:
1009:
1010: static void
1011: ngx_worker_process_exit(ngx_cycle_t *cycle)
1012: {
1013: ngx_uint_t i;
1014: ngx_connection_t *c;
1015:
1016: #if (NGX_THREADS)
1017: ngx_terminate = 1;
1018:
1019: ngx_wakeup_worker_threads(cycle);
1020: #endif
1021:
1022: for (i = 0; ngx_modules[i]; i++) {
1023: if (ngx_modules[i]->exit_process) {
1024: ngx_modules[i]->exit_process(cycle);
1025: }
1026: }
1027:
1028: if (ngx_exiting) {
1029: c = cycle->connections;
1030: for (i = 0; i < cycle->connection_n; i++) {
1031: if (c[i].fd != -1
1032: && c[i].read
1033: && !c[i].read->accept
1034: && !c[i].read->channel
1035: && !c[i].read->resolver)
1036: {
1037: ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
1038: "open socket #%d left in connection %ui",
1039: c[i].fd, i);
1040: ngx_debug_quit = 1;
1041: }
1042: }
1043:
1044: if (ngx_debug_quit) {
1045: ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "aborting");
1046: ngx_debug_point();
1047: }
1048: }
1049:
1050: /*
1051: * Copy ngx_cycle->log related data to the special static exit cycle,
1052: * log, and log file structures enough to allow a signal handler to log.
1053: * The handler may be called when standard ngx_cycle->log allocated from
1054: * ngx_cycle->pool is already destroyed.
1055: */
1056:
1057: ngx_exit_log_file.fd = ngx_cycle->log->file->fd;
1058:
1059: ngx_exit_log = *ngx_cycle->log;
1060: ngx_exit_log.file = &ngx_exit_log_file;
1061:
1062: ngx_exit_cycle.log = &ngx_exit_log;
1063: ngx_exit_cycle.files = ngx_cycle->files;
1064: ngx_exit_cycle.files_n = ngx_cycle->files_n;
1065: ngx_cycle = &ngx_exit_cycle;
1066:
1067: ngx_destroy_pool(cycle->pool);
1068:
1069: ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0, "exit");
1070:
1071: exit(0);
1072: }
1073:
1074:
1075: static void
1076: ngx_channel_handler(ngx_event_t *ev)
1077: {
1078: ngx_int_t n;
1079: ngx_channel_t ch;
1080: ngx_connection_t *c;
1081:
1082: if (ev->timedout) {
1083: ev->timedout = 0;
1084: return;
1085: }
1086:
1087: c = ev->data;
1088:
1089: ngx_log_debug0(NGX_LOG_DEBUG_CORE, ev->log, 0, "channel handler");
1090:
1091: for ( ;; ) {
1092:
1093: n = ngx_read_channel(c->fd, &ch, sizeof(ngx_channel_t), ev->log);
1094:
1095: ngx_log_debug1(NGX_LOG_DEBUG_CORE, ev->log, 0, "channel: %i", n);
1096:
1097: if (n == NGX_ERROR) {
1098:
1099: if (ngx_event_flags & NGX_USE_EPOLL_EVENT) {
1100: ngx_del_conn(c, 0);
1101: }
1102:
1103: ngx_close_connection(c);
1104: return;
1105: }
1106:
1107: if (ngx_event_flags & NGX_USE_EVENTPORT_EVENT) {
1108: if (ngx_add_event(ev, NGX_READ_EVENT, 0) == NGX_ERROR) {
1109: return;
1110: }
1111: }
1112:
1113: if (n == NGX_AGAIN) {
1114: return;
1115: }
1116:
1117: ngx_log_debug1(NGX_LOG_DEBUG_CORE, ev->log, 0,
1118: "channel command: %d", ch.command);
1119:
1120: switch (ch.command) {
1121:
1122: case NGX_CMD_QUIT:
1123: ngx_quit = 1;
1124: break;
1125:
1126: case NGX_CMD_TERMINATE:
1127: ngx_terminate = 1;
1128: break;
1129:
1130: case NGX_CMD_REOPEN:
1131: ngx_reopen = 1;
1132: break;
1133:
1134: case NGX_CMD_OPEN_CHANNEL:
1135:
1136: ngx_log_debug3(NGX_LOG_DEBUG_CORE, ev->log, 0,
1137: "get channel s:%i pid:%P fd:%d",
1138: ch.slot, ch.pid, ch.fd);
1139:
1140: ngx_processes[ch.slot].pid = ch.pid;
1141: ngx_processes[ch.slot].channel[0] = ch.fd;
1142: break;
1143:
1144: case NGX_CMD_CLOSE_CHANNEL:
1145:
1146: ngx_log_debug4(NGX_LOG_DEBUG_CORE, ev->log, 0,
1147: "close channel s:%i pid:%P our:%P fd:%d",
1148: ch.slot, ch.pid, ngx_processes[ch.slot].pid,
1149: ngx_processes[ch.slot].channel[0]);
1150:
1151: if (close(ngx_processes[ch.slot].channel[0]) == -1) {
1152: ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
1153: "close() channel failed");
1154: }
1155:
1156: ngx_processes[ch.slot].channel[0] = -1;
1157: break;
1158: }
1159: }
1160: }
1161:
1162:
1163: #if (NGX_THREADS)
1164:
1165: static void
1166: ngx_wakeup_worker_threads(ngx_cycle_t *cycle)
1167: {
1168: ngx_int_t i;
1169: ngx_uint_t live;
1170:
1171: for ( ;; ) {
1172:
1173: live = 0;
1174:
1175: for (i = 0; i < ngx_threads_n; i++) {
1176: if (ngx_threads[i].state < NGX_THREAD_EXIT) {
1177: if (ngx_cond_signal(ngx_threads[i].cv) == NGX_ERROR) {
1178: ngx_threads[i].state = NGX_THREAD_DONE;
1179:
1180: } else {
1181: live = 1;
1182: }
1183: }
1184:
1185: if (ngx_threads[i].state == NGX_THREAD_EXIT) {
1186: ngx_thread_join(ngx_threads[i].tid, NULL);
1187: ngx_threads[i].state = NGX_THREAD_DONE;
1188: }
1189: }
1190:
1191: if (live == 0) {
1192: ngx_log_debug0(NGX_LOG_DEBUG_CORE, cycle->log, 0,
1193: "all worker threads are joined");
1194:
1195: /* STUB */
1196: ngx_done_events(cycle);
1197: ngx_mutex_destroy(ngx_event_timer_mutex);
1198: ngx_mutex_destroy(ngx_posted_events_mutex);
1199:
1200: return;
1201: }
1202:
1203: ngx_sched_yield();
1204: }
1205: }
1206:
1207:
1208: static ngx_thread_value_t
1209: ngx_worker_thread_cycle(void *data)
1210: {
1211: ngx_thread_t *thr = data;
1212:
1213: sigset_t set;
1214: ngx_err_t err;
1215: ngx_core_tls_t *tls;
1216: ngx_cycle_t *cycle;
1217:
1218: cycle = (ngx_cycle_t *) ngx_cycle;
1219:
1220: sigemptyset(&set);
1221: sigaddset(&set, ngx_signal_value(NGX_RECONFIGURE_SIGNAL));
1222: sigaddset(&set, ngx_signal_value(NGX_REOPEN_SIGNAL));
1223: sigaddset(&set, ngx_signal_value(NGX_CHANGEBIN_SIGNAL));
1224:
1225: err = ngx_thread_sigmask(SIG_BLOCK, &set, NULL);
1226: if (err) {
1227: ngx_log_error(NGX_LOG_ALERT, cycle->log, err,
1228: ngx_thread_sigmask_n " failed");
1229: return (ngx_thread_value_t) 1;
1230: }
1231:
1232: ngx_log_debug1(NGX_LOG_DEBUG_CORE, cycle->log, 0,
1233: "thread " NGX_TID_T_FMT " started", ngx_thread_self());
1234:
1235: ngx_setthrtitle("worker thread");
1236:
1237: tls = ngx_calloc(sizeof(ngx_core_tls_t), cycle->log);
1238: if (tls == NULL) {
1239: return (ngx_thread_value_t) 1;
1240: }
1241:
1242: err = ngx_thread_set_tls(ngx_core_tls_key, tls);
1243: if (err != 0) {
1244: ngx_log_error(NGX_LOG_ALERT, cycle->log, err,
1245: ngx_thread_set_tls_n " failed");
1246: return (ngx_thread_value_t) 1;
1247: }
1248:
1249: ngx_mutex_lock(ngx_posted_events_mutex);
1250:
1251: for ( ;; ) {
1252: thr->state = NGX_THREAD_FREE;
1253:
1254: if (ngx_cond_wait(thr->cv, ngx_posted_events_mutex) == NGX_ERROR) {
1255: return (ngx_thread_value_t) 1;
1256: }
1257:
1258: if (ngx_terminate) {
1259: thr->state = NGX_THREAD_EXIT;
1260:
1261: ngx_mutex_unlock(ngx_posted_events_mutex);
1262:
1263: ngx_log_debug1(NGX_LOG_DEBUG_CORE, cycle->log, 0,
1264: "thread " NGX_TID_T_FMT " is done",
1265: ngx_thread_self());
1266:
1267: return (ngx_thread_value_t) 0;
1268: }
1269:
1270: thr->state = NGX_THREAD_BUSY;
1271:
1272: if (ngx_event_thread_process_posted(cycle) == NGX_ERROR) {
1273: return (ngx_thread_value_t) 1;
1274: }
1275:
1276: if (ngx_event_thread_process_posted(cycle) == NGX_ERROR) {
1277: return (ngx_thread_value_t) 1;
1278: }
1279:
1280: if (ngx_process_changes) {
1281: if (ngx_process_changes(cycle, 1) == NGX_ERROR) {
1282: return (ngx_thread_value_t) 1;
1283: }
1284: }
1285: }
1286: }
1287:
1288: #endif
1289:
1290:
1291: static void
1292: ngx_cache_manager_process_cycle(ngx_cycle_t *cycle, void *data)
1293: {
1294: ngx_cache_manager_ctx_t *ctx = data;
1295:
1296: void *ident[4];
1297: ngx_event_t ev;
1298:
1299: /*
1300: * Set correct process type since closing listening Unix domain socket
1301: * in a master process also removes the Unix domain socket file.
1302: */
1303: ngx_process = NGX_PROCESS_HELPER;
1304:
1305: ngx_close_listening_sockets(cycle);
1306:
1307: /* Set a moderate number of connections for a helper process. */
1308: cycle->connection_n = 512;
1309:
1310: ngx_worker_process_init(cycle, -1);
1311:
1312: ngx_memzero(&ev, sizeof(ngx_event_t));
1313: ev.handler = ctx->handler;
1314: ev.data = ident;
1315: ev.log = cycle->log;
1316: ident[3] = (void *) -1;
1317:
1318: ngx_use_accept_mutex = 0;
1319:
1320: ngx_setproctitle(ctx->name);
1321:
1322: ngx_add_timer(&ev, ctx->delay);
1323:
1324: for ( ;; ) {
1325:
1326: if (ngx_terminate || ngx_quit) {
1327: ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting");
1328: exit(0);
1329: }
1330:
1331: if (ngx_reopen) {
1332: ngx_reopen = 0;
1333: ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reopening logs");
1334: ngx_reopen_files(cycle, -1);
1335: }
1336:
1337: ngx_process_events_and_timers(cycle);
1338: }
1339: }
1340:
1341:
1342: static void
1343: ngx_cache_manager_process_handler(ngx_event_t *ev)
1344: {
1345: time_t next, n;
1346: ngx_uint_t i;
1347: ngx_path_t **path;
1348:
1349: next = 60 * 60;
1350:
1351: path = ngx_cycle->paths.elts;
1352: for (i = 0; i < ngx_cycle->paths.nelts; i++) {
1353:
1354: if (path[i]->manager) {
1355: n = path[i]->manager(path[i]->data);
1356:
1357: next = (n <= next) ? n : next;
1358:
1359: ngx_time_update();
1360: }
1361: }
1362:
1363: if (next == 0) {
1364: next = 1;
1365: }
1366:
1367: ngx_add_timer(ev, next * 1000);
1368: }
1369:
1370:
1371: static void
1372: ngx_cache_loader_process_handler(ngx_event_t *ev)
1373: {
1374: ngx_uint_t i;
1375: ngx_path_t **path;
1376: ngx_cycle_t *cycle;
1377:
1378: cycle = (ngx_cycle_t *) ngx_cycle;
1379:
1380: path = cycle->paths.elts;
1381: for (i = 0; i < cycle->paths.nelts; i++) {
1382:
1383: if (ngx_terminate || ngx_quit) {
1384: break;
1385: }
1386:
1387: if (path[i]->loader) {
1388: path[i]->loader(path[i]->data);
1389: ngx_time_update();
1390: }
1391: }
1392:
1393: exit(0);
1394: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>