upstream nginx-0.7.31
[nginx.git] / nginx / src / os / unix / ngx_process.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 typedef struct {
14      int     signo;
15      char   *signame;
16      void  (*handler)(int signo);
17 } ngx_signal_t;
18
19
20
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);
24
25
26 int              ngx_argc;
27 char           **ngx_argv;
28 char           **ngx_os_argv;
29
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];
34
35
36 ngx_signal_t  signals[] = {
37     { ngx_signal_value(NGX_RECONFIGURE_SIGNAL),
38       "SIG" ngx_value(NGX_RECONFIGURE_SIGNAL),
39       ngx_signal_handler },
40
41     { ngx_signal_value(NGX_REOPEN_SIGNAL),
42       "SIG" ngx_value(NGX_REOPEN_SIGNAL),
43       ngx_signal_handler },
44
45     { ngx_signal_value(NGX_NOACCEPT_SIGNAL),
46       "SIG" ngx_value(NGX_NOACCEPT_SIGNAL),
47       ngx_signal_handler },
48
49     { ngx_signal_value(NGX_TERMINATE_SIGNAL),
50       "SIG" ngx_value(NGX_TERMINATE_SIGNAL),
51       ngx_signal_handler },
52
53     { ngx_signal_value(NGX_SHUTDOWN_SIGNAL),
54       "SIG" ngx_value(NGX_SHUTDOWN_SIGNAL),
55       ngx_signal_handler },
56
57     { ngx_signal_value(NGX_CHANGEBIN_SIGNAL),
58       "SIG" ngx_value(NGX_CHANGEBIN_SIGNAL),
59       ngx_signal_handler },
60
61     { SIGALRM, "SIGALRM", ngx_signal_handler },
62
63     { SIGINT, "SIGINT", ngx_signal_handler },
64
65     { SIGIO, "SIGIO", ngx_signal_handler },
66
67     { SIGCHLD, "SIGCHLD", ngx_signal_handler },
68
69     { SIGPIPE, "SIGPIPE, SIG_IGN", SIG_IGN },
70
71     { 0, NULL, NULL }
72 };
73
74
75 ngx_pid_t
76 ngx_spawn_process(ngx_cycle_t *cycle, ngx_spawn_proc_pt proc, void *data,
77     char *name, ngx_int_t respawn)
78 {
79     u_long     on;
80     ngx_pid_t  pid;
81     ngx_int_t  s;
82
83     if (respawn >= 0) {
84         s = respawn;
85
86     } else {
87         for (s = 0; s < ngx_last_process; s++) {
88             if (ngx_processes[s].pid == -1) {
89                 break;
90             }
91         }
92
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",
96                           NGX_MAX_PROCESSES);
97             return NGX_INVALID_PID;
98         }
99     }
100
101
102     if (respawn != NGX_PROCESS_DETACHED) {
103
104         /* Solaris 9 still has no AF_LOCAL */
105
106         if (socketpair(AF_UNIX, SOCK_STREAM, 0, ngx_processes[s].channel) == -1)
107         {
108             ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
109                           "socketpair() failed while spawning \"%s\"", name);
110             return NGX_INVALID_PID;
111         }
112
113         ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0,
114                        "channel %d:%d",
115                        ngx_processes[s].channel[0],
116                        ngx_processes[s].channel[1]);
117
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\"",
121                           name);
122             ngx_close_channel(ngx_processes[s].channel, cycle->log);
123             return NGX_INVALID_PID;
124         }
125
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\"",
129                           name);
130             ngx_close_channel(ngx_processes[s].channel, cycle->log);
131             return NGX_INVALID_PID;
132         }
133
134         on = 1;
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;
140         }
141
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;
147         }
148
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\"",
152                            name);
153             ngx_close_channel(ngx_processes[s].channel, cycle->log);
154             return NGX_INVALID_PID;
155         }
156
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\"",
160                            name);
161             ngx_close_channel(ngx_processes[s].channel, cycle->log);
162             return NGX_INVALID_PID;
163         }
164
165         ngx_channel = ngx_processes[s].channel[1];
166
167     } else {
168         ngx_processes[s].channel[0] = -1;
169         ngx_processes[s].channel[1] = -1;
170     }
171
172     ngx_process_slot = s;
173
174
175     pid = fork();
176
177     switch (pid) {
178
179     case -1:
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;
184
185     case 0:
186         ngx_pid = ngx_getpid();
187         proc(cycle, data);
188         break;
189
190     default:
191         break;
192     }
193
194     ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "start %s %P", name, pid);
195
196     ngx_processes[s].pid = pid;
197     ngx_processes[s].exited = 0;
198
199     if (respawn >= 0) {
200         return pid;
201     }
202
203     ngx_processes[s].proc = proc;
204     ngx_processes[s].data = data;
205     ngx_processes[s].name = name;
206     ngx_processes[s].exiting = 0;
207
208     switch (respawn) {
209
210     case NGX_PROCESS_RESPAWN:
211         ngx_processes[s].respawn = 1;
212         ngx_processes[s].just_respawn = 0;
213         ngx_processes[s].detached = 0;
214         break;
215
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;
220         break;
221
222     case NGX_PROCESS_DETACHED:
223         ngx_processes[s].respawn = 0;
224         ngx_processes[s].just_respawn = 0;
225         ngx_processes[s].detached = 1;
226         break;
227     }
228
229     if (s == ngx_last_process) {
230         ngx_last_process++;
231     }
232
233     return pid;
234 }
235
236
237 ngx_pid_t
238 ngx_execute(ngx_cycle_t *cycle, ngx_exec_ctx_t *ctx)
239 {
240     return ngx_spawn_process(cycle, ngx_execute_proc, ctx, ctx->name,
241                              NGX_PROCESS_DETACHED);
242 }
243
244
245 static void
246 ngx_execute_proc(ngx_cycle_t *cycle, void *data)
247 {
248     ngx_exec_ctx_t  *ctx = data;
249
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);
254     }
255
256     exit(1);
257 }
258
259
260 ngx_int_t
261 ngx_init_signals(ngx_log_t *log)
262 {
263     ngx_signal_t      *sig;
264     struct sigaction   sa;
265
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);
273             return NGX_ERROR;
274         }
275     }
276
277     return NGX_OK;
278 }
279
280
281 void
282 ngx_signal_handler(int signo)
283 {
284     char            *action;
285     ngx_int_t        ignore;
286     ngx_err_t        err;
287     ngx_signal_t    *sig;
288
289     ignore = 0;
290
291     err = ngx_errno;
292
293     for (sig = signals; sig->signo != 0; sig++) {
294         if (sig->signo == signo) {
295             break;
296         }
297     }
298
299     ngx_time_update(0, 0);
300
301     action = "";
302
303     switch (ngx_process) {
304
305     case NGX_PROCESS_MASTER:
306     case NGX_PROCESS_SINGLE:
307         switch (signo) {
308
309         case ngx_signal_value(NGX_SHUTDOWN_SIGNAL):
310             ngx_quit = 1;
311             action = ", shutting down";
312             break;
313
314         case ngx_signal_value(NGX_TERMINATE_SIGNAL):
315         case SIGINT:
316             ngx_terminate = 1;
317             action = ", exiting";
318             break;
319
320         case ngx_signal_value(NGX_NOACCEPT_SIGNAL):
321             ngx_noaccept = 1;
322             action = ", stop accepting connections";
323             break;
324
325         case ngx_signal_value(NGX_RECONFIGURE_SIGNAL):
326             ngx_reconfigure = 1;
327             action = ", reconfiguring";
328             break;
329
330         case ngx_signal_value(NGX_REOPEN_SIGNAL):
331             ngx_reopen = 1;
332             action = ", reopening logs";
333             break;
334
335         case ngx_signal_value(NGX_CHANGEBIN_SIGNAL):
336             if (getppid() > 1 || ngx_new_binary > 0) {
337
338                 /*
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.
343                  */
344
345                 action = ", ignoring";
346                 ignore = 1;
347                 break;
348             }
349
350             ngx_change_binary = 1;
351             action = ", changing binary";
352             break;
353
354         case SIGALRM:
355             break;
356
357         case SIGIO:
358             ngx_sigio = 1;
359             break;
360
361         case SIGCHLD:
362             ngx_reap = 1;
363             break;
364         }
365
366         break;
367
368     case NGX_PROCESS_WORKER:
369         switch (signo) {
370
371         case ngx_signal_value(NGX_NOACCEPT_SIGNAL):
372             ngx_debug_quit = 1;
373         case ngx_signal_value(NGX_SHUTDOWN_SIGNAL):
374             ngx_quit = 1;
375             action = ", shutting down";
376             break;
377
378         case ngx_signal_value(NGX_TERMINATE_SIGNAL):
379         case SIGINT:
380             ngx_terminate = 1;
381             action = ", exiting";
382             break;
383
384         case ngx_signal_value(NGX_REOPEN_SIGNAL):
385             ngx_reopen = 1;
386             action = ", reopening logs";
387             break;
388
389         case ngx_signal_value(NGX_RECONFIGURE_SIGNAL):
390         case ngx_signal_value(NGX_CHANGEBIN_SIGNAL):
391         case SIGIO:
392             action = ", ignoring";
393             break;
394         }
395
396         break;
397     }
398
399     ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0,
400                   "signal %d (%s) received%s", signo, sig->signame, action);
401
402     if (ignore) {
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");
407     }
408
409     if (signo == SIGCHLD) {
410         ngx_process_get_status();
411     }
412
413     ngx_set_errno(err);
414 }
415
416
417 static void
418 ngx_process_get_status(void)
419 {
420     int              status;
421     char            *process;
422     ngx_pid_t        pid;
423     ngx_err_t        err;
424     ngx_int_t        i;
425     ngx_uint_t       one;
426
427     one = 0;
428
429     for ( ;; ) {
430         pid = waitpid(-1, &status, WNOHANG);
431
432         if (pid == 0) {
433             return;
434         }
435
436         if (pid == -1) {
437             err = ngx_errno;
438
439             if (err == NGX_EINTR) {
440                 continue;
441             }
442
443             if (err == NGX_ECHILD && one) {
444                 return;
445             }
446
447 #if (NGX_SOLARIS || NGX_FREEBSD)
448
449             /*
450              * Solaris always calls the signal handler for each exited process
451              * despite waitpid() may be already called for this process.
452              *
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.
456              */
457
458             if (err == NGX_ECHILD) {
459                 ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, errno,
460                               "waitpid() failed");
461                 return;
462             }
463
464 #endif
465
466             ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, errno,
467                           "waitpid() failed");
468
469             return;
470         }
471
472
473         if (ngx_accept_mutex_ptr) {
474
475             /*
476              * unlock the accept mutex if the abnormally exited process
477              * held it
478              */
479
480             ngx_atomic_cmp_set(ngx_accept_mutex_ptr, pid, 0);
481         }
482
483
484         one = 1;
485         process = "unknown process";
486
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;
492                 break;
493             }
494         }
495
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)" : "");
501
502         } else {
503             ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0,
504                           "%s %P exited with code %d",
505                           process, pid, WEXITSTATUS(status));
506         }
507
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;
514         }
515     }
516 }
517
518
519 void
520 ngx_debug_point(void)
521 {
522     ngx_core_conf_t  *ccf;
523
524     ccf = (ngx_core_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx,
525                                            ngx_core_module);
526
527     switch (ccf->debug_points) {
528
529     case NGX_DEBUG_POINTS_STOP:
530         raise(SIGSTOP);
531         break;
532
533     case NGX_DEBUG_POINTS_ABORT:
534         ngx_abort();
535     }
536 }