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