|  |  | 
|  | /* | 
|  | * 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, siginfo_t *siginfo, void *ucontext); | 
|  | } ngx_signal_t; | 
|  |  | 
|  |  | 
|  |  | 
|  | static void ngx_execute_proc(ngx_cycle_t *cycle, void *data); | 
|  | static void ngx_signal_handler(int signo, siginfo_t *siginfo, void *ucontext); | 
|  | 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", "", NULL }, | 
|  |  | 
|  | { SIGPIPE, "SIGPIPE, SIG_IGN", "", NULL }, | 
|  |  | 
|  | { 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_parent = ngx_pid; | 
|  | 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)); | 
|  |  | 
|  | if (sig->handler) { | 
|  | sa.sa_sigaction = sig->handler; | 
|  | sa.sa_flags = SA_SIGINFO; | 
|  |  | 
|  | } else { | 
|  | sa.sa_handler = SIG_IGN; | 
|  | } | 
|  |  | 
|  | 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; | 
|  | } | 
|  |  | 
|  |  | 
|  | static void | 
|  | ngx_signal_handler(int signo, siginfo_t *siginfo, void *ucontext) | 
|  | { | 
|  | 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 (ngx_getppid() == ngx_parent || ngx_new_binary > 0) { | 
|  |  | 
|  | /* | 
|  | * Ignore the signal in the new binary if its parent is | 
|  | * not changed, 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; | 
|  | /* fall through */ | 
|  | 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; | 
|  | } | 
|  |  | 
|  | if (siginfo && siginfo->si_pid) { | 
|  | ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0, | 
|  | "signal %d (%s) received from %P%s", | 
|  | signo, sig->signame, siginfo->si_pid, action); | 
|  |  | 
|  | } else { | 
|  | 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_pid_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; | 
|  | } |