mirror of
https://github.com/nginx/nginx.git
synced 2025-01-22 20:33:07 +08:00
238 lines
6.2 KiB
C
238 lines
6.2 KiB
C
|
|
/*
|
|
* Copyright (C) Igor Sysoev
|
|
* Copyright (C) Nginx, Inc.
|
|
*/
|
|
|
|
|
|
#include <ngx_config.h>
|
|
#include <ngx_core.h>
|
|
|
|
|
|
int ngx_argc;
|
|
char **ngx_argv;
|
|
char **ngx_os_argv;
|
|
|
|
ngx_int_t ngx_last_process;
|
|
ngx_process_t ngx_processes[NGX_MAX_PROCESSES];
|
|
|
|
|
|
ngx_pid_t
|
|
ngx_spawn_process(ngx_cycle_t *cycle, char *name, ngx_int_t respawn)
|
|
{
|
|
u_long rc, n, code;
|
|
ngx_int_t s;
|
|
ngx_pid_t pid;
|
|
ngx_exec_ctx_t ctx;
|
|
HANDLE events[2];
|
|
char file[MAX_PATH + 1];
|
|
|
|
if (respawn >= 0) {
|
|
s = respawn;
|
|
|
|
} else {
|
|
for (s = 0; s < ngx_last_process; s++) {
|
|
if (ngx_processes[s].handle == NULL) {
|
|
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;
|
|
}
|
|
}
|
|
|
|
n = GetModuleFileName(NULL, file, MAX_PATH);
|
|
|
|
if (n == 0) {
|
|
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
|
|
"GetModuleFileName() failed");
|
|
return NGX_INVALID_PID;
|
|
}
|
|
|
|
file[n] = '\0';
|
|
|
|
ngx_log_debug1(NGX_LOG_DEBUG_CORE, cycle->log, 0,
|
|
"GetModuleFileName: \"%s\"", file);
|
|
|
|
ctx.path = file;
|
|
ctx.name = name;
|
|
ctx.args = GetCommandLine();
|
|
ctx.argv = NULL;
|
|
ctx.envp = NULL;
|
|
|
|
pid = ngx_execute(cycle, &ctx);
|
|
|
|
if (pid == NGX_INVALID_PID) {
|
|
return pid;
|
|
}
|
|
|
|
ngx_memzero(&ngx_processes[s], sizeof(ngx_process_t));
|
|
|
|
ngx_processes[s].handle = ctx.child;
|
|
ngx_processes[s].pid = pid;
|
|
ngx_processes[s].name = name;
|
|
|
|
ngx_sprintf(ngx_processes[s].term_event, "ngx_%s_term_%ul%Z", name, pid);
|
|
ngx_sprintf(ngx_processes[s].quit_event, "ngx_%s_quit_%ul%Z", name, pid);
|
|
ngx_sprintf(ngx_processes[s].reopen_event, "ngx_%s_reopen_%ul%Z",
|
|
name, pid);
|
|
|
|
events[0] = ngx_master_process_event;
|
|
events[1] = ctx.child;
|
|
|
|
rc = WaitForMultipleObjects(2, events, 0, 5000);
|
|
|
|
ngx_time_update();
|
|
|
|
ngx_log_debug1(NGX_LOG_DEBUG_CORE, cycle->log, 0,
|
|
"WaitForMultipleObjects: %ul", rc);
|
|
|
|
switch (rc) {
|
|
|
|
case WAIT_OBJECT_0:
|
|
|
|
ngx_processes[s].term = OpenEvent(EVENT_MODIFY_STATE, 0,
|
|
(char *) ngx_processes[s].term_event);
|
|
if (ngx_processes[s].term == NULL) {
|
|
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
|
|
"OpenEvent(\"%s\") failed",
|
|
ngx_processes[s].term_event);
|
|
goto failed;
|
|
}
|
|
|
|
ngx_processes[s].quit = OpenEvent(EVENT_MODIFY_STATE, 0,
|
|
(char *) ngx_processes[s].quit_event);
|
|
if (ngx_processes[s].quit == NULL) {
|
|
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
|
|
"OpenEvent(\"%s\") failed",
|
|
ngx_processes[s].quit_event);
|
|
goto failed;
|
|
}
|
|
|
|
ngx_processes[s].reopen = OpenEvent(EVENT_MODIFY_STATE, 0,
|
|
(char *) ngx_processes[s].reopen_event);
|
|
if (ngx_processes[s].reopen == NULL) {
|
|
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
|
|
"OpenEvent(\"%s\") failed",
|
|
ngx_processes[s].reopen_event);
|
|
goto failed;
|
|
}
|
|
|
|
if (ResetEvent(ngx_master_process_event) == 0) {
|
|
ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
|
|
"ResetEvent(\"%s\") failed",
|
|
ngx_master_process_event_name);
|
|
goto failed;
|
|
}
|
|
|
|
break;
|
|
|
|
case WAIT_OBJECT_0 + 1:
|
|
if (GetExitCodeProcess(ctx.child, &code) == 0) {
|
|
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
|
|
"GetExitCodeProcess(%P) failed", pid);
|
|
}
|
|
|
|
ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
|
|
"%s process %P exited with code %Xul",
|
|
name, pid, code);
|
|
|
|
goto failed;
|
|
|
|
case WAIT_TIMEOUT:
|
|
ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
|
|
"the event \"%s\" was not signaled for 5s",
|
|
ngx_master_process_event_name);
|
|
goto failed;
|
|
|
|
case WAIT_FAILED:
|
|
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
|
|
"WaitForSingleObject(\"%s\") failed",
|
|
ngx_master_process_event_name);
|
|
|
|
goto failed;
|
|
}
|
|
|
|
if (respawn >= 0) {
|
|
return pid;
|
|
}
|
|
|
|
switch (respawn) {
|
|
|
|
case NGX_PROCESS_RESPAWN:
|
|
ngx_processes[s].just_spawn = 0;
|
|
break;
|
|
|
|
case NGX_PROCESS_JUST_RESPAWN:
|
|
ngx_processes[s].just_spawn = 1;
|
|
break;
|
|
}
|
|
|
|
if (s == ngx_last_process) {
|
|
ngx_last_process++;
|
|
}
|
|
|
|
return pid;
|
|
|
|
failed:
|
|
|
|
if (ngx_processes[s].reopen) {
|
|
ngx_close_handle(ngx_processes[s].reopen);
|
|
}
|
|
|
|
if (ngx_processes[s].quit) {
|
|
ngx_close_handle(ngx_processes[s].quit);
|
|
}
|
|
|
|
if (ngx_processes[s].term) {
|
|
ngx_close_handle(ngx_processes[s].term);
|
|
}
|
|
|
|
TerminateProcess(ngx_processes[s].handle, 2);
|
|
|
|
if (ngx_processes[s].handle) {
|
|
ngx_close_handle(ngx_processes[s].handle);
|
|
}
|
|
|
|
return NGX_INVALID_PID;
|
|
}
|
|
|
|
|
|
ngx_pid_t
|
|
ngx_execute(ngx_cycle_t *cycle, ngx_exec_ctx_t *ctx)
|
|
{
|
|
STARTUPINFO si;
|
|
PROCESS_INFORMATION pi;
|
|
|
|
ngx_memzero(&si, sizeof(STARTUPINFO));
|
|
si.cb = sizeof(STARTUPINFO);
|
|
|
|
ngx_memzero(&pi, sizeof(PROCESS_INFORMATION));
|
|
|
|
if (CreateProcess(ctx->path, ctx->args,
|
|
NULL, NULL, 0, CREATE_NO_WINDOW, NULL, NULL, &si, &pi)
|
|
== 0)
|
|
{
|
|
ngx_log_error(NGX_LOG_CRIT, cycle->log, ngx_errno,
|
|
"CreateProcess(\"%s\") failed", ngx_argv[0]);
|
|
|
|
return 0;
|
|
}
|
|
|
|
ctx->child = pi.hProcess;
|
|
|
|
if (CloseHandle(pi.hThread) == 0) {
|
|
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
|
|
"CloseHandle(pi.hThread) failed");
|
|
}
|
|
|
|
ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0,
|
|
"start %s process %P", ctx->name, pi.dwProcessId);
|
|
|
|
return pi.dwProcessId;
|
|
}
|