nginx/src/os/unix/ngx_process.c

325 lines
8.4 KiB
C
Raw Normal View History

2003-11-20 00:26:41 +08:00
/*
* Copyright (C) Igor Sysoev
*/
2003-11-20 00:26:41 +08:00
#include <ngx_config.h>
#include <ngx_core.h>
2004-04-05 04:32:09 +08:00
#include <ngx_event.h>
2004-07-15 00:01:42 +08:00
#include <ngx_channel.h>
2003-11-20 00:26:41 +08:00
2004-03-05 00:34:23 +08:00
static void ngx_execute_proc(ngx_cycle_t *cycle, void *data);
2004-01-06 04:55:48 +08:00
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];
2003-11-20 00:26:41 +08:00
ngx_pid_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-06-15 15:55:11 +08:00
u_long on;
2004-01-06 04:55:48 +08:00
ngx_pid_t pid;
2004-06-15 15:55:11 +08:00
ngx_int_t s;
2003-11-20 00:26:41 +08:00
2004-07-14 01:59:12 +08:00
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_ERROR;
}
}
2004-06-15 15:55:11 +08:00
2004-06-23 13:54:27 +08:00
if (respawn != NGX_PROCESS_DETACHED) {
2003-11-20 00:26:41 +08:00
2004-06-23 13:54:27 +08:00
/* Solaris 9 still has no AF_LOCAL */
2004-01-06 04:55:48 +08:00
2004-06-23 13:54:27 +08:00
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_ERROR;
}
2004-06-19 00:22:16 +08:00
2004-07-15 00:01:42 +08:00
ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0,
"channel %d:%d",
ngx_processes[s].channel[0],
ngx_processes[s].channel[1]);
2004-06-23 13:54:27 +08:00
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_ERROR;
}
2004-06-19 00:22:16 +08:00
2004-06-23 13:54:27 +08:00
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_ERROR;
}
2004-06-15 15:55:11 +08:00
2004-06-23 13:54:27 +08:00
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_ERROR;
}
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_ERROR;
}
2004-06-23 23:18:17 +08:00
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_ERROR;
}
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_ERROR;
}
2004-06-23 13:54:27 +08:00
ngx_channel = ngx_processes[s].channel[1];
} else {
ngx_processes[s].channel[0] = -1;
ngx_processes[s].channel[1] = -1;
2004-06-15 15:55:11 +08:00
}
2004-06-19 00:22:16 +08:00
ngx_process_slot = s;
2004-06-15 15:55:11 +08:00
pid = fork();
2003-11-20 00:26:41 +08:00
switch (pid) {
2004-06-15 15:55:11 +08:00
2003-11-20 00:26:41 +08:00
case -1:
2004-06-15 15:55:11 +08:00
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
"fork() failed while spawning \"%s\"", name);
2004-06-23 13:54:27 +08:00
ngx_close_channel(ngx_processes[s].channel, cycle->log);
2003-11-20 00:26:41 +08:00
return NGX_ERROR;
case 0:
2004-02-04 00:43:54 +08:00
ngx_pid = ngx_getpid();
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
}
ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "start %s %P", name, pid);
2003-11-20 00:26:41 +08:00
2004-06-15 15:55:11 +08:00
ngx_processes[s].pid = pid;
ngx_processes[s].exited = 0;
2004-01-06 04:55:48 +08:00
if (respawn >= 0) {
2004-01-14 00:43:23 +08:00
return pid;
2004-01-06 04:55:48 +08:00
}
2004-06-15 15:55:11 +08:00
ngx_processes[s].proc = proc;
ngx_processes[s].data = data;
ngx_processes[s].name = name;
ngx_processes[s].exiting = 0;
2004-04-16 13:14:16 +08:00
switch (respawn) {
case NGX_PROCESS_RESPAWN:
2004-06-15 15:55:11 +08:00
ngx_processes[s].respawn = 1;
ngx_processes[s].just_respawn = 0;
ngx_processes[s].detached = 0;
2004-04-16 13:14:16 +08:00
break;
case NGX_PROCESS_JUST_RESPAWN:
2004-06-15 15:55:11 +08:00
ngx_processes[s].respawn = 1;
ngx_processes[s].just_respawn = 1;
ngx_processes[s].detached = 0;
2004-04-16 13:14:16 +08:00
break;
case NGX_PROCESS_DETACHED:
2004-06-15 15:55:11 +08:00
ngx_processes[s].respawn = 0;
ngx_processes[s].just_respawn = 0;
ngx_processes[s].detached = 1;
2004-04-16 13:14:16 +08:00
break;
}
2004-07-14 01:59:12 +08:00
if (s == ngx_last_process) {
ngx_last_process++;
}
2003-11-20 00:26:41 +08:00
2004-01-14 00:43:23 +08:00
return pid;
2003-11-20 00:26:41 +08:00
}
ngx_pid_t
ngx_execute(ngx_cycle_t *cycle, ngx_exec_ctx_t *ctx)
2004-01-06 04:55:48 +08:00
{
2004-03-05 00:34:23 +08:00
return ngx_spawn_process(cycle, ngx_execute_proc, ctx, ctx->name,
2004-01-14 05:33:59 +08:00
NGX_PROCESS_DETACHED);
2004-01-06 04:55:48 +08:00
}
static void
ngx_execute_proc(ngx_cycle_t *cycle, void *data)
2004-01-06 04:55:48 +08:00
{
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_process_get_status(void)
2004-01-06 04:55:48 +08:00
{
int status;
char *process;
ngx_pid_t pid;
ngx_err_t err;
2004-06-15 15:55:11 +08:00
ngx_int_t i;
ngx_uint_t one;
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;
}
#if (NGX_SOLARIS)
/*
* Solaris always calls the signal handler for each exited process
* despite waitpid() may be already called for this process
*/
if (err == NGX_ECHILD) {
ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, errno,
"waitpid() failed");
}
#endif
2003-11-20 00:26:41 +08:00
ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, errno,
"waitpid() failed");
2003-11-20 00:26:41 +08:00
return;
}
2004-04-05 04:32:09 +08:00
if (ngx_accept_mutex_ptr) {
/*
* unlock the accept mutex if the abnormally exited process
* held it
*/
ngx_atomic_cmp_set(ngx_accept_mutex_ptr, pid, 0);
}
2003-11-20 00:26:41 +08:00
one = 1;
2004-07-14 01:59:12 +08:00
process = "unknown 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;
2004-01-09 05:02:06 +08:00
ngx_processes[i].exited = 1;
2004-01-06 04:55:48 +08:00
process = ngx_processes[i].name;
break;
}
}
if (WTERMSIG(status)) {
ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
"%s %P exited on signal %d%s",
2004-01-06 04:55:48 +08:00
process, pid, WTERMSIG(status),
WCOREDUMP(status) ? " (core dumped)" : "");
} else {
ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0,
"%s %P exited with code %d",
2004-01-06 04:55:48 +08:00
process, pid, WEXITSTATUS(status));
}
2004-01-21 04:40:08 +08:00
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 could not respawn",
process, pid, WEXITSTATUS(status));
2004-01-21 04:40:08 +08:00
ngx_processes[i].respawn = 0;
}
2003-11-20 00:26:41 +08:00
}
}
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:
abort();
}
}