src/os/unix/ngx_process.c - nginx source code

Global variables defined

Data types defined

Functions defined

Source code


  1. /*
  2. * Copyright (C) Igor Sysoev
  3. * Copyright (C) Nginx, Inc.
  4. */


  5. #include <ngx_config.h>
  6. #include <ngx_core.h>
  7. #include <ngx_event.h>
  8. #include <ngx_channel.h>


  9. typedef struct {
  10.     int     signo;
  11.     char   *signame;
  12.     char   *name;
  13.     void  (*handler)(int signo, siginfo_t *siginfo, void *ucontext);
  14. } ngx_signal_t;



  15. static void ngx_execute_proc(ngx_cycle_t *cycle, void *data);
  16. static void ngx_signal_handler(int signo, siginfo_t *siginfo, void *ucontext);
  17. static void ngx_process_get_status(void);
  18. static void ngx_unlock_mutexes(ngx_pid_t pid);


  19. int              ngx_argc;
  20. char           **ngx_argv;
  21. char           **ngx_os_argv;

  22. ngx_int_t        ngx_process_slot;
  23. ngx_socket_t     ngx_channel;
  24. ngx_int_t        ngx_last_process;
  25. ngx_process_t    ngx_processes[NGX_MAX_PROCESSES];


  26. ngx_signal_t  signals[] = {
  27.     { ngx_signal_value(NGX_RECONFIGURE_SIGNAL),
  28.       "SIG" ngx_value(NGX_RECONFIGURE_SIGNAL),
  29.       "reload",
  30.       ngx_signal_handler },

  31.     { ngx_signal_value(NGX_REOPEN_SIGNAL),
  32.       "SIG" ngx_value(NGX_REOPEN_SIGNAL),
  33.       "reopen",
  34.       ngx_signal_handler },

  35.     { ngx_signal_value(NGX_NOACCEPT_SIGNAL),
  36.       "SIG" ngx_value(NGX_NOACCEPT_SIGNAL),
  37.       "",
  38.       ngx_signal_handler },

  39.     { ngx_signal_value(NGX_TERMINATE_SIGNAL),
  40.       "SIG" ngx_value(NGX_TERMINATE_SIGNAL),
  41.       "stop",
  42.       ngx_signal_handler },

  43.     { ngx_signal_value(NGX_SHUTDOWN_SIGNAL),
  44.       "SIG" ngx_value(NGX_SHUTDOWN_SIGNAL),
  45.       "quit",
  46.       ngx_signal_handler },

  47.     { ngx_signal_value(NGX_CHANGEBIN_SIGNAL),
  48.       "SIG" ngx_value(NGX_CHANGEBIN_SIGNAL),
  49.       "",
  50.       ngx_signal_handler },

  51.     { SIGALRM, "SIGALRM", "", ngx_signal_handler },

  52.     { SIGINT, "SIGINT", "", ngx_signal_handler },

  53.     { SIGIO, "SIGIO", "", ngx_signal_handler },

  54.     { SIGCHLD, "SIGCHLD", "", ngx_signal_handler },

  55.     { SIGSYS, "SIGSYS, SIG_IGN", "", NULL },

  56.     { SIGPIPE, "SIGPIPE, SIG_IGN", "", NULL },

  57.     { 0, NULL, "", NULL }
  58. };


  59. ngx_pid_t
  60. ngx_spawn_process(ngx_cycle_t *cycle, ngx_spawn_proc_pt proc, void *data,
  61.     char *name, ngx_int_t respawn)
  62. {
  63.     u_long     on;
  64.     ngx_pid_t  pid;
  65.     ngx_int_t  s;

  66.     if (respawn >= 0) {
  67.         s = respawn;

  68.     } else {
  69.         for (s = 0; s < ngx_last_process; s++) {
  70.             if (ngx_processes[s].pid == -1) {
  71.                 break;
  72.             }
  73.         }

  74.         if (s == NGX_MAX_PROCESSES) {
  75.             ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
  76.                           "no more than %d processes can be spawned",
  77.                           NGX_MAX_PROCESSES);
  78.             return NGX_INVALID_PID;
  79.         }
  80.     }


  81.     if (respawn != NGX_PROCESS_DETACHED) {

  82.         /* Solaris 9 still has no AF_LOCAL */

  83.         if (socketpair(AF_UNIX, SOCK_STREAM, 0, ngx_processes[s].channel) == -1)
  84.         {
  85.             ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
  86.                           "socketpair() failed while spawning \"%s\"", name);
  87.             return NGX_INVALID_PID;
  88.         }

  89.         ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0,
  90.                        "channel %d:%d",
  91.                        ngx_processes[s].channel[0],
  92.                        ngx_processes[s].channel[1]);

  93.         if (ngx_nonblocking(ngx_processes[s].channel[0]) == -1) {
  94.             ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
  95.                           ngx_nonblocking_n " failed while spawning \"%s\"",
  96.                           name);
  97.             ngx_close_channel(ngx_processes[s].channel, cycle->log);
  98.             return NGX_INVALID_PID;
  99.         }

  100.         if (ngx_nonblocking(ngx_processes[s].channel[1]) == -1) {
  101.             ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
  102.                           ngx_nonblocking_n " failed while spawning \"%s\"",
  103.                           name);
  104.             ngx_close_channel(ngx_processes[s].channel, cycle->log);
  105.             return NGX_INVALID_PID;
  106.         }

  107.         on = 1;
  108.         if (ioctl(ngx_processes[s].channel[0], FIOASYNC, &on) == -1) {
  109.             ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
  110.                           "ioctl(FIOASYNC) failed while spawning \"%s\"", name);
  111.             ngx_close_channel(ngx_processes[s].channel, cycle->log);
  112.             return NGX_INVALID_PID;
  113.         }

  114.         if (fcntl(ngx_processes[s].channel[0], F_SETOWN, ngx_pid) == -1) {
  115.             ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
  116.                           "fcntl(F_SETOWN) failed while spawning \"%s\"", name);
  117.             ngx_close_channel(ngx_processes[s].channel, cycle->log);
  118.             return NGX_INVALID_PID;
  119.         }

  120.         if (fcntl(ngx_processes[s].channel[0], F_SETFD, FD_CLOEXEC) == -1) {
  121.             ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
  122.                           "fcntl(FD_CLOEXEC) failed while spawning \"%s\"",
  123.                            name);
  124.             ngx_close_channel(ngx_processes[s].channel, cycle->log);
  125.             return NGX_INVALID_PID;
  126.         }

  127.         if (fcntl(ngx_processes[s].channel[1], F_SETFD, FD_CLOEXEC) == -1) {
  128.             ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
  129.                           "fcntl(FD_CLOEXEC) failed while spawning \"%s\"",
  130.                            name);
  131.             ngx_close_channel(ngx_processes[s].channel, cycle->log);
  132.             return NGX_INVALID_PID;
  133.         }

  134.         ngx_channel = ngx_processes[s].channel[1];

  135.     } else {
  136.         ngx_processes[s].channel[0] = -1;
  137.         ngx_processes[s].channel[1] = -1;
  138.     }

  139.     ngx_process_slot = s;


  140.     pid = fork();

  141.     switch (pid) {

  142.     case -1:
  143.         ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
  144.                       "fork() failed while spawning \"%s\"", name);
  145.         ngx_close_channel(ngx_processes[s].channel, cycle->log);
  146.         return NGX_INVALID_PID;

  147.     case 0:
  148.         ngx_parent = ngx_pid;
  149.         ngx_pid = ngx_getpid();
  150.         proc(cycle, data);
  151.         break;

  152.     default:
  153.         break;
  154.     }

  155.     ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "start %s %P", name, pid);

  156.     ngx_processes[s].pid = pid;
  157.     ngx_processes[s].exited = 0;

  158.     if (respawn >= 0) {
  159.         return pid;
  160.     }

  161.     ngx_processes[s].proc = proc;
  162.     ngx_processes[s].data = data;
  163.     ngx_processes[s].name = name;
  164.     ngx_processes[s].exiting = 0;

  165.     switch (respawn) {

  166.     case NGX_PROCESS_NORESPAWN:
  167.         ngx_processes[s].respawn = 0;
  168.         ngx_processes[s].just_spawn = 0;
  169.         ngx_processes[s].detached = 0;
  170.         break;

  171.     case NGX_PROCESS_JUST_SPAWN:
  172.         ngx_processes[s].respawn = 0;
  173.         ngx_processes[s].just_spawn = 1;
  174.         ngx_processes[s].detached = 0;
  175.         break;

  176.     case NGX_PROCESS_RESPAWN:
  177.         ngx_processes[s].respawn = 1;
  178.         ngx_processes[s].just_spawn = 0;
  179.         ngx_processes[s].detached = 0;
  180.         break;

  181.     case NGX_PROCESS_JUST_RESPAWN:
  182.         ngx_processes[s].respawn = 1;
  183.         ngx_processes[s].just_spawn = 1;
  184.         ngx_processes[s].detached = 0;
  185.         break;

  186.     case NGX_PROCESS_DETACHED:
  187.         ngx_processes[s].respawn = 0;
  188.         ngx_processes[s].just_spawn = 0;
  189.         ngx_processes[s].detached = 1;
  190.         break;
  191.     }

  192.     if (s == ngx_last_process) {
  193.         ngx_last_process++;
  194.     }

  195.     return pid;
  196. }


  197. ngx_pid_t
  198. ngx_execute(ngx_cycle_t *cycle, ngx_exec_ctx_t *ctx)
  199. {
  200.     return ngx_spawn_process(cycle, ngx_execute_proc, ctx, ctx->name,
  201.                              NGX_PROCESS_DETACHED);
  202. }


  203. static void
  204. ngx_execute_proc(ngx_cycle_t *cycle, void *data)
  205. {
  206.     ngx_exec_ctx_t  *ctx = data;

  207.     if (execve(ctx->path, ctx->argv, ctx->envp) == -1) {
  208.         ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
  209.                       "execve() failed while executing %s \"%s\"",
  210.                       ctx->name, ctx->path);
  211.     }

  212.     exit(1);
  213. }


  214. ngx_int_t
  215. ngx_init_signals(ngx_log_t *log)
  216. {
  217.     ngx_signal_t      *sig;
  218.     struct sigaction   sa;

  219.     for (sig = signals; sig->signo != 0; sig++) {
  220.         ngx_memzero(&sa, sizeof(struct sigaction));

  221.         if (sig->handler) {
  222.             sa.sa_sigaction = sig->handler;
  223.             sa.sa_flags = SA_SIGINFO;

  224.         } else {
  225.             sa.sa_handler = SIG_IGN;
  226.         }

  227.         sigemptyset(&sa.sa_mask);
  228.         if (sigaction(sig->signo, &sa, NULL) == -1) {
  229. #if (NGX_VALGRIND)
  230.             ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
  231.                           "sigaction(%s) failed, ignored", sig->signame);
  232. #else
  233.             ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
  234.                           "sigaction(%s) failed", sig->signame);
  235.             return NGX_ERROR;
  236. #endif
  237.         }
  238.     }

  239.     return NGX_OK;
  240. }


  241. static void
  242. ngx_signal_handler(int signo, siginfo_t *siginfo, void *ucontext)
  243. {
  244.     char            *action;
  245.     ngx_int_t        ignore;
  246.     ngx_err_t        err;
  247.     ngx_signal_t    *sig;

  248.     ignore = 0;

  249.     err = ngx_errno;

  250.     for (sig = signals; sig->signo != 0; sig++) {
  251.         if (sig->signo == signo) {
  252.             break;
  253.         }
  254.     }

  255.     ngx_time_sigsafe_update();

  256.     action = "";

  257.     switch (ngx_process) {

  258.     case NGX_PROCESS_MASTER:
  259.     case NGX_PROCESS_SINGLE:
  260.         switch (signo) {

  261.         case ngx_signal_value(NGX_SHUTDOWN_SIGNAL):
  262.             ngx_quit = 1;
  263.             action = ", shutting down";
  264.             break;

  265.         case ngx_signal_value(NGX_TERMINATE_SIGNAL):
  266.         case SIGINT:
  267.             ngx_terminate = 1;
  268.             action = ", exiting";
  269.             break;

  270.         case ngx_signal_value(NGX_NOACCEPT_SIGNAL):
  271.             if (ngx_daemonized) {
  272.                 ngx_noaccept = 1;
  273.                 action = ", stop accepting connections";
  274.             }
  275.             break;

  276.         case ngx_signal_value(NGX_RECONFIGURE_SIGNAL):
  277.             ngx_reconfigure = 1;
  278.             action = ", reconfiguring";
  279.             break;

  280.         case ngx_signal_value(NGX_REOPEN_SIGNAL):
  281.             ngx_reopen = 1;
  282.             action = ", reopening logs";
  283.             break;

  284.         case ngx_signal_value(NGX_CHANGEBIN_SIGNAL):
  285.             if (ngx_getppid() == ngx_parent || ngx_new_binary > 0) {

  286.                 /*
  287.                  * Ignore the signal in the new binary if its parent is
  288.                  * not changed, i.e. the old binary's process is still
  289.                  * running.  Or ignore the signal in the old binary's
  290.                  * process if the new binary's process is already running.
  291.                  */

  292.                 action = ", ignoring";
  293.                 ignore = 1;
  294.                 break;
  295.             }

  296.             ngx_change_binary = 1;
  297.             action = ", changing binary";
  298.             break;

  299.         case SIGALRM:
  300.             ngx_sigalrm = 1;
  301.             break;

  302.         case SIGIO:
  303.             ngx_sigio = 1;
  304.             break;

  305.         case SIGCHLD:
  306.             ngx_reap = 1;
  307.             break;
  308.         }

  309.         break;

  310.     case NGX_PROCESS_WORKER:
  311.     case NGX_PROCESS_HELPER:
  312.         switch (signo) {

  313.         case ngx_signal_value(NGX_NOACCEPT_SIGNAL):
  314.             if (!ngx_daemonized) {
  315.                 break;
  316.             }
  317.             ngx_debug_quit = 1;
  318.             /* fall through */
  319.         case ngx_signal_value(NGX_SHUTDOWN_SIGNAL):
  320.             ngx_quit = 1;
  321.             action = ", shutting down";
  322.             break;

  323.         case ngx_signal_value(NGX_TERMINATE_SIGNAL):
  324.         case SIGINT:
  325.             ngx_terminate = 1;
  326.             action = ", exiting";
  327.             break;

  328.         case ngx_signal_value(NGX_REOPEN_SIGNAL):
  329.             ngx_reopen = 1;
  330.             action = ", reopening logs";
  331.             break;

  332.         case ngx_signal_value(NGX_RECONFIGURE_SIGNAL):
  333.         case ngx_signal_value(NGX_CHANGEBIN_SIGNAL):
  334.         case SIGIO:
  335.             action = ", ignoring";
  336.             break;
  337.         }

  338.         break;
  339.     }

  340.     if (siginfo && siginfo->si_pid) {
  341.         ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0,
  342.                       "signal %d (%s) received from %P%s",
  343.                       signo, sig->signame, siginfo->si_pid, action);

  344.     } else {
  345.         ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0,
  346.                       "signal %d (%s) received%s",
  347.                       signo, sig->signame, action);
  348.     }

  349.     if (ignore) {
  350.         ngx_log_error(NGX_LOG_CRIT, ngx_cycle->log, 0,
  351.                       "the changing binary signal is ignored: "
  352.                       "you should shutdown or terminate "
  353.                       "before either old or new binary's process");
  354.     }

  355.     if (signo == SIGCHLD) {
  356.         ngx_process_get_status();
  357.     }

  358.     ngx_set_errno(err);
  359. }


  360. static void
  361. ngx_process_get_status(void)
  362. {
  363.     int              status;
  364.     char            *process;
  365.     ngx_pid_t        pid;
  366.     ngx_err_t        err;
  367.     ngx_int_t        i;
  368.     ngx_uint_t       one;

  369.     one = 0;

  370.     for ( ;; ) {
  371.         pid = waitpid(-1, &status, WNOHANG);

  372.         if (pid == 0) {
  373.             return;
  374.         }

  375.         if (pid == -1) {
  376.             err = ngx_errno;

  377.             if (err == NGX_EINTR) {
  378.                 continue;
  379.             }

  380.             if (err == NGX_ECHILD && one) {
  381.                 return;
  382.             }

  383.             /*
  384.              * Solaris always calls the signal handler for each exited process
  385.              * despite waitpid() may be already called for this process.
  386.              *
  387.              * When several processes exit at the same time FreeBSD may
  388.              * erroneously call the signal handler for exited process
  389.              * despite waitpid() may be already called for this process.
  390.              */

  391.             if (err == NGX_ECHILD) {
  392.                 ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, err,
  393.                               "waitpid() failed");
  394.                 return;
  395.             }

  396.             ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, err,
  397.                           "waitpid() failed");
  398.             return;
  399.         }


  400.         one = 1;
  401.         process = "unknown process";

  402.         for (i = 0; i < ngx_last_process; i++) {
  403.             if (ngx_processes[i].pid == pid) {
  404.                 ngx_processes[i].status = status;
  405.                 ngx_processes[i].exited = 1;
  406.                 process = ngx_processes[i].name;
  407.                 break;
  408.             }
  409.         }

  410.         if (WTERMSIG(status)) {
  411. #ifdef WCOREDUMP
  412.             ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
  413.                           "%s %P exited on signal %d%s",
  414.                           process, pid, WTERMSIG(status),
  415.                           WCOREDUMP(status) ? " (core dumped)" : "");
  416. #else
  417.             ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
  418.                           "%s %P exited on signal %d",
  419.                           process, pid, WTERMSIG(status));
  420. #endif

  421.         } else {
  422.             ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0,
  423.                           "%s %P exited with code %d",
  424.                           process, pid, WEXITSTATUS(status));
  425.         }

  426.         if (WEXITSTATUS(status) == 2 && ngx_processes[i].respawn) {
  427.             ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
  428.                           "%s %P exited with fatal code %d "
  429.                           "and cannot be respawned",
  430.                           process, pid, WEXITSTATUS(status));
  431.             ngx_processes[i].respawn = 0;
  432.         }

  433.         ngx_unlock_mutexes(pid);
  434.     }
  435. }


  436. static void
  437. ngx_unlock_mutexes(ngx_pid_t pid)
  438. {
  439.     ngx_uint_t        i;
  440.     ngx_shm_zone_t   *shm_zone;
  441.     ngx_list_part_t  *part;
  442.     ngx_slab_pool_t  *sp;

  443.     /*
  444.      * unlock the accept mutex if the abnormally exited process
  445.      * held it
  446.      */

  447.     if (ngx_accept_mutex_ptr) {
  448.         (void) ngx_shmtx_force_unlock(&ngx_accept_mutex, pid);
  449.     }

  450.     /*
  451.      * unlock shared memory mutexes if held by the abnormally exited
  452.      * process
  453.      */

  454.     part = (ngx_list_part_t *) &ngx_cycle->shared_memory.part;
  455.     shm_zone = part->elts;

  456.     for (i = 0; /* void */ ; i++) {

  457.         if (i >= part->nelts) {
  458.             if (part->next == NULL) {
  459.                 break;
  460.             }
  461.             part = part->next;
  462.             shm_zone = part->elts;
  463.             i = 0;
  464.         }

  465.         sp = (ngx_slab_pool_t *) shm_zone[i].shm.addr;

  466.         if (ngx_shmtx_force_unlock(&sp->mutex, pid)) {
  467.             ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
  468.                           "shared memory zone \"%V\" was locked by %P",
  469.                           &shm_zone[i].shm.name, pid);
  470.         }
  471.     }
  472. }


  473. void
  474. ngx_debug_point(void)
  475. {
  476.     ngx_core_conf_t  *ccf;

  477.     ccf = (ngx_core_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx,
  478.                                            ngx_core_module);

  479.     switch (ccf->debug_points) {

  480.     case NGX_DEBUG_POINTS_STOP:
  481.         raise(SIGSTOP);
  482.         break;

  483.     case NGX_DEBUG_POINTS_ABORT:
  484.         ngx_abort();
  485.     }
  486. }


  487. ngx_int_t
  488. ngx_os_signal_process(ngx_cycle_t *cycle, char *name, ngx_pid_t pid)
  489. {
  490.     ngx_signal_t  *sig;

  491.     for (sig = signals; sig->signo != 0; sig++) {
  492.         if (ngx_strcmp(name, sig->name) == 0) {
  493.             if (kill(pid, sig->signo) != -1) {
  494.                 return 0;
  495.             }

  496.             ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
  497.                           "kill(%P, %d) failed", pid, sig->signo);
  498.         }
  499.     }

  500.     return 1;
  501. }