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