Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.13.12 ]​[ nginx-1.12.2 ]​

0001 
0002 /*
0003  * Copyright (C) Igor Sysoev
0004  * Copyright (C) Nginx, Inc.
0005  */
0006 
0007 
0008 #include <ngx_config.h>
0009 #include <ngx_core.h>
0010 #include <ngx_event.h>
0011 #include <ngx_channel.h>
0012 
0013 
0014 typedef struct {
0015     int     signo;
0016     char   *signame;
0017     char   *name;
0018     void  (*handler)(int signo);
0019 } ngx_signal_t;
0020 
0021 
0022 
0023 static void ngx_execute_proc(ngx_cycle_t *cycle, void *data);
0024 static void ngx_signal_handler(int signo);
0025 static void ngx_process_get_status(void);
0026 static void ngx_unlock_mutexes(ngx_pid_t pid);
0027 
0028 
0029 int              ngx_argc;
0030 char           **ngx_argv;
0031 char           **ngx_os_argv;
0032 
0033 ngx_int_t        ngx_process_slot;
0034 ngx_socket_t     ngx_channel;
0035 ngx_int_t        ngx_last_process;
0036 ngx_process_t    ngx_processes[NGX_MAX_PROCESSES];
0037 
0038 
0039 ngx_signal_t  signals[] = {
0040     { ngx_signal_value(NGX_RECONFIGURE_SIGNAL),
0041       "SIG" ngx_value(NGX_RECONFIGURE_SIGNAL),
0042       "reload",
0043       ngx_signal_handler },
0044 
0045     { ngx_signal_value(NGX_REOPEN_SIGNAL),
0046       "SIG" ngx_value(NGX_REOPEN_SIGNAL),
0047       "reopen",
0048       ngx_signal_handler },
0049 
0050     { ngx_signal_value(NGX_NOACCEPT_SIGNAL),
0051       "SIG" ngx_value(NGX_NOACCEPT_SIGNAL),
0052       "",
0053       ngx_signal_handler },
0054 
0055     { ngx_signal_value(NGX_TERMINATE_SIGNAL),
0056       "SIG" ngx_value(NGX_TERMINATE_SIGNAL),
0057       "stop",
0058       ngx_signal_handler },
0059 
0060     { ngx_signal_value(NGX_SHUTDOWN_SIGNAL),
0061       "SIG" ngx_value(NGX_SHUTDOWN_SIGNAL),
0062       "quit",
0063       ngx_signal_handler },
0064 
0065     { ngx_signal_value(NGX_CHANGEBIN_SIGNAL),
0066       "SIG" ngx_value(NGX_CHANGEBIN_SIGNAL),
0067       "",
0068       ngx_signal_handler },
0069 
0070     { SIGALRM, "SIGALRM", "", ngx_signal_handler },
0071 
0072     { SIGINT, "SIGINT", "", ngx_signal_handler },
0073 
0074     { SIGIO, "SIGIO", "", ngx_signal_handler },
0075 
0076     { SIGCHLD, "SIGCHLD", "", ngx_signal_handler },
0077 
0078     { SIGSYS, "SIGSYS, SIG_IGN", "", SIG_IGN },
0079 
0080     { SIGPIPE, "SIGPIPE, SIG_IGN", "", SIG_IGN },
0081 
0082     { 0, NULL, "", NULL }
0083 };
0084 
0085 
0086 ngx_pid_t
0087 ngx_spawn_process(ngx_cycle_t *cycle, ngx_spawn_proc_pt proc, void *data,
0088     char *name, ngx_int_t respawn)
0089 {
0090     u_long     on;
0091     ngx_pid_t  pid;
0092     ngx_int_t  s;
0093 
0094     if (respawn >= 0) {
0095         s = respawn;
0096 
0097     } else {
0098         for (s = 0; s < ngx_last_process; s++) {
0099             if (ngx_processes[s].pid == -1) {
0100                 break;
0101             }
0102         }
0103 
0104         if (s == NGX_MAX_PROCESSES) {
0105             ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
0106                           "no more than %d processes can be spawned",
0107                           NGX_MAX_PROCESSES);
0108             return NGX_INVALID_PID;
0109         }
0110     }
0111 
0112 
0113     if (respawn != NGX_PROCESS_DETACHED) {
0114 
0115         /* Solaris 9 still has no AF_LOCAL */
0116 
0117         if (socketpair(AF_UNIX, SOCK_STREAM, 0, ngx_processes[s].channel) == -1)
0118         {
0119             ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
0120                           "socketpair() failed while spawning \"%s\"", name);
0121             return NGX_INVALID_PID;
0122         }
0123 
0124         ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0,
0125                        "channel %d:%d",
0126                        ngx_processes[s].channel[0],
0127                        ngx_processes[s].channel[1]);
0128 
0129         if (ngx_nonblocking(ngx_processes[s].channel[0]) == -1) {
0130             ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
0131                           ngx_nonblocking_n " failed while spawning \"%s\"",
0132                           name);
0133             ngx_close_channel(ngx_processes[s].channel, cycle->log);
0134             return NGX_INVALID_PID;
0135         }
0136 
0137         if (ngx_nonblocking(ngx_processes[s].channel[1]) == -1) {
0138             ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
0139                           ngx_nonblocking_n " failed while spawning \"%s\"",
0140                           name);
0141             ngx_close_channel(ngx_processes[s].channel, cycle->log);
0142             return NGX_INVALID_PID;
0143         }
0144 
0145         on = 1;
0146         if (ioctl(ngx_processes[s].channel[0], FIOASYNC, &on) == -1) {
0147             ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
0148                           "ioctl(FIOASYNC) failed while spawning \"%s\"", name);
0149             ngx_close_channel(ngx_processes[s].channel, cycle->log);
0150             return NGX_INVALID_PID;
0151         }
0152 
0153         if (fcntl(ngx_processes[s].channel[0], F_SETOWN, ngx_pid) == -1) {
0154             ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
0155                           "fcntl(F_SETOWN) failed while spawning \"%s\"", name);
0156             ngx_close_channel(ngx_processes[s].channel, cycle->log);
0157             return NGX_INVALID_PID;
0158         }
0159 
0160         if (fcntl(ngx_processes[s].channel[0], F_SETFD, FD_CLOEXEC) == -1) {
0161             ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
0162                           "fcntl(FD_CLOEXEC) failed while spawning \"%s\"",
0163                            name);
0164             ngx_close_channel(ngx_processes[s].channel, cycle->log);
0165             return NGX_INVALID_PID;
0166         }
0167 
0168         if (fcntl(ngx_processes[s].channel[1], F_SETFD, FD_CLOEXEC) == -1) {
0169             ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
0170                           "fcntl(FD_CLOEXEC) failed while spawning \"%s\"",
0171                            name);
0172             ngx_close_channel(ngx_processes[s].channel, cycle->log);
0173             return NGX_INVALID_PID;
0174         }
0175 
0176         ngx_channel = ngx_processes[s].channel[1];
0177 
0178     } else {
0179         ngx_processes[s].channel[0] = -1;
0180         ngx_processes[s].channel[1] = -1;
0181     }
0182 
0183     ngx_process_slot = s;
0184 
0185 
0186     pid = fork();
0187 
0188     switch (pid) {
0189 
0190     case -1:
0191         ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
0192                       "fork() failed while spawning \"%s\"", name);
0193         ngx_close_channel(ngx_processes[s].channel, cycle->log);
0194         return NGX_INVALID_PID;
0195 
0196     case 0:
0197         ngx_pid = ngx_getpid();
0198         proc(cycle, data);
0199         break;
0200 
0201     default:
0202         break;
0203     }
0204 
0205     ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "start %s %P", name, pid);
0206 
0207     ngx_processes[s].pid = pid;
0208     ngx_processes[s].exited = 0;
0209 
0210     if (respawn >= 0) {
0211         return pid;
0212     }
0213 
0214     ngx_processes[s].proc = proc;
0215     ngx_processes[s].data = data;
0216     ngx_processes[s].name = name;
0217     ngx_processes[s].exiting = 0;
0218 
0219     switch (respawn) {
0220 
0221     case NGX_PROCESS_NORESPAWN:
0222         ngx_processes[s].respawn = 0;
0223         ngx_processes[s].just_spawn = 0;
0224         ngx_processes[s].detached = 0;
0225         break;
0226 
0227     case NGX_PROCESS_JUST_SPAWN:
0228         ngx_processes[s].respawn = 0;
0229         ngx_processes[s].just_spawn = 1;
0230         ngx_processes[s].detached = 0;
0231         break;
0232 
0233     case NGX_PROCESS_RESPAWN:
0234         ngx_processes[s].respawn = 1;
0235         ngx_processes[s].just_spawn = 0;
0236         ngx_processes[s].detached = 0;
0237         break;
0238 
0239     case NGX_PROCESS_JUST_RESPAWN:
0240         ngx_processes[s].respawn = 1;
0241         ngx_processes[s].just_spawn = 1;
0242         ngx_processes[s].detached = 0;
0243         break;
0244 
0245     case NGX_PROCESS_DETACHED:
0246         ngx_processes[s].respawn = 0;
0247         ngx_processes[s].just_spawn = 0;
0248         ngx_processes[s].detached = 1;
0249         break;
0250     }
0251 
0252     if (s == ngx_last_process) {
0253         ngx_last_process++;
0254     }
0255 
0256     return pid;
0257 }
0258 
0259 
0260 ngx_pid_t
0261 ngx_execute(ngx_cycle_t *cycle, ngx_exec_ctx_t *ctx)
0262 {
0263     return ngx_spawn_process(cycle, ngx_execute_proc, ctx, ctx->name,
0264                              NGX_PROCESS_DETACHED);
0265 }
0266 
0267 
0268 static void
0269 ngx_execute_proc(ngx_cycle_t *cycle, void *data)
0270 {
0271     ngx_exec_ctx_t  *ctx = data;
0272 
0273     if (execve(ctx->path, ctx->argv, ctx->envp) == -1) {
0274         ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
0275                       "execve() failed while executing %s \"%s\"",
0276                       ctx->name, ctx->path);
0277     }
0278 
0279     exit(1);
0280 }
0281 
0282 
0283 ngx_int_t
0284 ngx_init_signals(ngx_log_t *log)
0285 {
0286     ngx_signal_t      *sig;
0287     struct sigaction   sa;
0288 
0289     for (sig = signals; sig->signo != 0; sig++) {
0290         ngx_memzero(&sa, sizeof(struct sigaction));
0291         sa.sa_handler = sig->handler;
0292         sigemptyset(&sa.sa_mask);
0293         if (sigaction(sig->signo, &sa, NULL) == -1) {
0294 #if (NGX_VALGRIND)
0295             ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
0296                           "sigaction(%s) failed, ignored", sig->signame);
0297 #else
0298             ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
0299                           "sigaction(%s) failed", sig->signame);
0300             return NGX_ERROR;
0301 #endif
0302         }
0303     }
0304 
0305     return NGX_OK;
0306 }
0307 
0308 
0309 static void
0310 ngx_signal_handler(int signo)
0311 {
0312     char            *action;
0313     ngx_int_t        ignore;
0314     ngx_err_t        err;
0315     ngx_signal_t    *sig;
0316 
0317     ignore = 0;
0318 
0319     err = ngx_errno;
0320 
0321     for (sig = signals; sig->signo != 0; sig++) {
0322         if (sig->signo == signo) {
0323             break;
0324         }
0325     }
0326 
0327     ngx_time_sigsafe_update();
0328 
0329     action = "";
0330 
0331     switch (ngx_process) {
0332 
0333     case NGX_PROCESS_MASTER:
0334     case NGX_PROCESS_SINGLE:
0335         switch (signo) {
0336 
0337         case ngx_signal_value(NGX_SHUTDOWN_SIGNAL):
0338             ngx_quit = 1;
0339             action = ", shutting down";
0340             break;
0341 
0342         case ngx_signal_value(NGX_TERMINATE_SIGNAL):
0343         case SIGINT:
0344             ngx_terminate = 1;
0345             action = ", exiting";
0346             break;
0347 
0348         case ngx_signal_value(NGX_NOACCEPT_SIGNAL):
0349             if (ngx_daemonized) {
0350                 ngx_noaccept = 1;
0351                 action = ", stop accepting connections";
0352             }
0353             break;
0354 
0355         case ngx_signal_value(NGX_RECONFIGURE_SIGNAL):
0356             ngx_reconfigure = 1;
0357             action = ", reconfiguring";
0358             break;
0359 
0360         case ngx_signal_value(NGX_REOPEN_SIGNAL):
0361             ngx_reopen = 1;
0362             action = ", reopening logs";
0363             break;
0364 
0365         case ngx_signal_value(NGX_CHANGEBIN_SIGNAL):
0366             if (getppid() > 1 || ngx_new_binary > 0) {
0367 
0368                 /*
0369                  * Ignore the signal in the new binary if its parent is
0370                  * not the init process, i.e. the old binary's process
0371                  * is still running.  Or ignore the signal in the old binary's
0372                  * process if the new binary's process is already running.
0373                  */
0374 
0375                 action = ", ignoring";
0376                 ignore = 1;
0377                 break;
0378             }
0379 
0380             ngx_change_binary = 1;
0381             action = ", changing binary";
0382             break;
0383 
0384         case SIGALRM:
0385             ngx_sigalrm = 1;
0386             break;
0387 
0388         case SIGIO:
0389             ngx_sigio = 1;
0390             break;
0391 
0392         case SIGCHLD:
0393             ngx_reap = 1;
0394             break;
0395         }
0396 
0397         break;
0398 
0399     case NGX_PROCESS_WORKER:
0400     case NGX_PROCESS_HELPER:
0401         switch (signo) {
0402 
0403         case ngx_signal_value(NGX_NOACCEPT_SIGNAL):
0404             if (!ngx_daemonized) {
0405                 break;
0406             }
0407             ngx_debug_quit = 1;
0408             /* fall through */
0409         case ngx_signal_value(NGX_SHUTDOWN_SIGNAL):
0410             ngx_quit = 1;
0411             action = ", shutting down";
0412             break;
0413 
0414         case ngx_signal_value(NGX_TERMINATE_SIGNAL):
0415         case SIGINT:
0416             ngx_terminate = 1;
0417             action = ", exiting";
0418             break;
0419 
0420         case ngx_signal_value(NGX_REOPEN_SIGNAL):
0421             ngx_reopen = 1;
0422             action = ", reopening logs";
0423             break;
0424 
0425         case ngx_signal_value(NGX_RECONFIGURE_SIGNAL):
0426         case ngx_signal_value(NGX_CHANGEBIN_SIGNAL):
0427         case SIGIO:
0428             action = ", ignoring";
0429             break;
0430         }
0431 
0432         break;
0433     }
0434 
0435     ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0,
0436                   "signal %d (%s) received%s", signo, sig->signame, action);
0437 
0438     if (ignore) {
0439         ngx_log_error(NGX_LOG_CRIT, ngx_cycle->log, 0,
0440                       "the changing binary signal is ignored: "
0441                       "you should shutdown or terminate "
0442                       "before either old or new binary's process");
0443     }
0444 
0445     if (signo == SIGCHLD) {
0446         ngx_process_get_status();
0447     }
0448 
0449     ngx_set_errno(err);
0450 }
0451 
0452 
0453 static void
0454 ngx_process_get_status(void)
0455 {
0456     int              status;
0457     char            *process;
0458     ngx_pid_t        pid;
0459     ngx_err_t        err;
0460     ngx_int_t        i;
0461     ngx_uint_t       one;
0462 
0463     one = 0;
0464 
0465     for ( ;; ) {
0466         pid = waitpid(-1, &status, WNOHANG);
0467 
0468         if (pid == 0) {
0469             return;
0470         }
0471 
0472         if (pid == -1) {
0473             err = ngx_errno;
0474 
0475             if (err == NGX_EINTR) {
0476                 continue;
0477             }
0478 
0479             if (err == NGX_ECHILD && one) {
0480                 return;
0481             }
0482 
0483             /*
0484              * Solaris always calls the signal handler for each exited process
0485              * despite waitpid() may be already called for this process.
0486              *
0487              * When several processes exit at the same time FreeBSD may
0488              * erroneously call the signal handler for exited process
0489              * despite waitpid() may be already called for this process.
0490              */
0491 
0492             if (err == NGX_ECHILD) {
0493                 ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, err,
0494                               "waitpid() failed");
0495                 return;
0496             }
0497 
0498             ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, err,
0499                           "waitpid() failed");
0500             return;
0501         }
0502 
0503 
0504         one = 1;
0505         process = "unknown process";
0506 
0507         for (i = 0; i < ngx_last_process; i++) {
0508             if (ngx_processes[i].pid == pid) {
0509                 ngx_processes[i].status = status;
0510                 ngx_processes[i].exited = 1;
0511                 process = ngx_processes[i].name;
0512                 break;
0513             }
0514         }
0515 
0516         if (WTERMSIG(status)) {
0517 #ifdef WCOREDUMP
0518             ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
0519                           "%s %P exited on signal %d%s",
0520                           process, pid, WTERMSIG(status),
0521                           WCOREDUMP(status) ? " (core dumped)" : "");
0522 #else
0523             ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
0524                           "%s %P exited on signal %d",
0525                           process, pid, WTERMSIG(status));
0526 #endif
0527 
0528         } else {
0529             ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0,
0530                           "%s %P exited with code %d",
0531                           process, pid, WEXITSTATUS(status));
0532         }
0533 
0534         if (WEXITSTATUS(status) == 2 && ngx_processes[i].respawn) {
0535             ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
0536                           "%s %P exited with fatal code %d "
0537                           "and cannot be respawned",
0538                           process, pid, WEXITSTATUS(status));
0539             ngx_processes[i].respawn = 0;
0540         }
0541 
0542         ngx_unlock_mutexes(pid);
0543     }
0544 }
0545 
0546 
0547 static void
0548 ngx_unlock_mutexes(ngx_pid_t pid)
0549 {
0550     ngx_uint_t        i;
0551     ngx_shm_zone_t   *shm_zone;
0552     ngx_list_part_t  *part;
0553     ngx_slab_pool_t  *sp;
0554 
0555     /*
0556      * unlock the accept mutex if the abnormally exited process
0557      * held it
0558      */
0559 
0560     if (ngx_accept_mutex_ptr) {
0561         (void) ngx_shmtx_force_unlock(&ngx_accept_mutex, pid);
0562     }
0563 
0564     /*
0565      * unlock shared memory mutexes if held by the abnormally exited
0566      * process
0567      */
0568 
0569     part = (ngx_list_part_t *) &ngx_cycle->shared_memory.part;
0570     shm_zone = part->elts;
0571 
0572     for (i = 0; /* void */ ; i++) {
0573 
0574         if (i >= part->nelts) {
0575             if (part->next == NULL) {
0576                 break;
0577             }
0578             part = part->next;
0579             shm_zone = part->elts;
0580             i = 0;
0581         }
0582 
0583         sp = (ngx_slab_pool_t *) shm_zone[i].shm.addr;
0584 
0585         if (ngx_shmtx_force_unlock(&sp->mutex, pid)) {
0586             ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
0587                           "shared memory zone \"%V\" was locked by %P",
0588                           &shm_zone[i].shm.name, pid);
0589         }
0590     }
0591 }
0592 
0593 
0594 void
0595 ngx_debug_point(void)
0596 {
0597     ngx_core_conf_t  *ccf;
0598 
0599     ccf = (ngx_core_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx,
0600                                            ngx_core_module);
0601 
0602     switch (ccf->debug_points) {
0603 
0604     case NGX_DEBUG_POINTS_STOP:
0605         raise(SIGSTOP);
0606         break;
0607 
0608     case NGX_DEBUG_POINTS_ABORT:
0609         ngx_abort();
0610     }
0611 }
0612 
0613 
0614 ngx_int_t
0615 ngx_os_signal_process(ngx_cycle_t *cycle, char *name, ngx_pid_t pid)
0616 {
0617     ngx_signal_t  *sig;
0618 
0619     for (sig = signals; sig->signo != 0; sig++) {
0620         if (ngx_strcmp(name, sig->name) == 0) {
0621             if (kill(pid, sig->signo) != -1) {
0622                 return 0;
0623             }
0624 
0625             ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
0626                           "kill(%P, %d) failed", pid, sig->signo);
0627         }
0628     }
0629 
0630     return 1;
0631 }