~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Nginx/os/unix/ngx_process.c

Version: ~ [ nginx-0.8.20 ] ~ [ nginx-0.7.62 ] ~ [ nginx-0.6.39 ] ~

  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 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.