view src/os/unix/ngx_process.c @ 218:05592fd7a436

nginx-0.0.1-2004-01-05-23:55:48 import
author Igor Sysoev <igor@sysoev.ru>
date Mon, 05 Jan 2004 20:55:48 +0000
parents 8dee38ea9117
children f57597ec5249
line wrap: on
line source


#include <ngx_config.h>
#include <ngx_core.h>


static void ngx_exec_proc(ngx_cycle_t *cycle, void *data);

ngx_uint_t     ngx_last_process;
ngx_process_t  ngx_processes[NGX_MAX_PROCESSES];


ngx_int_t ngx_spawn_process(ngx_cycle_t *cycle,
                            ngx_spawn_proc_pt proc, void *data,
                            char *name, ngx_int_t respawn)
{
    sigset_t   set, oset;
    ngx_pid_t  pid;

    if (respawn < 0) {
        sigemptyset(&set);
        sigaddset(&set, SIGCHLD);
        if (sigprocmask(SIG_BLOCK, &set, &oset) == -1) {
            ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                          "sigprocmask() failed while spawning %s", name);
            return NGX_ERROR;
        }
    }

    pid = fork();

    if (pid == -1) {
        ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                      "fork() failed while spawning \"%s\"", name);
    }

    if (pid == -1 || pid == 0) {
        if (sigprocmask(SIG_SETMASK, &oset, &set) == -1) {
            ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                          "sigprocmask() failed while spawning %s", name);
            return NGX_ERROR;
        }
    }

    switch (pid) {
    case -1:
        return NGX_ERROR;

    case 0:
        proc(cycle, data);
        break;

    default:
        break;
    }

    ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0,
                   "spawn %s: " PID_T_FMT, name, pid);

    if (respawn >= 0) {
        ngx_processes[respawn].pid = pid;
        ngx_processes[respawn].exited = 0;
        return NGX_OK;
    }

    ngx_processes[ngx_last_process].pid = pid;
    ngx_processes[ngx_last_process].proc = proc;
    ngx_processes[ngx_last_process].data = data;
    ngx_processes[ngx_last_process].name = name;
    ngx_processes[ngx_last_process].respawn =
                                      (respawn == NGX_PROCESS_RESPAWN) ? 1 : 0;
    ngx_processes[ngx_last_process].detached =
                                     (respawn == NGX_PROCESS_DETACHED) ? 1 : 0;
    ngx_processes[ngx_last_process].exited = 0;
    ngx_processes[ngx_last_process].exiting = 0;
    ngx_last_process++;

    if (sigprocmask(SIG_SETMASK, &oset, &set) == -1) {
        ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                      "sigprocmask() failed while spawning %s", name);
        return NGX_ERROR;
    }

    return NGX_OK;
}


ngx_int_t ngx_exec(ngx_cycle_t *cycle, ngx_exec_ctx_t *ctx)
{
    if (ngx_spawn_process(cycle, ngx_exec_proc, ctx, ctx->name,
                                            NGX_PROCESS_DETACHED) == NGX_ERROR)
    {
        ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
                      "can not spawn %s", ctx->name);
        return NGX_ERROR;
    }

    return NGX_OK;
}


static void ngx_exec_proc(ngx_cycle_t *cycle, void *data)
{
    ngx_exec_ctx_t  *ctx = data;

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

    exit(1);
}


