src/os/unix/ngx_process.c - nginx-1.7.10

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);
  14. } ngx_signal_t;



  15. static void ngx_execute_proc(ngx_cycle_t *cycle, void *data);
  16. static void ngx_signal_handler(int signo);
  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", "", SIG_IGN },

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

  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_pid = ngx_getpid();
  149.         proc(cycle, data);
  150.         break;

  151.     default:
  152.         break;
  153.     }

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

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

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

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

  164.     switch (respawn) {

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

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

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

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

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

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

  194.     return pid;
  195. }


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


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

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

  211.     exit(1);
  212. }


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

  218.     for (sig = signals; sig->signo != 0; sig++) {
  219.         ngx_memzero(&sa, sizeof(struct sigaction));
  220.         sa.sa_handler = sig->handler;
  221.         sigemptyset(&sa.sa_mask);
  222.         if (sigaction(sig->signo, &sa, NULL) == -1) {
  223. #if (NGX_VALGRIND)
  224.             ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
  225.                           "sigaction(%s) failed, ignored", sig->signame);
  226. #else
  227.             ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
  228.                           "sigaction(%s) failed", sig->signame);
  229.             return NGX_ERROR;
  230. #endif
  231.         }
  232.     }

  233.     return NGX_OK;
  234. }


  235. void
  236. ngx_signal_handler(int signo)
  237. {
  238.     char            *action;
  239.     ngx_int_t        ignore;
  240.     ngx_err_t        err;
  241.     ngx_signal_t    *sig;

  242.     ignore = 0;

  243.     err = ngx_errno;

  244.     for (sig = signals; sig->signo != 0; sig++) {
  245.         if (sig->signo == signo) {
  246.             break;
  247.         }
  248.     }

  249.     ngx_time_sigsafe_update();

  250.     action = "";

  251.     switch (ngx_process) {

  252.     case NGX_PROCESS_MASTER:
  253.     case NGX_PROCESS_SINGLE:
  254.         switch (signo) {

  255.         case ngx_signal_value(NGX_SHUTDOWN_SIGNAL):
  256.             ngx_quit = 1;
  257.             action = ", shutting down";
  258.             break;

  259.         case ngx_signal_value(NGX_TERMINATE_SIGNAL):
  260.         case SIGINT:
  261.             ngx_terminate = 1;
  262.             action = ", exiting";
  263.             break;

  264.         case ngx_signal_value(NGX_NOACCEPT_SIGNAL):
  265.             if (ngx_daemonized) {
  266.                 ngx_noaccept = 1;
  267.                 action = ", stop accepting connections";
  268.             }
  269.             break;

  270.         case ngx_signal_value(NGX_RECONFIGURE_SIGNAL):
  271.             ngx_reconfigure = 1;
  272.             action = ", reconfiguring";
  273.             break;

  274.         case ngx_signal_value(NGX_REOPEN_SIGNAL):
  275.             ngx_reopen = 1;
  276.             action = ", reopening logs";
  277.             break;

  278.         case ngx_signal_value(NGX_CHANGEBIN_SIGNAL):
  279.             if (getppid() > 1 || ngx_new_binary > 0) {

  280.                 /*
  281.                  * Ignore the signal in the new binary if its parent is
  282.                  * not the init process, i.e. the old binary's process
  283.                  * is still running.  Or ignore the signal in the old binary's
  284.                  * process if the new binary's process is already running.
  285.                  */

  286.                 action = ", ignoring";
  287.                 ignore = 1;
  288.                 break;
  289.             }

  290.             ngx_change_binary = 1;
  291.             action = ", changing binary";
  292.             break;

  293.         case SIGALRM:
  294.             ngx_sigalrm = 1;
  295.             break;

  296.         case SIGIO:
  297.             ngx_sigio = 1;
  298.             break;

  299.         case SIGCHLD:
  300.             ngx_reap = 1;
  301.             break;
  302.         }

  303.         break;

  304.     case NGX_PROCESS_WORKER:
  305.     case NGX_PROCESS_HELPER:
  306.         switch (signo) {

  307.         case ngx_signal_value(NGX_NOACCEPT_SIGNAL):
  308.             if (!ngx_daemonized) {
  309.                 break;
  310.             }
  311.             ngx_debug_quit = 1;
  312.         case ngx_signal_value(NGX_SHUTDOWN_SIGNAL):
  313.             ngx_quit = 1;
  314.             action = ", shutting down";
  315.             break;

  316.         case ngx_signal_value(NGX_TERMINATE_SIGNAL):
  317.         case SIGINT:
  318.             ngx_terminate = 1;
  319.             action = ", exiting";
  320.             break;

  321.         case ngx_signal_value(NGX_REOPEN_SIGNAL):
  322.             ngx_reopen = 1;
  323.             action = ", reopening logs";
  324.             break;

  325.         case ngx_signal_value(NGX_RECONFIGURE_SIGNAL):
  326.         case ngx_signal_value(NGX_CHANGEBIN_SIGNAL):
  327.         case SIGIO:
  328.             action = ", ignoring";
  329.             break;
  330.         }

  331.         break;
  332.     }

  333.     ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0,
  334.                   "signal %d (%s) received%s", signo, sig->signame, action);

  335.     if (ignore) {
  336.         ngx_log_error(NGX_LOG_CRIT, ngx_cycle->log, 0,
  337.                       "the changing binary signal is ignored: "
  338.                       "you should shutdown or terminate "
  339.                       "before either old or new binary's process");
  340.     }

  341.     if (signo == SIGCHLD) {
  342.         ngx_process_get_status();
  343.     }

  344.     ngx_set_errno(err);
  345. }


  346. static void
  347. ngx_process_get_status(void)
  348. {
  349.     int              status;
  350.     char            *process;
  351.     ngx_pid_t        pid;
  352.     ngx_err_t        err;
  353.     ngx_int_t        i;
  354.     ngx_uint_t       one;

  355.     one = 0;

  356.     for ( ;; ) {
  357.         pid = waitpid(-1, &status, WNOHANG);

  358.         if (pid == 0) {
  359.             return;
  360.         }

  361.         if (pid == -1) {
  362.             err = ngx_errno;

  363.             if (err == NGX_EINTR) {
  364.                 continue;
  365.             }

  366.             if (err == NGX_ECHILD && one) {
  367.                 return;
  368.             }

  369.             /*
  370.              * Solaris always calls the signal handler for each exited process
  371.              * despite waitpid() may be already called for this process.
  372.              *
  373.              * When several processes exit at the same time FreeBSD may
  374.              * erroneously call the signal handler for exited process
  375.              * despite waitpid() may be already called for this process.
  376.              */

  377.             if (err == NGX_ECHILD) {
  378.                 ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, err,
  379.                               "waitpid() failed");
  380.                 return;
  381.             }

  382.             ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, err,
  383.                           "waitpid() failed");
  384.             return;
  385.         }


  386.         one = 1;
  387.         process = "unknown process";

  388.         for (i = 0; i < ngx_last_process; i++) {
  389.             if (ngx_processes[i].pid == pid) {
  390.                 ngx_processes[i].status = status;
  391.                 ngx_processes[i].exited = 1;
  392.                 process = ngx_processes[i].name;
  393.                 break;
  394.             }
  395.         }

  396.         if (WTERMSIG(status)) {
  397. #ifdef WCOREDUMP
  398.             ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
  399.                           "%s %P exited on signal %d%s",
  400.                           process, pid, WTERMSIG(status),
  401.                           WCOREDUMP(status) ? " (core dumped)" : "");
  402. #else
  403.             ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
  404.                           "%s %P exited on signal %d",
  405.                           process, pid, WTERMSIG(status));
  406. #endif

  407.         } else {
  408.             ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0,
  409.                           "%s %P exited with code %d",
  410.                           process, pid, WEXITSTATUS(status));
  411.         }

  412.         if (WEXITSTATUS(status) == 2 && ngx_processes[i].respawn) {
  413.             ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
  414.                           "%s %P exited with fatal code %d "
  415.                           "and cannot be respawned",
  416.                           process, pid, WEXITSTATUS(status));
  417.             ngx_processes[i].respawn = 0;
  418.         }

  419.         ngx_unlock_mutexes(pid);
  420.     }
  421. }


  422. static void
  423. ngx_unlock_mutexes(ngx_pid_t pid)
  424. {
  425.     ngx_uint_t        i;
  426.     ngx_shm_zone_t   *shm_zone;
  427.     ngx_list_part_t  *part;
  428.     ngx_slab_pool_t  *sp;

  429.     /*
  430.      * unlock the accept mutex if the abnormally exited process
  431.      * held it
  432.      */

  433.     if (ngx_accept_mutex_ptr) {
  434.         (void) ngx_shmtx_force_unlock(&ngx_accept_mutex, pid);
  435.     }

  436.     /*
  437.      * unlock shared memory mutexes if held by the abnormally exited
  438.      * process
  439.      */

  440.     part = (ngx_list_part_t *) &ngx_cycle->shared_memory.part;
  441.     shm_zone = part->elts;

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

  443.         if (i >= part->nelts) {
  444.             if (part->next == NULL) {
  445.                 break;
  446.             }
  447.             part = part->next;
  448.             shm_zone = part->elts;
  449.             i = 0;
  450.         }

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

  452.         if (ngx_shmtx_force_unlock(&sp->mutex, pid)) {
  453.             ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
  454.                           "shared memory zone \"%V\" was locked by %P",
  455.                           &shm_zone[i].shm.name, pid);
  456.         }
  457.     }
  458. }


  459. void
  460. ngx_debug_point(void)
  461. {
  462.     ngx_core_conf_t  *ccf;

  463.     ccf = (ngx_core_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx,
  464.                                            ngx_core_module);

  465.     switch (ccf->debug_points) {

  466.     case NGX_DEBUG_POINTS_STOP:
  467.         raise(SIGSTOP);
  468.         break;

  469.     case NGX_DEBUG_POINTS_ABORT:
  470.         ngx_abort();
  471.     }
  472. }


  473. ngx_int_t
  474. ngx_os_signal_process(ngx_cycle_t *cycle, char *name, ngx_int_t pid)
  475. {
  476.     ngx_signal_t  *sig;

  477.     for (sig = signals; sig->signo != 0; sig++) {
  478.         if (ngx_strcmp(name, sig->name) == 0) {
  479.             if (kill(pid, sig->signo) != -1) {
  480.                 return 0;
  481.             }

  482.             ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
  483.                           "kill(%P, %d) failed", pid, sig->signo);
  484.         }
  485.     }

  486.     return 1;
  487. }