diff options
Diffstat (limited to 'storage/mroonga/vendor/groonga/vendor/nginx-1.7.4/src/os/unix/ngx_process.c')
-rw-r--r-- | storage/mroonga/vendor/groonga/vendor/nginx-1.7.4/src/os/unix/ngx_process.c | 630 |
1 files changed, 630 insertions, 0 deletions
diff --git a/storage/mroonga/vendor/groonga/vendor/nginx-1.7.4/src/os/unix/ngx_process.c b/storage/mroonga/vendor/groonga/vendor/nginx-1.7.4/src/os/unix/ngx_process.c new file mode 100644 index 00000000000..6f3f38556ab --- /dev/null +++ b/storage/mroonga/vendor/groonga/vendor/nginx-1.7.4/src/os/unix/ngx_process.c @@ -0,0 +1,630 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include <ngx_config.h> +#include <ngx_core.h> +#include <ngx_event.h> +#include <ngx_channel.h> + + +typedef struct { + int signo; + char *signame; + char *name; + void (*handler)(int signo); +} ngx_signal_t; + + + +static void ngx_execute_proc(ngx_cycle_t *cycle, void *data); +static void ngx_signal_handler(int signo); +static void ngx_process_get_status(void); +static void ngx_unlock_mutexes(ngx_pid_t pid); + + +int ngx_argc; +char **ngx_argv; +char **ngx_os_argv; + +ngx_int_t ngx_process_slot; +ngx_socket_t ngx_channel; +ngx_int_t ngx_last_process; +ngx_process_t ngx_processes[NGX_MAX_PROCESSES]; + + +ngx_signal_t signals[] = { + { ngx_signal_value(NGX_RECONFIGURE_SIGNAL), + "SIG" ngx_value(NGX_RECONFIGURE_SIGNAL), + "reload", + ngx_signal_handler }, + + { ngx_signal_value(NGX_REOPEN_SIGNAL), + "SIG" ngx_value(NGX_REOPEN_SIGNAL), + "reopen", + ngx_signal_handler }, + + { ngx_signal_value(NGX_NOACCEPT_SIGNAL), + "SIG" ngx_value(NGX_NOACCEPT_SIGNAL), + "", + ngx_signal_handler }, + + { ngx_signal_value(NGX_TERMINATE_SIGNAL), + "SIG" ngx_value(NGX_TERMINATE_SIGNAL), + "stop", + ngx_signal_handler }, + + { ngx_signal_value(NGX_SHUTDOWN_SIGNAL), + "SIG" ngx_value(NGX_SHUTDOWN_SIGNAL), + "quit", + ngx_signal_handler }, + + { ngx_signal_value(NGX_CHANGEBIN_SIGNAL), + "SIG" ngx_value(NGX_CHANGEBIN_SIGNAL), + "", + ngx_signal_handler }, + + { SIGALRM, "SIGALRM", "", ngx_signal_handler }, + + { SIGINT, "SIGINT", "", ngx_signal_handler }, + + { SIGIO, "SIGIO", "", ngx_signal_handler }, + + { SIGCHLD, "SIGCHLD", "", ngx_signal_handler }, + + { SIGSYS, "SIGSYS, SIG_IGN", "", SIG_IGN }, + + { SIGPIPE, "SIGPIPE, SIG_IGN", "", SIG_IGN }, + + { 0, NULL, "", NULL } +}; + + +ngx_pid_t +ngx_spawn_process(ngx_cycle_t *cycle, ngx_spawn_proc_pt proc, void *data, + char *name, ngx_int_t respawn) +{ + u_long on; + ngx_pid_t pid; + ngx_int_t s; + + if (respawn >= 0) { + s = respawn; + + } else { + for (s = 0; s < ngx_last_process; s++) { + if (ngx_processes[s].pid == -1) { + break; + } + } + + if (s == NGX_MAX_PROCESSES) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, + "no more than %d processes can be spawned", + NGX_MAX_PROCESSES); + return NGX_INVALID_PID; + } + } + + + if (respawn != NGX_PROCESS_DETACHED) { + + /* Solaris 9 still has no AF_LOCAL */ + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, ngx_processes[s].channel) == -1) + { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "socketpair() failed while spawning \"%s\"", name); + return NGX_INVALID_PID; + } + + ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0, + "channel %d:%d", + ngx_processes[s].channel[0], + ngx_processes[s].channel[1]); + + if (ngx_nonblocking(ngx_processes[s].channel[0]) == -1) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + ngx_nonblocking_n " failed while spawning \"%s\"", + name); + ngx_close_channel(ngx_processes[s].channel, cycle->log); + return NGX_INVALID_PID; + } + + if (ngx_nonblocking(ngx_processes[s].channel[1]) == -1) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + ngx_nonblocking_n " failed while spawning \"%s\"", + name); + ngx_close_channel(ngx_processes[s].channel, cycle->log); + return NGX_INVALID_PID; + } + + on = 1; + if (ioctl(ngx_processes[s].channel[0], FIOASYNC, &on) == -1) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "ioctl(FIOASYNC) failed while spawning \"%s\"", name); + ngx_close_channel(ngx_processes[s].channel, cycle->log); + return NGX_INVALID_PID; + } + + if (fcntl(ngx_processes[s].channel[0], F_SETOWN, ngx_pid) == -1) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "fcntl(F_SETOWN) failed while spawning \"%s\"", name); + ngx_close_channel(ngx_processes[s].channel, cycle->log); + return NGX_INVALID_PID; + } + + if (fcntl(ngx_processes[s].channel[0], F_SETFD, FD_CLOEXEC) == -1) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "fcntl(FD_CLOEXEC) failed while spawning \"%s\"", + name); + ngx_close_channel(ngx_processes[s].channel, cycle->log); + return NGX_INVALID_PID; + } + + if (fcntl(ngx_processes[s].channel[1], F_SETFD, FD_CLOEXEC) == -1) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "fcntl(FD_CLOEXEC) failed while spawning \"%s\"", + name); + ngx_close_channel(ngx_processes[s].channel, cycle->log); + return NGX_INVALID_PID; + } + + ngx_channel = ngx_processes[s].channel[1]; + + } else { + ngx_processes[s].channel[0] = -1; + ngx_processes[s].channel[1] = -1; + } + + ngx_process_slot = s; + + + pid = fork(); + + switch (pid) { + + case -1: + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "fork() failed while spawning \"%s\"", name); + ngx_close_channel(ngx_processes[s].channel, cycle->log); + return NGX_INVALID_PID; + + case 0: + ngx_pid = ngx_getpid(); + proc(cycle, data); + break; + + default: + break; + } + + ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "start %s %P", name, pid); + + ngx_processes[s].pid = pid; + ngx_processes[s].exited = 0; + + if (respawn >= 0) { + return pid; + } + + ngx_processes[s].proc = proc; + ngx_processes[s].data = data; + ngx_processes[s].name = name; + ngx_processes[s].exiting = 0; + + switch (respawn) { + + case NGX_PROCESS_NORESPAWN: + ngx_processes[s].respawn = 0; + ngx_processes[s].just_spawn = 0; + ngx_processes[s].detached = 0; + break; + + case NGX_PROCESS_JUST_SPAWN: + ngx_processes[s].respawn = 0; + ngx_processes[s].just_spawn = 1; + ngx_processes[s].detached = 0; + break; + + case NGX_PROCESS_RESPAWN: + ngx_processes[s].respawn = 1; + ngx_processes[s].just_spawn = 0; + ngx_processes[s].detached = 0; + break; + + case NGX_PROCESS_JUST_RESPAWN: + ngx_processes[s].respawn = 1; + ngx_processes[s].just_spawn = 1; + ngx_processes[s].detached = 0; + break; + + case NGX_PROCESS_DETACHED: + ngx_processes[s].respawn = 0; + ngx_processes[s].just_spawn = 0; + ngx_processes[s].detached = 1; + break; + } + + if (s == ngx_last_process) { + ngx_last_process++; + } + + return pid; +} + + +ngx_pid_t +ngx_execute(ngx_cycle_t *cycle, ngx_exec_ctx_t *ctx) +{ + return ngx_spawn_process(cycle, ngx_execute_proc, ctx, ctx->name, + NGX_PROCESS_DETACHED); +} + + +static void +ngx_execute_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); +} + + +ngx_int_t +ngx_init_signals(ngx_log_t *log) +{ + ngx_signal_t *sig; + struct sigaction sa; + + for (sig = signals; sig->signo != 0; sig++) { + ngx_memzero(&sa, sizeof(struct sigaction)); + sa.sa_handler = sig->handler; + sigemptyset(&sa.sa_mask); + if (sigaction(sig->signo, &sa, NULL) == -1) { +#if (NGX_VALGRIND) + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + "sigaction(%s) failed, ignored", sig->signame); +#else + ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, + "sigaction(%s) failed", sig->signame); + return NGX_ERROR; +#endif + } + } + + return NGX_OK; +} + + +void +ngx_signal_handler(int signo) +{ + char *action; + ngx_int_t ignore; + ngx_err_t err; + ngx_signal_t *sig; + + ignore = 0; + + err = ngx_errno; + + for (sig = signals; sig->signo != 0; sig++) { + if (sig->signo == signo) { + break; + } + } + + ngx_time_sigsafe_update(); + + action = ""; + + switch (ngx_process) { + + case NGX_PROCESS_MASTER: + case NGX_PROCESS_SINGLE: + switch (signo) { + + case ngx_signal_value(NGX_SHUTDOWN_SIGNAL): + ngx_quit = 1; + action = ", shutting down"; + break; + + case ngx_signal_value(NGX_TERMINATE_SIGNAL): + case SIGINT: + ngx_terminate = 1; + action = ", exiting"; + break; + + case ngx_signal_value(NGX_NOACCEPT_SIGNAL): + if (ngx_daemonized) { + ngx_noaccept = 1; + action = ", stop accepting connections"; + } + break; + + case ngx_signal_value(NGX_RECONFIGURE_SIGNAL): + ngx_reconfigure = 1; + action = ", reconfiguring"; + break; + + case ngx_signal_value(NGX_REOPEN_SIGNAL): + ngx_reopen = 1; + action = ", reopening logs"; + break; + + case ngx_signal_value(NGX_CHANGEBIN_SIGNAL): + if (getppid() > 1 || ngx_new_binary > 0) { + + /* + * Ignore the signal in the new binary if its parent is + * not the init process, i.e. the old binary's process + * is still running. Or ignore the signal in the old binary's + * process if the new binary's process is already running. + */ + + action = ", ignoring"; + ignore = 1; + break; + } + + ngx_change_binary = 1; + action = ", changing binary"; + break; + + case SIGALRM: + ngx_sigalrm = 1; + break; + + case SIGIO: + ngx_sigio = 1; + break; + + case SIGCHLD: + ngx_reap = 1; + break; + } + + break; + + case NGX_PROCESS_WORKER: + case NGX_PROCESS_HELPER: + switch (signo) { + + case ngx_signal_value(NGX_NOACCEPT_SIGNAL): + if (!ngx_daemonized) { + break; + } + ngx_debug_quit = 1; + case ngx_signal_value(NGX_SHUTDOWN_SIGNAL): + ngx_quit = 1; + action = ", shutting down"; + break; + + case ngx_signal_value(NGX_TERMINATE_SIGNAL): + case SIGINT: + ngx_terminate = 1; + action = ", exiting"; + break; + + case ngx_signal_value(NGX_REOPEN_SIGNAL): + ngx_reopen = 1; + action = ", reopening logs"; + break; + + case ngx_signal_value(NGX_RECONFIGURE_SIGNAL): + case ngx_signal_value(NGX_CHANGEBIN_SIGNAL): + case SIGIO: + action = ", ignoring"; + break; + } + + break; + } + + ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0, + "signal %d (%s) received%s", signo, sig->signame, action); + + if (ignore) { + ngx_log_error(NGX_LOG_CRIT, ngx_cycle->log, 0, + "the changing binary signal is ignored: " + "you should shutdown or terminate " + "before either old or new binary's process"); + } + + if (signo == SIGCHLD) { + ngx_process_get_status(); + } + + ngx_set_errno(err); +} + + +static void +ngx_process_get_status(void) +{ + int status; + char *process; + ngx_pid_t pid; + ngx_err_t err; + ngx_int_t i; + ngx_uint_t one; + + 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; + } + + /* + * Solaris always calls the signal handler for each exited process + * despite waitpid() may be already called for this process. + * + * When several processes exit at the same time FreeBSD may + * erroneously call the signal handler for exited process + * despite waitpid() may be already called for this process. + */ + + if (err == NGX_ECHILD) { + ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, err, + "waitpid() failed"); + return; + } + + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, err, + "waitpid() failed"); + return; + } + + + one = 1; + process = "unknown process"; + + for (i = 0; i < ngx_last_process; i++) { + if (ngx_processes[i].pid == pid) { + ngx_processes[i].status = status; + ngx_processes[i].exited = 1; + process = ngx_processes[i].name; + break; + } + } + + if (WTERMSIG(status)) { +#ifdef WCOREDUMP + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, + "%s %P exited on signal %d%s", + process, pid, WTERMSIG(status), + WCOREDUMP(status) ? " (core dumped)" : ""); +#else + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, + "%s %P exited on signal %d", + process, pid, WTERMSIG(status)); +#endif + + } else { + ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0, + "%s %P exited with code %d", + process, pid, WEXITSTATUS(status)); + } + + if (WEXITSTATUS(status) == 2 && ngx_processes[i].respawn) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, + "%s %P exited with fatal code %d " + "and cannot be respawned", + process, pid, WEXITSTATUS(status)); + ngx_processes[i].respawn = 0; + } + + ngx_unlock_mutexes(pid); + } +} + + +static void +ngx_unlock_mutexes(ngx_pid_t pid) +{ + ngx_uint_t i; + ngx_shm_zone_t *shm_zone; + ngx_list_part_t *part; + ngx_slab_pool_t *sp; + + /* + * unlock the accept mutex if the abnormally exited process + * held it + */ + + if (ngx_accept_mutex_ptr) { + (void) ngx_shmtx_force_unlock(&ngx_accept_mutex, pid); + } + + /* + * unlock shared memory mutexes if held by the abnormally exited + * process + */ + + part = (ngx_list_part_t *) &ngx_cycle->shared_memory.part; + shm_zone = part->elts; + + for (i = 0; /* void */ ; i++) { + + if (i >= part->nelts) { + if (part->next == NULL) { + break; + } + part = part->next; + shm_zone = part->elts; + i = 0; + } + + sp = (ngx_slab_pool_t *) shm_zone[i].shm.addr; + + if (ngx_shmtx_force_unlock(&sp->mutex, pid)) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, + "shared memory zone \"%V\" was locked by %P", + &shm_zone[i].shm.name, pid); + } + } +} + + +void +ngx_debug_point(void) +{ + ngx_core_conf_t *ccf; + + ccf = (ngx_core_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx, + ngx_core_module); + + switch (ccf->debug_points) { + + case NGX_DEBUG_POINTS_STOP: + raise(SIGSTOP); + break; + + case NGX_DEBUG_POINTS_ABORT: + ngx_abort(); + } +} + + +ngx_int_t +ngx_os_signal_process(ngx_cycle_t *cycle, char *name, ngx_int_t pid) +{ + ngx_signal_t *sig; + + for (sig = signals; sig->signo != 0; sig++) { + if (ngx_strcmp(name, sig->name) == 0) { + if (kill(pid, sig->signo) != -1) { + return 0; + } + + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "kill(%P, %d) failed", pid, sig->signo); + } + } + + return 1; +} |