3 * Copyright (C) Igor Sysoev
7 #include <ngx_config.h>
10 #include <ngx_channel.h>
16 void (*handler)(int signo);
21 static void ngx_execute_proc(ngx_cycle_t *cycle, void *data);
22 static void ngx_signal_handler(int signo);
23 static void ngx_process_get_status(void);
30 ngx_int_t ngx_process_slot;
31 ngx_socket_t ngx_channel;
32 ngx_int_t ngx_last_process;
33 ngx_process_t ngx_processes[NGX_MAX_PROCESSES];
36 ngx_signal_t signals[] = {
37 { ngx_signal_value(NGX_RECONFIGURE_SIGNAL),
38 "SIG" ngx_value(NGX_RECONFIGURE_SIGNAL),
41 { ngx_signal_value(NGX_REOPEN_SIGNAL),
42 "SIG" ngx_value(NGX_REOPEN_SIGNAL),
45 { ngx_signal_value(NGX_NOACCEPT_SIGNAL),
46 "SIG" ngx_value(NGX_NOACCEPT_SIGNAL),
49 { ngx_signal_value(NGX_TERMINATE_SIGNAL),
50 "SIG" ngx_value(NGX_TERMINATE_SIGNAL),
53 { ngx_signal_value(NGX_SHUTDOWN_SIGNAL),
54 "SIG" ngx_value(NGX_SHUTDOWN_SIGNAL),
57 { ngx_signal_value(NGX_CHANGEBIN_SIGNAL),
58 "SIG" ngx_value(NGX_CHANGEBIN_SIGNAL),
61 { SIGALRM, "SIGALRM", ngx_signal_handler },
63 { SIGINT, "SIGINT", ngx_signal_handler },
65 { SIGIO, "SIGIO", ngx_signal_handler },
67 { SIGCHLD, "SIGCHLD", ngx_signal_handler },
69 { SIGPIPE, "SIGPIPE, SIG_IGN", SIG_IGN },
76 ngx_spawn_process(ngx_cycle_t *cycle, ngx_spawn_proc_pt proc, void *data,
77 char *name, ngx_int_t respawn)
87 for (s = 0; s < ngx_last_process; s++) {
88 if (ngx_processes[s].pid == -1) {
93 if (s == NGX_MAX_PROCESSES) {
94 ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
95 "no more than %d processes can be spawned",
97 return NGX_INVALID_PID;
102 if (respawn != NGX_PROCESS_DETACHED) {
104 /* Solaris 9 still has no AF_LOCAL */
106 if (socketpair(AF_UNIX, SOCK_STREAM, 0, ngx_processes[s].channel) == -1)
108 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
109 "socketpair() failed while spawning \"%s\"", name);
110 return NGX_INVALID_PID;
113 ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0,
115 ngx_processes[s].channel[0],
116 ngx_processes[s].channel[1]);
118 if (ngx_nonblocking(ngx_processes[s].channel[0]) == -1) {
119 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
120 ngx_nonblocking_n " failed while spawning \"%s\"",
122 ngx_close_channel(ngx_processes[s].channel, cycle->log);
123 return NGX_INVALID_PID;
126 if (ngx_nonblocking(ngx_processes[s].channel[1]) == -1) {
127 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
128 ngx_nonblocking_n " failed while spawning \"%s\"",
130 ngx_close_channel(ngx_processes[s].channel, cycle->log);
131 return NGX_INVALID_PID;
135 if (ioctl(ngx_processes[s].channel[0], FIOASYNC, &on) == -1) {
136 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
137 "ioctl(FIOASYNC) failed while spawning \"%s\"", name);
138 ngx_close_channel(ngx_processes[s].channel, cycle->log);
139 return NGX_INVALID_PID;
142 if (fcntl(ngx_processes[s].channel[0], F_SETOWN, ngx_pid) == -1) {
143 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
144 "fcntl(F_SETOWN) failed while spawning \"%s\"", name);
145 ngx_close_channel(ngx_processes[s].channel, cycle->log);
146 return NGX_INVALID_PID;
149 if (fcntl(ngx_processes[s].channel[0], F_SETFD, FD_CLOEXEC) == -1) {
150 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
151 "fcntl(FD_CLOEXEC) failed while spawning \"%s\"",
153 ngx_close_channel(ngx_processes[s].channel, cycle->log);
154 return NGX_INVALID_PID;
157 if (fcntl(ngx_processes[s].channel[1], F_SETFD, FD_CLOEXEC) == -1) {
158 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
159 "fcntl(FD_CLOEXEC) failed while spawning \"%s\"",
161 ngx_close_channel(ngx_processes[s].channel, cycle->log);
162 return NGX_INVALID_PID;
165 ngx_channel = ngx_processes[s].channel[1];
168 ngx_processes[s].channel[0] = -1;
169 ngx_processes[s].channel[1] = -1;
172 ngx_process_slot = s;
180 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
181 "fork() failed while spawning \"%s\"", name);
182 ngx_close_channel(ngx_processes[s].channel, cycle->log);
183 return NGX_INVALID_PID;
186 ngx_pid = ngx_getpid();
194 ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "start %s %P", name, pid);
196 ngx_processes[s].pid = pid;
197 ngx_processes[s].exited = 0;
203 ngx_processes[s].proc = proc;
204 ngx_processes[s].data = data;
205 ngx_processes[s].name = name;
206 ngx_processes[s].exiting = 0;
210 case NGX_PROCESS_RESPAWN:
211 ngx_processes[s].respawn = 1;
212 ngx_processes[s].just_respawn = 0;
213 ngx_processes[s].detached = 0;
216 case NGX_PROCESS_JUST_RESPAWN:
217 ngx_processes[s].respawn = 1;
218 ngx_processes[s].just_respawn = 1;
219 ngx_processes[s].detached = 0;
222 case NGX_PROCESS_DETACHED:
223 ngx_processes[s].respawn = 0;
224 ngx_processes[s].just_respawn = 0;
225 ngx_processes[s].detached = 1;
229 if (s == ngx_last_process) {
238 ngx_execute(ngx_cycle_t *cycle, ngx_exec_ctx_t *ctx)
240 return ngx_spawn_process(cycle, ngx_execute_proc, ctx, ctx->name,
241 NGX_PROCESS_DETACHED);
246 ngx_execute_proc(ngx_cycle_t *cycle, void *data)
248 ngx_exec_ctx_t *ctx = data;
250 if (execve(ctx->path, ctx->argv, ctx->envp) == -1) {
251 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
252 "execve() failed while executing %s \"%s\"",
253 ctx->name, ctx->path);
261 ngx_init_signals(ngx_log_t *log)
266 for (sig = signals; sig->signo != 0; sig++) {
267 ngx_memzero(&sa, sizeof(struct sigaction));
268 sa.sa_handler = sig->handler;
269 sigemptyset(&sa.sa_mask);
270 if (sigaction(sig->signo, &sa, NULL) == -1) {
271 ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
272 "sigaction(%s) failed", sig->signame);
282 ngx_signal_handler(int signo)
293 for (sig = signals; sig->signo != 0; sig++) {
294 if (sig->signo == signo) {
299 ngx_time_update(0, 0);
303 switch (ngx_process) {
305 case NGX_PROCESS_MASTER:
306 case NGX_PROCESS_SINGLE:
309 case ngx_signal_value(NGX_SHUTDOWN_SIGNAL):
311 action = ", shutting down";
314 case ngx_signal_value(NGX_TERMINATE_SIGNAL):
317 action = ", exiting";
320 case ngx_signal_value(NGX_NOACCEPT_SIGNAL):
322 action = ", stop accepting connections";
325 case ngx_signal_value(NGX_RECONFIGURE_SIGNAL):
327 action = ", reconfiguring";
330 case ngx_signal_value(NGX_REOPEN_SIGNAL):
332 action = ", reopening logs";
335 case ngx_signal_value(NGX_CHANGEBIN_SIGNAL):
336 if (getppid() > 1 || ngx_new_binary > 0) {
339 * Ignore the signal in the new binary if its parent is
340 * not the init process, i.e. the old binary's process
341 * is still running. Or ignore the signal in the old binary's
342 * process if the new binary's process is already running.
345 action = ", ignoring";
350 ngx_change_binary = 1;
351 action = ", changing binary";
368 case NGX_PROCESS_WORKER:
371 case ngx_signal_value(NGX_NOACCEPT_SIGNAL):
373 case ngx_signal_value(NGX_SHUTDOWN_SIGNAL):
375 action = ", shutting down";
378 case ngx_signal_value(NGX_TERMINATE_SIGNAL):
381 action = ", exiting";
384 case ngx_signal_value(NGX_REOPEN_SIGNAL):
386 action = ", reopening logs";
389 case ngx_signal_value(NGX_RECONFIGURE_SIGNAL):
390 case ngx_signal_value(NGX_CHANGEBIN_SIGNAL):
392 action = ", ignoring";
399 ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0,
400 "signal %d (%s) received%s", signo, sig->signame, action);
403 ngx_log_error(NGX_LOG_CRIT, ngx_cycle->log, 0,
404 "the changing binary signal is ignored: "
405 "you should shutdown or terminate "
406 "before either old or new binary's process");
409 if (signo == SIGCHLD) {
410 ngx_process_get_status();
418 ngx_process_get_status(void)
430 pid = waitpid(-1, &status, WNOHANG);
439 if (err == NGX_EINTR) {
443 if (err == NGX_ECHILD && one) {
447 #if (NGX_SOLARIS || NGX_FREEBSD)
450 * Solaris always calls the signal handler for each exited process
451 * despite waitpid() may be already called for this process.
453 * When several processes exit at the same time FreeBSD may
454 * erroneously call the signal handler for exited process
455 * despite waitpid() may be already called for this process.
458 if (err == NGX_ECHILD) {
459 ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, errno,
466 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, errno,
473 if (ngx_accept_mutex_ptr) {
476 * unlock the accept mutex if the abnormally exited process
480 ngx_atomic_cmp_set(ngx_accept_mutex_ptr, pid, 0);
485 process = "unknown process";
487 for (i = 0; i < ngx_last_process; i++) {
488 if (ngx_processes[i].pid == pid) {
489 ngx_processes[i].status = status;
490 ngx_processes[i].exited = 1;
491 process = ngx_processes[i].name;
496 if (WTERMSIG(status)) {
497 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
498 "%s %P exited on signal %d%s",
499 process, pid, WTERMSIG(status),
500 WCOREDUMP(status) ? " (core dumped)" : "");
503 ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0,
504 "%s %P exited with code %d",
505 process, pid, WEXITSTATUS(status));
508 if (WEXITSTATUS(status) == 2 && ngx_processes[i].respawn) {
509 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
510 "%s %P exited with fatal code %d "
511 "and can not be respawn",
512 process, pid, WEXITSTATUS(status));
513 ngx_processes[i].respawn = 0;
520 ngx_debug_point(void)
522 ngx_core_conf_t *ccf;
524 ccf = (ngx_core_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx,
527 switch (ccf->debug_points) {
529 case NGX_DEBUG_POINTS_STOP:
533 case NGX_DEBUG_POINTS_ABORT: