Mercurial > hg > nginx-quic
view src/os/win32/ngx_process.c @ 6956:9b5f31fdb850
HTTP/2: fixed stream finalization.
In order to finalize stream the error flag is set on fake connection and
either "write" or "read" event handler is called. The read events of fake
connections are always ready, but it's not the case with the write events.
When the ready flag isn't set, the error flag can be not checked in some
cases and as a result stream isn't finalized. Now the ready flag is
explicilty set on write events for proper finalization in all cases.
author | Valentin Bartenev <vbart@nginx.com> |
---|---|
date | Wed, 29 Mar 2017 20:16:23 +0300 |
parents | 7640d6c213e1 |
children |
line wrap: on
line source
/* * 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_%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; }