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