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 typedef struct {
14 int signo;
15 char *signame;
16 char *name;
17 void (*handler)(int signo);
18 } ngx_signal_t;
19
20
21
22 static void ngx_execute_proc(ngx_cycle_t *cycle, void *data);
23 static void ngx_signal_handler(int signo);
24 static void ngx_process_get_status(void);
25
26
27 int ngx_argc;
28 char **ngx_argv;
29 char **ngx_os_argv;
30
31 ngx_int_t ngx_process_slot;
32 ngx_socket_t ngx_channel;
33 ngx_int_t ngx_last_process;
34 ngx_process_t ngx_processes[NGX_MAX_PROCESSES];
35
36
37 ngx_signal_t signals[] = {
38 { ngx_signal_value(NGX_RECONFIGURE_SIGNAL),
39 "SIG" ngx_value(NGX_RECONFIGURE_SIGNAL),
40 "reload",
41 ngx_signal_handler },
42
43 { ngx_signal_value(NGX_REOPEN_SIGNAL),
44 "SIG" ngx_value(NGX_REOPEN_SIGNAL),
45 "reopen",
46 ngx_signal_handler },
47
48 { ngx_signal_value(NGX_NOACCEPT_SIGNAL),
49 "SIG" ngx_value(NGX_NOACCEPT_SIGNAL),
50 "",
51 ngx_signal_handler },
52
53 { ngx_signal_value(NGX_TERMINATE_SIGNAL),
54 "SIG" ngx_value(NGX_TERMINATE_SIGNAL),
55 "stop",
56 ngx_signal_handler },
57
58 { ngx_signal_value(NGX_SHUTDOWN_SIGNAL),
59 "SIG" ngx_value(NGX_SHUTDOWN_SIGNAL),
60 "quit",
61 ngx_signal_handler },
62
63 { ngx_signal_value(NGX_CHANGEBIN_SIGNAL),
64 "SIG" ngx_value(NGX_CHANGEBIN_SIGNAL),
65 "",
66 ngx_signal_handler },
67
68 { SIGALRM, "SIGALRM", "", ngx_signal_handler },
69
70 { SIGINT, "SIGINT", "", ngx_signal_handler },
71
72 { SIGIO, "SIGIO", "", ngx_signal_handler },
73
74 { SIGCHLD, "SIGCHLD", "", ngx_signal_handler },
75
76 { SIGSYS, "SIGSYS, SIG_IGN", "", SIG_IGN },
77
78 { SIGPIPE, "SIGPIPE, SIG_IGN", "", SIG_IGN },
79
80 { 0, NULL, "", NULL }
81 };
82
83
84 ngx_pid_t
85 ngx_spawn_process(ngx_cycle_t *cycle, ngx_spawn_proc_pt proc, void *data,
86 char *name, ngx_int_t respawn)
87 {
88 u_long on;
89 ngx_pid_t pid;
90 ngx_int_t s;
91
92 if (respawn >= 0) {
93 s = respawn;
94
95 } else {
96 for (s = 0; s < ngx_last_process; s++) {
97 if (ngx_processes[s].pid == -1) {
98 break;
99 }
100 }
101
102 if (s == NGX_MAX_PROCESSES) {
103 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
104 "no more than %d processes can be spawned",
105 NGX_MAX_PROCESSES);
106 return NGX_INVALID_PID;
107 }
108 }
109
110
111 if (respawn != NGX_PROCESS_DETACHED) {
112
113 /* Solaris 9 still has no AF_LOCAL */
114
115 if (socketpair(AF_UNIX, SOCK_STREAM, 0, ngx_processes[s].channel) == -1)
116 {
117 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
118 "socketpair() failed while spawning \"%s\"", name);
119 return NGX_INVALID_PID;
120 }
121
122 ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0,
123 "channel %d:%d",
124 ngx_processes[s].channel[0],
125 ngx_processes[s].channel[1]);
126
127 if (ngx_nonblocking(ngx_processes[s].channel[0]) == -1) {
128 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
129 ngx_nonblocking_n " failed while spawning \"%s\"",
130 name);
131 ngx_close_channel(ngx_processes[s].channel, cycle->log);
132 return NGX_INVALID_PID;
133 }
134
135 if (ngx_nonblocking(ngx_processes[s].channel[1]) == -1) {
136 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
137 ngx_nonblocking_n " failed while spawning \"%s\"",
138 name);
139 ngx_close_channel(ngx_processes[s].channel, cycle->log);
140 return NGX_INVALID_PID;
141 }
142
143 on = 1;
144 if (ioctl(ngx_processes[s].channel[0], FIOASYNC, &on) == -1) {
145 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
146 "ioctl(FIOASYNC) failed while spawning \"%s\"", name);
147 ngx_close_channel(ngx_processes[s].channel, cycle->log);
148 return NGX_INVALID_PID;
149 }
150
151 if (fcntl(ngx_processes[s].channel[0], F_SETOWN, ngx_pid) == -1) {
152 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
153 "fcntl(F_SETOWN) failed while spawning \"%s\"", name);
154 ngx_close_channel(ngx_processes[s].channel, cycle->log);
155 return NGX_INVALID_PID;
156 }
157
158 if (fcntl(ngx_processes[s].channel[0], F_SETFD, FD_CLOEXEC) == -1) {
159 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
160 "fcntl(FD_CLOEXEC) failed while spawning \"%s\"",
161 name);
162 ngx_close_channel(ngx_processes[s].channel, cycle->log);
163 return NGX_INVALID_PID;
164 }
165
166 if (fcntl(ngx_processes[s].channel[1], F_SETFD, FD_CLOEXEC) == -1) {
167 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
168 "fcntl(FD_CLOEXEC) failed while spawning \"%s\"",
169 name);
170 ngx_close_channel(ngx_processes[s].channel, cycle->log);
171 return NGX_INVALID_PID;
172 }
173
174 ngx_channel = ngx_processes[s].channel[1];
175
176 } else {
177 ngx_processes[s].channel[0] = -1;
178 ngx_processes[s].channel[1] = -1;
179 }
180
181 ngx_process_slot = s;
182
183
184 pid = fork();
185
186 switch (pid) {
187
188 case -1:
189 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
190 "fork() failed while spawning \"%s\"", name);
191 ngx_close_channel(ngx_processes[s].channel, cycle->log);
192 return NGX_INVALID_PID;
193
194 case 0:
195 ngx_pid = ngx_getpid();
196 proc(cycle, data);
197 break;
198
199 default:
200 break;
201 }
202
203 ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "start %s %P", name, pid);
204
205 ngx_processes[s].pid = pid;
206 ngx_processes[s].exited = 0;
207
208 if (respawn >= 0) {
209 return pid;
210 }
211
212 ngx_processes[s].proc = proc;
213 ngx_processes[s].data = data;
214 ngx_processes[s].name = name;
215 ngx_processes[s].exiting = 0;
216
217 switch (respawn) {
218
219 case NGX_PROCESS_NORESPAWN:
220 ngx_processes[s].respawn = 0;
221 ngx_processes[s].just_spawn = 0;
222 ngx_processes[s].detached = 0;
223 break;
224
225 case NGX_PROCESS_JUST_SPAWN:
226 ngx_processes[s].respawn = 0;
227 ngx_processes[s].just_spawn = 1;
228 ngx_processes[s].detached = 0;
229 break;
230
231 case NGX_PROCESS_RESPAWN:
232 ngx_processes[s].respawn = 1;
233 ngx_processes[s].just_spawn = 0;
234 ngx_processes[s].detached = 0;
235 break;
236
237 case NGX_PROCESS_JUST_RESPAWN:
238 ngx_processes[s].respawn = 1;
239 ngx_processes[s].just_spawn = 1;
240 ngx_processes[s].detached = 0;
241 break;
242
243 case NGX_PROCESS_DETACHED:
244 ngx_processes[s].respawn = 0;
245 ngx_processes[s].just_spawn = 0;
246 ngx_processes[s].detached = 1;
247 break;
248 }
249
250 if (s == ngx_last_process) {
251 ngx_last_process++;
252 }
253
254 return pid;
255 }
256
257
258 ngx_pid_t
259 ngx_execute(ngx_cycle_t *cycle, ngx_exec_ctx_t *ctx)
260 {
261 return ngx_spawn_process(cycle, ngx_execute_proc, ctx, ctx->name,
262 NGX_PROCESS_DETACHED);
263 }
264
265
266 static void
267 ngx_execute_proc(ngx_cycle_t *cycle, void *data)
268 {
269 ngx_exec_ctx_t *ctx = data;
270
271 if (execve(ctx->path, ctx->argv, ctx->envp) == -1) {
272 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
273 "execve() failed while executing %s \"%s\"",
274 ctx->name, ctx->path);
275 }
276
277 exit(1);
278 }
279
280
281 ngx_int_t
282 ngx_init_signals(ngx_log_t *log)
283 {
284 ngx_signal_t *sig;
285 struct sigaction sa;
286
287 for (sig = signals; sig->signo != 0; sig++) {
288 ngx_memzero(&sa, sizeof(struct sigaction));
289 sa.sa_handler = sig->handler;
290 sigemptyset(&sa.sa_mask);
291 if (sigaction(sig->signo, &sa, NULL) == -1) {
292 ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
293 "sigaction(%s) failed", sig->signame);
294 return NGX_ERROR;
295 }
296 }
297
298 return NGX_OK;
299 }
300
301
302 void
303 ngx_signal_handler(int signo)
304 {
305 char *action;
306 ngx_int_t ignore;
307 ngx_err_t err;
308 ngx_signal_t *sig;
309
310 ignore = 0;
311
312 err = ngx_errno;
313
314 for (sig = signals; sig->signo != 0; sig++) {
315 if (sig->signo == signo) {
316 break;
317 }
318 }
319
320 ngx_time_update(0, 0);
321
322 action = "";
323
324 switch (ngx_process) {
325
326 case NGX_PROCESS_MASTER:
327 case NGX_PROCESS_SINGLE:
328 switch (signo) {
329
330 case ngx_signal_value(NGX_SHUTDOWN_SIGNAL):
331 ngx_quit = 1;
332 action = ", shutting down";
333 break;
334
335 case ngx_signal_value(NGX_TERMINATE_SIGNAL):
336 case SIGINT:
337 ngx_terminate = 1;
338 action = ", exiting";
339 break;
340
341 case ngx_signal_value(NGX_NOACCEPT_SIGNAL):
342 ngx_noaccept = 1;
343 action = ", stop accepting connections";
344 break;
345
346 case ngx_signal_value(NGX_RECONFIGURE_SIGNAL):
347 ngx_reconfigure = 1;
348 action = ", reconfiguring";
349 break;
350
351 case ngx_signal_value(NGX_REOPEN_SIGNAL):
352 ngx_reopen = 1;
353 action = ", reopening logs";
354 break;
355
356 case ngx_signal_value(NGX_CHANGEBIN_SIGNAL):
357 if (getppid() > 1 || ngx_new_binary > 0) {
358
359 /*
360 * Ignore the signal in the new binary if its parent is
361 * not the init process, i.e. the old binary's process
362 * is still running. Or ignore the signal in the old binary's
363 * process if the new binary's process is already running.
364 */
365
366 action = ", ignoring";
367 ignore = 1;
368 break;
369 }
370
371 ngx_change_binary = 1;
372 action = ", changing binary";
373 break;
374
375 case SIGALRM:
376 ngx_sigalrm = 1;
377 break;
378
379 case SIGIO:
380 ngx_sigio = 1;
381 break;
382
383 case SIGCHLD:
384 ngx_reap = 1;
385 break;
386 }
387
388 break;
389
390 case NGX_PROCESS_WORKER:
391 switch (signo) {
392
393 case ngx_signal_value(NGX_NOACCEPT_SIGNAL):
394 ngx_debug_quit = 1;
395 case ngx_signal_value(NGX_SHUTDOWN_SIGNAL):
396 ngx_quit = 1;
397 action = ", shutting down";
398 break;
399
400 case ngx_signal_value(NGX_TERMINATE_SIGNAL):
401 case SIGINT:
402 ngx_terminate = 1;
403 action = ", exiting";
404 break;
405
406 case ngx_signal_value(NGX_REOPEN_SIGNAL):
407 ngx_reopen = 1;
408 action = ", reopening logs";
409 break;
410
411 case ngx_signal_value(NGX_RECONFIGURE_SIGNAL):
412 case ngx_signal_value(NGX_CHANGEBIN_SIGNAL):
413 case SIGIO:
414 action = ", ignoring";
415 break;
416 }
417
418 break;
419 }
420
421 ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0,
422 "signal %d (%s) received%s", signo, sig->signame, action);
423
424 if (ignore) {
425 ngx_log_error(NGX_LOG_CRIT, ngx_cycle->log, 0,
426 "the changing binary signal is ignored: "
427 "you should shutdown or terminate "
428 "before either old or new binary's process");
429 }
430
431 if (signo == SIGCHLD) {
432 ngx_process_get_status();
433 }
434
435 ngx_set_errno(err);
436 }
437
438
439 static void
440 ngx_process_get_status(void)
441 {
442 int status;
443 char *process;
444 ngx_pid_t pid;
445 ngx_err_t err;
446 ngx_int_t i;
447 ngx_uint_t one;
448
449 one = 0;
450
451 for ( ;; ) {
452 pid = waitpid(-1, &status, WNOHANG);
453
454 if (pid == 0) {
455 return;
456 }
457
458 if (pid == -1) {
459 err = ngx_errno;
460
461 if (err == NGX_EINTR) {
462 continue;
463 }
464
465 if (err == NGX_ECHILD && one) {
466 return;
467 }
468
469 #if (NGX_SOLARIS || NGX_FREEBSD)
470
471 /*
472 * Solaris always calls the signal handler for each exited process
473 * despite waitpid() may be already called for this process.
474 *
475 * When several processes exit at the same time FreeBSD may
476 * erroneously call the signal handler for exited process
477 * despite waitpid() may be already called for this process.
478 */
479
480 if (err == NGX_ECHILD) {
481 ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, errno,
482 "waitpid() failed");
483 return;
484 }
485
486 #endif
487
488 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, errno,
489 "waitpid() failed");
490
491 return;
492 }
493
494
495 if (ngx_accept_mutex_ptr) {
496
497 /*
498 * unlock the accept mutex if the abnormally exited process
499 * held it
500 */
501
502 ngx_atomic_cmp_set(ngx_accept_mutex_ptr, pid, 0);
503 }
504
505
506 one = 1;
507 process = "unknown process";
508
509 for (i = 0; i < ngx_last_process; i++) {
510 if (ngx_processes[i].pid == pid) {
511 ngx_processes[i].status = status;
512 ngx_processes[i].exited = 1;
513 process = ngx_processes[i].name;
514 break;
515 }
516 }
517
518 if (WTERMSIG(status)) {
519 #ifdef WCOREDUMP
520 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
521 "%s %P exited on signal %d%s",
522 process, pid, WTERMSIG(status),
523 WCOREDUMP(status) ? " (core dumped)" : "");
524 #else
525 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
526 "%s %P exited on signal %d",
527 process, pid, WTERMSIG(status));
528 #endif
529
530 } else {
531 ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0,
532 "%s %P exited with code %d",
533 process, pid, WEXITSTATUS(status));
534 }
535
536 if (WEXITSTATUS(status) == 2 && ngx_processes[i].respawn) {
537 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
538 "%s %P exited with fatal code %d "
539 "and can not be respawn",
540 process, pid, WEXITSTATUS(status));
541 ngx_processes[i].respawn = 0;
542 }
543 }
544 }
545
546
547 void
548 ngx_debug_point(void)
549 {
550 ngx_core_conf_t *ccf;
551
552 ccf = (ngx_core_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx,
553 ngx_core_module);
554
555 switch (ccf->debug_points) {
556
557 case NGX_DEBUG_POINTS_STOP:
558 raise(SIGSTOP);
559 break;
560
561 case NGX_DEBUG_POINTS_ABORT:
562 ngx_abort();
563 }
564 }
565
566
567 ngx_int_t
568 ngx_os_signal_process(ngx_cycle_t *cycle, char *name, ngx_int_t pid)
569 {
570 ngx_signal_t *sig;
571
572 for (sig = signals; sig->signo != 0; sig++) {
573 if (ngx_strcmp(name, sig->name) == 0) {
574 if (kill(pid, sig->signo) != -1) {
575 return 0;
576 }
577
578 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
579 "kill(%P, %d) failed", pid, sig->signo);
580 }
581 }
582
583 return 1;
584 }
585
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.