/* * Copyright (C) Igor Sysoev * Copyright (C) Nginx, Inc. */ #include #include 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_%P%Z", name, pid); ngx_sprintf(ngx_processes[s].quit_event, "ngx_%s_quit_%P%Z", name, pid); ngx_sprintf(ngx_processes[s].reopen_event, "ngx_%s_reopen_%P%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 %Xl", 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); ngx_processes[s].handle = NULL; } 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; }