void ngx_signal_processes(ngx_cycle_t *cycle, ngx_int_t signal)
{
    sigset_t    set, oset;
    ngx_uint_t  i;

    sigemptyset(&set);
    sigaddset(&set, SIGCHLD);
    if (sigprocmask(SIG_BLOCK, &set, &oset) == -1) {
        ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                      "sigprocmask() failed while signaling processes");
        return;
    }

    for (i = 0; i < ngx_last_process; i++) {

        if (ngx_processes[i].detached) {
            continue;
        }

        if (ngx_processes[i].exited) {
            if (i != --ngx_last_process) {
                ngx_processes[i--] = ngx_processes[ngx_last_process];
            }
            continue;
        }

        ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0,
                       "kill (" PID_T_FMT ", %d)" ,
                       ngx_processes[i].pid, signal);

        if (kill(ngx_processes[i].pid, signal) == -1) {
            ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                          "kill(%d, %d) failed", ngx_processes[i].pid, signal);
            continue;
        }

        if (signal != ngx_signal_value(NGX_REOPEN_SIGNAL)) {
            ngx_processes[i].exiting = 1;
        }
    }

    if (sigprocmask(SIG_SETMASK, &oset, &set) == -1) {
        ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                      "sigprocmask() failed while signaling processes");
    }
}


void ngx_respawn_processes(ngx_cycle_t *cycle)
{
    sigset_t    set, oset;
    ngx_uint_t  i;

    sigemptyset(&set);
    sigaddset(&set, SIGCHLD);
    if (sigprocmask(SIG_BLOCK, &set, &oset) == -1) {
        ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                      "sigprocmask() failed while respawning processes");
        return;
    }

    /*
     * to avoid a race condition we can check and set value of ngx_respawn
     * only in signal handler or while SIGCHLD is blocked
     */

    if (ngx_respawn) {

        for (i = 0; i < ngx_last_process; i++) {
            if (!ngx_processes[i].exited) {
                continue;
            }

            if (!ngx_processes[i].respawn) {
                if (i != --ngx_last_process) {
                    ngx_processes[i--] = ngx_processes[ngx_last_process];
                }
                continue;
            }

            if (ngx_spawn_process(cycle,
                                  ngx_processes[i].proc, ngx_processes[i].data,
                                  ngx_processes[i].name, i) == NGX_ERROR)
            {
                ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
                              "can not respawn %s", ngx_processes[i].name);
            }
        }

        ngx_respawn = 0;
    }

    if (sigprocmask(SIG_SETMASK, &oset, &set) == -1) {
        ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                      "sigprocmask() failed while respawning processes");
    }
}


#if 0
void ngx_sigchld_handler(int signo)
{
    int              status;
    char            *process;
    ngx_pid_t        pid;
    ngx_err_t        err;
    ngx_uint_t       i, one;
    struct timeval   tv;

    ngx_gettimeofday(&tv);
    ngx_time_update(tv.tv_sec);

    ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, 0,
                  "signal #%d (SIGCHLD) received", signo);
}
#endif


void ngx_process_get_status()
{
    int              status;
    char            *process;
    ngx_pid_t        pid;
    ngx_err_t        err;
    ngx_uint_t       i, one;
    struct timeval   tv;
    one = 0;

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

        if (pid == 0) {
            return;
        }

        if (pid == -1) {
            err = ngx_errno;

            if (err == NGX_EINTR) {
                continue;
            }

            if (err == NGX_ECHILD && one) {
                return;
            }

            ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, errno,
                          "waitpid() failed");
            return;
        }

        one = 1;
        process = "";

        for (i = 0; i < ngx_last_process; i++) {
            if (ngx_processes[i].pid == pid) {
                ngx_processes[i].status = status;

                if (!ngx_processes[i].exiting) {
                    ngx_processes[i].exited = 1;

                    if (ngx_processes[i].respawn) {
                        ngx_respawn = 1;
                    }
                }

                process = ngx_processes[i].name;
                break;
            }
        }

        if (i == ngx_last_process) {
            process = "unknown process";
        }

        if (WTERMSIG(status)) {
            ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
                          "%s " PID_T_FMT " exited on signal %d%s",
                          process, pid, WTERMSIG(status),
                          WCOREDUMP(status) ? " (core dumped)" : "");

        } else {
            ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, 0,
                          "%s " PID_T_FMT " exited with code %d",
                          process, pid, WEXITSTATUS(status));
        }
    }
}