2003-11-20 00:26:41 +08:00
|
|
|
|
|
|
|
#include <ngx_config.h>
|
|
|
|
#include <ngx_core.h>
|
|
|
|
|
|
|
|
|
2004-01-06 04:55:48 +08:00
|
|
|
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];
|
2003-11-20 00:26:41 +08:00
|
|
|
|
2004-01-08 16:47:17 +08:00
|
|
|
sigset_t ngx_sigmask;
|
|
|
|
|
|
|
|
|
|
|
|
void ngx_wait_events()
|
|
|
|
{
|
|
|
|
sigsuspend(&ngx_sigmask);
|
|
|
|
}
|
|
|
|
|
2003-11-20 00:26:41 +08:00
|
|
|
|
2004-01-06 04:55:48 +08:00
|
|
|
ngx_int_t ngx_spawn_process(ngx_cycle_t *cycle,
|
|
|
|
ngx_spawn_proc_pt proc, void *data,
|
|
|
|
char *name, ngx_int_t respawn)
|
2003-11-20 00:26:41 +08:00
|
|
|
{
|
2004-01-06 04:55:48 +08:00
|
|
|
sigset_t set, oset;
|
|
|
|
ngx_pid_t pid;
|
2003-11-20 00:26:41 +08:00
|
|
|
|
2004-01-06 04:55:48 +08:00
|
|
|
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;
|
|
|
|
}
|
2003-11-20 00:26:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
pid = fork();
|
|
|
|
|
2004-01-06 04:55:48 +08:00
|
|
|
if (pid == -1) {
|
|
|
|
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
|
|
|
|
"fork() failed while spawning \"%s\"", name);
|
|
|
|
}
|
|
|
|
|
2003-11-20 00:26:41 +08:00
|
|
|
if (pid == -1 || pid == 0) {
|
|
|
|
if (sigprocmask(SIG_SETMASK, &oset, &set) == -1) {
|
2004-01-06 04:55:48 +08:00
|
|
|
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
|
|
|
|
"sigprocmask() failed while spawning %s", name);
|
|
|
|
return NGX_ERROR;
|
2003-11-20 00:26:41 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (pid) {
|
|
|
|
case -1:
|
|
|
|
return NGX_ERROR;
|
|
|
|
|
|
|
|
case 0:
|
2004-01-06 04:55:48 +08:00
|
|
|
proc(cycle, data);
|
2003-11-20 00:26:41 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2003-11-26 04:44:56 +08:00
|
|
|
break;
|
2003-11-20 00:26:41 +08:00
|
|
|
}
|
|
|
|
|
2004-01-06 04:55:48 +08:00
|
|
|
ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0,
|
|
|
|
"spawn %s: " PID_T_FMT, name, pid);
|
2003-11-20 00:26:41 +08:00
|
|
|
|
2004-01-06 04:55:48 +08:00
|
|
|
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++;
|
2003-11-20 00:26:41 +08:00
|
|
|
|
|
|
|
if (sigprocmask(SIG_SETMASK, &oset, &set) == -1) {
|
2004-01-06 04:55:48 +08:00
|
|
|
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
|
|
|
|
"sigprocmask() failed while spawning %s", name);
|
|
|
|
return NGX_ERROR;
|
2003-11-20 00:26:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return NGX_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-01-06 04:55:48 +08:00
|
|
|
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");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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;
|
2003-11-20 00:26:41 +08:00
|
|
|
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;
|
2004-01-06 04:55:48 +08:00
|
|
|
process = "";
|
2003-11-20 00:26:41 +08:00
|
|
|
|
2004-01-06 04:55:48 +08:00
|
|
|
for (i = 0; i < ngx_last_process; i++) {
|
|
|
|
if (ngx_processes[i].pid == pid) {
|
|
|
|
ngx_processes[i].status = status;
|
2003-11-20 00:26:41 +08:00
|
|
|
|
2004-01-06 04:55:48 +08:00
|
|
|
if (!ngx_processes[i].exiting) {
|
|
|
|
ngx_processes[i].exited = 1;
|
2003-11-20 00:26:41 +08:00
|
|
|
|
2004-01-06 04:55:48 +08:00
|
|
|
if (ngx_processes[i].respawn) {
|
|
|
|
ngx_respawn = 1;
|
|
|
|
}
|
|
|
|
}
|
2003-11-20 00:26:41 +08:00
|
|
|
|
2004-01-06 04:55:48 +08:00
|
|
|
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));
|
|
|
|
}
|
2003-11-20 00:26:41 +08:00
|
|
|
}
|
|
|
|
}
|