|  |  | 
|  | /* | 
|  | * Copyright (C) Igor Sysoev | 
|  | * Copyright (C) Nginx, Inc. | 
|  | */ | 
|  |  | 
|  |  | 
|  | #include <ngx_config.h> | 
|  | #include <ngx_core.h> | 
|  | #include <ngx_event.h> | 
|  | #include <nginx.h> | 
|  |  | 
|  |  | 
|  | static void ngx_process_init(ngx_cycle_t *cycle); | 
|  | static void ngx_console_init(ngx_cycle_t *cycle); | 
|  | static int __stdcall ngx_console_handler(u_long type); | 
|  | static ngx_int_t ngx_create_signal_events(ngx_cycle_t *cycle); | 
|  | static ngx_int_t ngx_start_worker_processes(ngx_cycle_t *cycle, ngx_int_t type); | 
|  | static void ngx_reopen_worker_processes(ngx_cycle_t *cycle); | 
|  | static void ngx_quit_worker_processes(ngx_cycle_t *cycle, ngx_uint_t old); | 
|  | static void ngx_terminate_worker_processes(ngx_cycle_t *cycle); | 
|  | static ngx_uint_t ngx_reap_worker(ngx_cycle_t *cycle, HANDLE h); | 
|  | static void ngx_master_process_exit(ngx_cycle_t *cycle); | 
|  | static void ngx_worker_process_cycle(ngx_cycle_t *cycle, char *mevn); | 
|  | static void ngx_worker_process_exit(ngx_cycle_t *cycle); | 
|  | static ngx_thread_value_t __stdcall ngx_worker_thread(void *data); | 
|  | static ngx_thread_value_t __stdcall ngx_cache_manager_thread(void *data); | 
|  | static void ngx_cache_manager_process_handler(void); | 
|  | static ngx_thread_value_t __stdcall ngx_cache_loader_thread(void *data); | 
|  |  | 
|  |  | 
|  | ngx_uint_t     ngx_process; | 
|  | ngx_pid_t      ngx_pid; | 
|  | ngx_uint_t     ngx_threaded; | 
|  |  | 
|  | ngx_uint_t     ngx_inherited; | 
|  | ngx_pid_t      ngx_new_binary; | 
|  |  | 
|  | sig_atomic_t   ngx_terminate; | 
|  | sig_atomic_t   ngx_quit; | 
|  | sig_atomic_t   ngx_reopen; | 
|  | sig_atomic_t   ngx_reconfigure; | 
|  | ngx_uint_t     ngx_exiting; | 
|  |  | 
|  |  | 
|  | HANDLE         ngx_master_process_event; | 
|  | char           ngx_master_process_event_name[NGX_PROCESS_SYNC_NAME]; | 
|  |  | 
|  | static HANDLE  ngx_stop_event; | 
|  | static char    ngx_stop_event_name[NGX_PROCESS_SYNC_NAME]; | 
|  | static HANDLE  ngx_quit_event; | 
|  | static char    ngx_quit_event_name[NGX_PROCESS_SYNC_NAME]; | 
|  | static HANDLE  ngx_reopen_event; | 
|  | static char    ngx_reopen_event_name[NGX_PROCESS_SYNC_NAME]; | 
|  | static HANDLE  ngx_reload_event; | 
|  | static char    ngx_reload_event_name[NGX_PROCESS_SYNC_NAME]; | 
|  |  | 
|  | HANDLE         ngx_cache_manager_mutex; | 
|  | char           ngx_cache_manager_mutex_name[NGX_PROCESS_SYNC_NAME]; | 
|  | HANDLE         ngx_cache_manager_event; | 
|  |  | 
|  |  | 
|  | void | 
|  | ngx_master_process_cycle(ngx_cycle_t *cycle) | 
|  | { | 
|  | u_long      nev, ev, timeout; | 
|  | ngx_err_t   err; | 
|  | ngx_int_t   n; | 
|  | ngx_msec_t  timer; | 
|  | ngx_uint_t  live; | 
|  | HANDLE      events[MAXIMUM_WAIT_OBJECTS]; | 
|  |  | 
|  | ngx_process_init(cycle); | 
|  |  | 
|  | ngx_sprintf((u_char *) ngx_master_process_event_name, | 
|  | "ngx_master_%s%Z", ngx_unique); | 
|  |  | 
|  | if (ngx_process == NGX_PROCESS_WORKER) { | 
|  | ngx_worker_process_cycle(cycle, ngx_master_process_event_name); | 
|  | return; | 
|  | } | 
|  |  | 
|  | ngx_log_debug0(NGX_LOG_DEBUG_CORE, cycle->log, 0, "master started"); | 
|  |  | 
|  | ngx_console_init(cycle); | 
|  |  | 
|  | SetEnvironmentVariable("ngx_unique", ngx_unique); | 
|  |  | 
|  | ngx_master_process_event = CreateEvent(NULL, 1, 0, | 
|  | ngx_master_process_event_name); | 
|  | if (ngx_master_process_event == NULL) { | 
|  | ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, | 
|  | "CreateEvent(\"%s\") failed", | 
|  | ngx_master_process_event_name); | 
|  | exit(2); | 
|  | } | 
|  |  | 
|  | if (ngx_create_signal_events(cycle) != NGX_OK) { | 
|  | exit(2); | 
|  | } | 
|  |  | 
|  | ngx_sprintf((u_char *) ngx_cache_manager_mutex_name, | 
|  | "ngx_cache_manager_mutex_%s%Z", ngx_unique); | 
|  |  | 
|  | ngx_cache_manager_mutex = CreateMutex(NULL, 0, | 
|  | ngx_cache_manager_mutex_name); | 
|  | if (ngx_cache_manager_mutex == NULL) { | 
|  | ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, | 
|  | "CreateMutex(\"%s\") failed", ngx_cache_manager_mutex_name); | 
|  | exit(2); | 
|  | } | 
|  |  | 
|  |  | 
|  | events[0] = ngx_stop_event; | 
|  | events[1] = ngx_quit_event; | 
|  | events[2] = ngx_reopen_event; | 
|  | events[3] = ngx_reload_event; | 
|  |  | 
|  | ngx_close_listening_sockets(cycle); | 
|  |  | 
|  | if (ngx_start_worker_processes(cycle, NGX_PROCESS_RESPAWN) == 0) { | 
|  | exit(2); | 
|  | } | 
|  |  | 
|  | timer = 0; | 
|  | timeout = INFINITE; | 
|  |  | 
|  | for ( ;; ) { | 
|  |  | 
|  | nev = 4; | 
|  | for (n = 0; n < ngx_last_process; n++) { | 
|  | if (ngx_processes[n].handle) { | 
|  | events[nev++] = ngx_processes[n].handle; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (timer) { | 
|  | timeout = timer > ngx_current_msec ? timer - ngx_current_msec : 0; | 
|  | } | 
|  |  | 
|  | ev = WaitForMultipleObjects(nev, events, 0, timeout); | 
|  |  | 
|  | err = ngx_errno; | 
|  | ngx_time_update(); | 
|  |  | 
|  | ngx_log_debug1(NGX_LOG_DEBUG_CORE, cycle->log, 0, | 
|  | "master WaitForMultipleObjects: %ul", ev); | 
|  |  | 
|  | if (ev == WAIT_OBJECT_0) { | 
|  | ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting"); | 
|  |  | 
|  | if (ResetEvent(ngx_stop_event) == 0) { | 
|  | ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, | 
|  | "ResetEvent(\"%s\") failed", ngx_stop_event_name); | 
|  | } | 
|  |  | 
|  | if (timer == 0) { | 
|  | timer = ngx_current_msec + 5000; | 
|  | } | 
|  |  | 
|  | ngx_terminate = 1; | 
|  | ngx_quit_worker_processes(cycle, 0); | 
|  |  | 
|  | continue; | 
|  | } | 
|  |  | 
|  | if (ev == WAIT_OBJECT_0 + 1) { | 
|  | ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "shutting down"); | 
|  |  | 
|  | if (ResetEvent(ngx_quit_event) == 0) { | 
|  | ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, | 
|  | "ResetEvent(\"%s\") failed", ngx_quit_event_name); | 
|  | } | 
|  |  | 
|  | ngx_quit = 1; | 
|  | ngx_quit_worker_processes(cycle, 0); | 
|  |  | 
|  | continue; | 
|  | } | 
|  |  | 
|  | if (ev == WAIT_OBJECT_0 + 2) { | 
|  | ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reopening logs"); | 
|  |  | 
|  | if (ResetEvent(ngx_reopen_event) == 0) { | 
|  | ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, | 
|  | "ResetEvent(\"%s\") failed", | 
|  | ngx_reopen_event_name); | 
|  | } | 
|  |  | 
|  | ngx_reopen_files(cycle, -1); | 
|  | ngx_reopen_worker_processes(cycle); | 
|  |  | 
|  | continue; | 
|  | } | 
|  |  | 
|  | if (ev == WAIT_OBJECT_0 + 3) { | 
|  | ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "reconfiguring"); | 
|  |  | 
|  | if (ResetEvent(ngx_reload_event) == 0) { | 
|  | ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, | 
|  | "ResetEvent(\"%s\") failed", | 
|  | ngx_reload_event_name); | 
|  | } | 
|  |  | 
|  | cycle = ngx_init_cycle(cycle); | 
|  | if (cycle == NULL) { | 
|  | cycle = (ngx_cycle_t *) ngx_cycle; | 
|  | continue; | 
|  | } | 
|  |  | 
|  | ngx_cycle = cycle; | 
|  |  | 
|  | ngx_close_listening_sockets(cycle); | 
|  |  | 
|  | if (ngx_start_worker_processes(cycle, NGX_PROCESS_JUST_RESPAWN)) { | 
|  | ngx_quit_worker_processes(cycle, 1); | 
|  | } | 
|  |  | 
|  | continue; | 
|  | } | 
|  |  | 
|  | if (ev > WAIT_OBJECT_0 + 3 && ev < WAIT_OBJECT_0 + nev) { | 
|  |  | 
|  | ngx_log_debug0(NGX_LOG_DEBUG_CORE, cycle->log, 0, "reap worker"); | 
|  |  | 
|  | live = ngx_reap_worker(cycle, events[ev]); | 
|  |  | 
|  | if (!live && (ngx_terminate || ngx_quit)) { | 
|  | ngx_master_process_exit(cycle); | 
|  | } | 
|  |  | 
|  | continue; | 
|  | } | 
|  |  | 
|  | if (ev == WAIT_TIMEOUT) { | 
|  | ngx_terminate_worker_processes(cycle); | 
|  |  | 
|  | ngx_master_process_exit(cycle); | 
|  | } | 
|  |  | 
|  | if (ev == WAIT_FAILED) { | 
|  | ngx_log_error(NGX_LOG_ALERT, cycle->log, err, | 
|  | "WaitForMultipleObjects() failed"); | 
|  |  | 
|  | continue; | 
|  | } | 
|  |  | 
|  | ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, | 
|  | "WaitForMultipleObjects() returned unexpected value %ul", ev); | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | static void | 
|  | ngx_process_init(ngx_cycle_t *cycle) | 
|  | { | 
|  | ngx_err_t         err; | 
|  | ngx_core_conf_t  *ccf; | 
|  |  | 
|  | ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); | 
|  |  | 
|  | if (ngx_init_threads(ngx_threads_n, ccf->thread_stack_size, cycle) | 
|  | != NGX_OK) | 
|  | { | 
|  | /* fatal */ | 
|  | exit(2); | 
|  | } | 
|  |  | 
|  | err = ngx_thread_key_create(&ngx_core_tls_key); | 
|  | if (err != 0) { | 
|  | ngx_log_error(NGX_LOG_ALERT, cycle->log, err, | 
|  | ngx_thread_key_create_n " failed"); | 
|  | /* fatal */ | 
|  | exit(2); | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | static void | 
|  | ngx_console_init(ngx_cycle_t *cycle) | 
|  | { | 
|  | ngx_core_conf_t  *ccf; | 
|  |  | 
|  | ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); | 
|  |  | 
|  | if (ccf->daemon) { | 
|  | if (FreeConsole() == 0) { | 
|  | ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, | 
|  | "FreeConsole() failed"); | 
|  | } | 
|  |  | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (SetConsoleCtrlHandler(ngx_console_handler, 1) == 0) { | 
|  | ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, | 
|  | "SetConsoleCtrlHandler() failed"); | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | static int __stdcall | 
|  | ngx_console_handler(u_long type) | 
|  | { | 
|  | char  *msg; | 
|  |  | 
|  | switch (type) { | 
|  |  | 
|  | case CTRL_C_EVENT: | 
|  | msg = "Ctrl-C pressed, exiting"; | 
|  | break; | 
|  |  | 
|  | case CTRL_BREAK_EVENT: | 
|  | msg = "Ctrl-Break pressed, exiting"; | 
|  | break; | 
|  |  | 
|  | case CTRL_CLOSE_EVENT: | 
|  | msg = "console closing, exiting"; | 
|  | break; | 
|  |  | 
|  | case CTRL_LOGOFF_EVENT: | 
|  | msg = "user logs off, exiting"; | 
|  | break; | 
|  |  | 
|  | default: | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0, msg); | 
|  |  | 
|  | if (ngx_stop_event == NULL) { | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | if (SetEvent(ngx_stop_event) == 0) { | 
|  | ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, | 
|  | "SetEvent(\"%s\") failed", ngx_stop_event_name); | 
|  | } | 
|  |  | 
|  | return 1; | 
|  | } | 
|  |  | 
|  |  | 
|  | static ngx_int_t | 
|  | ngx_create_signal_events(ngx_cycle_t *cycle) | 
|  | { | 
|  | ngx_sprintf((u_char *) ngx_stop_event_name, | 
|  | "Global\\ngx_stop_%s%Z", ngx_unique); | 
|  |  | 
|  | ngx_stop_event = CreateEvent(NULL, 1, 0, ngx_stop_event_name); | 
|  | if (ngx_stop_event == NULL) { | 
|  | ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, | 
|  | "CreateEvent(\"%s\") failed", ngx_stop_event_name); | 
|  | return NGX_ERROR; | 
|  | } | 
|  |  | 
|  |  | 
|  | ngx_sprintf((u_char *) ngx_quit_event_name, | 
|  | "Global\\ngx_quit_%s%Z", ngx_unique); | 
|  |  | 
|  | ngx_quit_event = CreateEvent(NULL, 1, 0, ngx_quit_event_name); | 
|  | if (ngx_quit_event == NULL) { | 
|  | ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, | 
|  | "CreateEvent(\"%s\") failed", ngx_quit_event_name); | 
|  | return NGX_ERROR; | 
|  | } | 
|  |  | 
|  |  | 
|  | ngx_sprintf((u_char *) ngx_reopen_event_name, | 
|  | "Global\\ngx_reopen_%s%Z", ngx_unique); | 
|  |  | 
|  | ngx_reopen_event = CreateEvent(NULL, 1, 0, ngx_reopen_event_name); | 
|  | if (ngx_reopen_event == NULL) { | 
|  | ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, | 
|  | "CreateEvent(\"%s\") failed", ngx_reopen_event_name); | 
|  | return NGX_ERROR; | 
|  | } | 
|  |  | 
|  |  | 
|  | ngx_sprintf((u_char *) ngx_reload_event_name, | 
|  | "Global\\ngx_reload_%s%Z", ngx_unique); | 
|  |  | 
|  | ngx_reload_event = CreateEvent(NULL, 1, 0, ngx_reload_event_name); | 
|  | if (ngx_reload_event == NULL) { | 
|  | ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, | 
|  | "CreateEvent(\"%s\") failed", ngx_reload_event_name); | 
|  | return NGX_ERROR; | 
|  | } | 
|  |  | 
|  | return NGX_OK; | 
|  | } | 
|  |  | 
|  |  | 
|  | static ngx_int_t | 
|  | ngx_start_worker_processes(ngx_cycle_t *cycle, ngx_int_t type) | 
|  | { | 
|  | ngx_int_t         n; | 
|  | ngx_core_conf_t  *ccf; | 
|  |  | 
|  | ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "start worker processes"); | 
|  |  | 
|  | ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); | 
|  |  | 
|  | for (n = 0; n < ccf->worker_processes; n++) { | 
|  | if (ngx_spawn_process(cycle, "worker", type) == NGX_INVALID_PID) { | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | return n; | 
|  | } | 
|  |  | 
|  |  | 
|  | static void | 
|  | ngx_reopen_worker_processes(ngx_cycle_t *cycle) | 
|  | { | 
|  | ngx_int_t  n; | 
|  |  | 
|  | for (n = 0; n < ngx_last_process; n++) { | 
|  |  | 
|  | if (ngx_processes[n].handle == NULL) { | 
|  | continue; | 
|  | } | 
|  |  | 
|  | if (SetEvent(ngx_processes[n].reopen) == 0) { | 
|  | ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, | 
|  | "SetEvent(\"%s\") failed", | 
|  | ngx_processes[n].reopen_event); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | static void | 
|  | ngx_quit_worker_processes(ngx_cycle_t *cycle, ngx_uint_t old) | 
|  | { | 
|  | ngx_int_t  n; | 
|  |  | 
|  | for (n = 0; n < ngx_last_process; n++) { | 
|  |  | 
|  | ngx_log_debug5(NGX_LOG_DEBUG_CORE, cycle->log, 0, | 
|  | "process: %d %P %p e:%d j:%d", | 
|  | n, | 
|  | ngx_processes[n].pid, | 
|  | ngx_processes[n].handle, | 
|  | ngx_processes[n].exiting, | 
|  | ngx_processes[n].just_spawn); | 
|  |  | 
|  | if (old && ngx_processes[n].just_spawn) { | 
|  | ngx_processes[n].just_spawn = 0; | 
|  | continue; | 
|  | } | 
|  |  | 
|  | if (ngx_processes[n].handle == NULL) { | 
|  | continue; | 
|  | } | 
|  |  | 
|  | if (SetEvent(ngx_processes[n].quit) == 0) { | 
|  | ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, | 
|  | "SetEvent(\"%s\") failed", | 
|  | ngx_processes[n].quit_event); | 
|  | } | 
|  |  | 
|  | ngx_processes[n].exiting = 1; | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | static void | 
|  | ngx_terminate_worker_processes(ngx_cycle_t *cycle) | 
|  | { | 
|  | ngx_int_t  n; | 
|  |  | 
|  | for (n = 0; n < ngx_last_process; n++) { | 
|  |  | 
|  | if (ngx_processes[n].handle == NULL) { | 
|  | continue; | 
|  | } | 
|  |  | 
|  | if (TerminateProcess(ngx_processes[n].handle, 0) == 0) { | 
|  | ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, | 
|  | "TerminateProcess(\"%p\") failed", | 
|  | ngx_processes[n].handle); | 
|  | } | 
|  |  | 
|  | ngx_processes[n].exiting = 1; | 
|  |  | 
|  | ngx_close_handle(ngx_processes[n].reopen); | 
|  | ngx_close_handle(ngx_processes[n].quit); | 
|  | ngx_close_handle(ngx_processes[n].term); | 
|  | ngx_close_handle(ngx_processes[n].handle); | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | static ngx_uint_t | 
|  | ngx_reap_worker(ngx_cycle_t *cycle, HANDLE h) | 
|  | { | 
|  | u_long     code; | 
|  | ngx_int_t  n; | 
|  |  | 
|  | for (n = 0; n < ngx_last_process; n++) { | 
|  |  | 
|  | if (ngx_processes[n].handle != h) { | 
|  | continue; | 
|  | } | 
|  |  | 
|  | if (GetExitCodeProcess(h, &code) == 0) { | 
|  | ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, | 
|  | "GetExitCodeProcess(%P) failed", | 
|  | ngx_processes[n].pid); | 
|  | } | 
|  |  | 
|  | ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, | 
|  | "%s process %P exited with code %Xul", | 
|  | ngx_processes[n].name, ngx_processes[n].pid, code); | 
|  |  | 
|  | ngx_close_handle(ngx_processes[n].reopen); | 
|  | ngx_close_handle(ngx_processes[n].quit); | 
|  | ngx_close_handle(ngx_processes[n].term); | 
|  | ngx_close_handle(h); | 
|  |  | 
|  | ngx_processes[n].handle = NULL; | 
|  | ngx_processes[n].term = NULL; | 
|  | ngx_processes[n].quit = NULL; | 
|  | ngx_processes[n].reopen = NULL; | 
|  |  | 
|  | if (!ngx_processes[n].exiting && !ngx_terminate && !ngx_quit) { | 
|  |  | 
|  | if (ngx_spawn_process(cycle, ngx_processes[n].name, n) | 
|  | == NGX_INVALID_PID) | 
|  | { | 
|  | ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, | 
|  | "could not respawn %s", ngx_processes[n].name); | 
|  |  | 
|  | if (n == ngx_last_process - 1) { | 
|  | ngx_last_process--; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | goto found; | 
|  | } | 
|  |  | 
|  | ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "unknown process handle %p", h); | 
|  |  | 
|  | found: | 
|  |  | 
|  | for (n = 0; n < ngx_last_process; n++) { | 
|  |  | 
|  | ngx_log_debug5(NGX_LOG_DEBUG_CORE, cycle->log, 0, | 
|  | "process: %d %P %p e:%d j:%d", | 
|  | n, | 
|  | ngx_processes[n].pid, | 
|  | ngx_processes[n].handle, | 
|  | ngx_processes[n].exiting, | 
|  | ngx_processes[n].just_spawn); | 
|  |  | 
|  | if (ngx_processes[n].handle) { | 
|  | return 1; | 
|  | } | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  |  | 
|  | static void | 
|  | ngx_master_process_exit(ngx_cycle_t *cycle) | 
|  | { | 
|  | ngx_uint_t  i; | 
|  |  | 
|  | ngx_delete_pidfile(cycle); | 
|  |  | 
|  | ngx_close_handle(ngx_cache_manager_mutex); | 
|  | ngx_close_handle(ngx_stop_event); | 
|  | ngx_close_handle(ngx_quit_event); | 
|  | ngx_close_handle(ngx_reopen_event); | 
|  | ngx_close_handle(ngx_reload_event); | 
|  | ngx_close_handle(ngx_master_process_event); | 
|  |  | 
|  | ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exit"); | 
|  |  | 
|  | for (i = 0; ngx_modules[i]; i++) { | 
|  | if (ngx_modules[i]->exit_master) { | 
|  | ngx_modules[i]->exit_master(cycle); | 
|  | } | 
|  | } | 
|  |  | 
|  | ngx_destroy_pool(cycle->pool); | 
|  |  | 
|  | exit(0); | 
|  | } | 
|  |  | 
|  |  | 
|  | static void | 
|  | ngx_worker_process_cycle(ngx_cycle_t *cycle, char *mevn) | 
|  | { | 
|  | char        wtevn[NGX_PROCESS_SYNC_NAME]; | 
|  | char        wqevn[NGX_PROCESS_SYNC_NAME]; | 
|  | char        wroevn[NGX_PROCESS_SYNC_NAME]; | 
|  | HANDLE      mev, events[3]; | 
|  | u_long      nev, ev; | 
|  | ngx_err_t   err; | 
|  | ngx_tid_t   wtid, cmtid, cltid; | 
|  | ngx_log_t  *log; | 
|  |  | 
|  | log = cycle->log; | 
|  |  | 
|  | ngx_log_debug0(NGX_LOG_DEBUG_CORE, log, 0, "worker started"); | 
|  |  | 
|  | ngx_sprintf((u_char *) wtevn, "ngx_worker_term_%ul%Z", ngx_pid); | 
|  | events[0] = CreateEvent(NULL, 1, 0, wtevn); | 
|  | if (events[0] == NULL) { | 
|  | ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, | 
|  | "CreateEvent(\"%s\") failed", wtevn); | 
|  | goto failed; | 
|  | } | 
|  |  | 
|  | ngx_sprintf((u_char *) wqevn, "ngx_worker_quit_%ul%Z", ngx_pid); | 
|  | events[1] = CreateEvent(NULL, 1, 0, wqevn); | 
|  | if (events[1] == NULL) { | 
|  | ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, | 
|  | "CreateEvent(\"%s\") failed", wqevn); | 
|  | goto failed; | 
|  | } | 
|  |  | 
|  | ngx_sprintf((u_char *) wroevn, "ngx_worker_reopen_%ul%Z", ngx_pid); | 
|  | events[2] = CreateEvent(NULL, 1, 0, wroevn); | 
|  | if (events[2] == NULL) { | 
|  | ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, | 
|  | "CreateEvent(\"%s\") failed", wroevn); | 
|  | goto failed; | 
|  | } | 
|  |  | 
|  | mev = OpenEvent(EVENT_MODIFY_STATE, 0, mevn); | 
|  | if (mev == NULL) { | 
|  | ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, | 
|  | "OpenEvent(\"%s\") failed", mevn); | 
|  | goto failed; | 
|  | } | 
|  |  | 
|  | if (SetEvent(mev) == 0) { | 
|  | ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, | 
|  | "SetEvent(\"%s\") failed", mevn); | 
|  | goto failed; | 
|  | } | 
|  |  | 
|  |  | 
|  | ngx_sprintf((u_char *) ngx_cache_manager_mutex_name, | 
|  | "ngx_cache_manager_mutex_%s%Z", ngx_unique); | 
|  |  | 
|  | ngx_cache_manager_mutex = OpenMutex(SYNCHRONIZE, 0, | 
|  | ngx_cache_manager_mutex_name); | 
|  | if (ngx_cache_manager_mutex == NULL) { | 
|  | ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, | 
|  | "OpenMutex(\"%s\") failed", ngx_cache_manager_mutex_name); | 
|  | goto failed; | 
|  | } | 
|  |  | 
|  | ngx_cache_manager_event = CreateEvent(NULL, 1, 0, NULL); | 
|  | if (ngx_cache_manager_event == NULL) { | 
|  | ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, | 
|  | "CreateEvent(\"ngx_cache_manager_event\") failed"); | 
|  | goto failed; | 
|  | } | 
|  |  | 
|  |  | 
|  | if (ngx_create_thread(&wtid, ngx_worker_thread, NULL, log) != 0) { | 
|  | goto failed; | 
|  | } | 
|  |  | 
|  | if (ngx_create_thread(&cmtid, ngx_cache_manager_thread, NULL, log) != 0) { | 
|  | goto failed; | 
|  | } | 
|  |  | 
|  | if (ngx_create_thread(&cltid, ngx_cache_loader_thread, NULL, log) != 0) { | 
|  | goto failed; | 
|  | } | 
|  |  | 
|  | for ( ;; ) { | 
|  | ev = WaitForMultipleObjects(3, events, 0, INFINITE); | 
|  |  | 
|  | err = ngx_errno; | 
|  | ngx_time_update(); | 
|  |  | 
|  | ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0, | 
|  | "worker WaitForMultipleObjects: %ul", ev); | 
|  |  | 
|  | if (ev == WAIT_OBJECT_0) { | 
|  | ngx_terminate = 1; | 
|  | ngx_log_error(NGX_LOG_NOTICE, log, 0, "exiting"); | 
|  |  | 
|  | if (ResetEvent(events[0]) == 0) { | 
|  | ngx_log_error(NGX_LOG_ALERT, log, 0, | 
|  | "ResetEvent(\"%s\") failed", wtevn); | 
|  | } | 
|  |  | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (ev == WAIT_OBJECT_0 + 1) { | 
|  | ngx_quit = 1; | 
|  | ngx_log_error(NGX_LOG_NOTICE, log, 0, "gracefully shutting down"); | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (ev == WAIT_OBJECT_0 + 2) { | 
|  | ngx_reopen = 1; | 
|  | ngx_log_error(NGX_LOG_NOTICE, log, 0, "reopening logs"); | 
|  |  | 
|  | if (ResetEvent(events[2]) == 0) { | 
|  | ngx_log_error(NGX_LOG_ALERT, log, 0, | 
|  | "ResetEvent(\"%s\") failed", wroevn); | 
|  | } | 
|  |  | 
|  | continue; | 
|  | } | 
|  |  | 
|  | if (ev == WAIT_FAILED) { | 
|  | ngx_log_error(NGX_LOG_ALERT, log, err, | 
|  | "WaitForMultipleObjects() failed"); | 
|  |  | 
|  | goto failed; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* wait threads */ | 
|  |  | 
|  | if (SetEvent(ngx_cache_manager_event) == 0) { | 
|  | ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, | 
|  | "SetEvent(\"ngx_cache_manager_event\") failed"); | 
|  | } | 
|  |  | 
|  | events[1] = wtid; | 
|  | events[2] = cmtid; | 
|  |  | 
|  | nev = 3; | 
|  |  | 
|  | for ( ;; ) { | 
|  | ev = WaitForMultipleObjects(nev, events, 0, INFINITE); | 
|  |  | 
|  | err = ngx_errno; | 
|  | ngx_time_update(); | 
|  |  | 
|  | ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0, | 
|  | "worker exit WaitForMultipleObjects: %ul", ev); | 
|  |  | 
|  | if (ev == WAIT_OBJECT_0) { | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (ev == WAIT_OBJECT_0 + 1) { | 
|  | if (nev == 2) { | 
|  | break; | 
|  | } | 
|  |  | 
|  | events[1] = events[2]; | 
|  | nev = 2; | 
|  | continue; | 
|  | } | 
|  |  | 
|  | if (ev == WAIT_OBJECT_0 + 2) { | 
|  | nev = 2; | 
|  | continue; | 
|  | } | 
|  |  | 
|  | if (ev == WAIT_FAILED) { | 
|  | ngx_log_error(NGX_LOG_ALERT, log, err, | 
|  | "WaitForMultipleObjects() failed"); | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | ngx_close_handle(ngx_cache_manager_event); | 
|  | ngx_close_handle(events[0]); | 
|  | ngx_close_handle(events[1]); | 
|  | ngx_close_handle(events[2]); | 
|  | ngx_close_handle(mev); | 
|  |  | 
|  | ngx_worker_process_exit(cycle); | 
|  |  | 
|  | failed: | 
|  |  | 
|  | exit(2); | 
|  | } | 
|  |  | 
|  |  | 
|  | static ngx_thread_value_t __stdcall | 
|  | ngx_worker_thread(void *data) | 
|  | { | 
|  | ngx_int_t          n; | 
|  | ngx_uint_t         i; | 
|  | ngx_cycle_t       *cycle; | 
|  | ngx_connection_t  *c; | 
|  |  | 
|  | cycle = (ngx_cycle_t *) ngx_cycle; | 
|  |  | 
|  | for (n = 0; ngx_modules[n]; n++) { | 
|  | if (ngx_modules[n]->init_process) { | 
|  | if (ngx_modules[n]->init_process(cycle) == NGX_ERROR) { | 
|  | /* fatal */ | 
|  | exit(2); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | while (!ngx_quit) { | 
|  |  | 
|  | if (ngx_exiting) { | 
|  |  | 
|  | c = cycle->connections; | 
|  |  | 
|  | for (i = 0; i < cycle->connection_n; i++) { | 
|  |  | 
|  | /* THREAD: lock */ | 
|  |  | 
|  | if (c[i].fd != -1 && c[i].idle) { | 
|  | c[i].close = 1; | 
|  | c[i].read->handler(c[i].read); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (ngx_event_timer_rbtree.root | 
|  | == ngx_event_timer_rbtree.sentinel) | 
|  | { | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | ngx_log_debug0(NGX_LOG_DEBUG_CORE, cycle->log, 0, "worker cycle"); | 
|  |  | 
|  | ngx_process_events_and_timers(cycle); | 
|  |  | 
|  | if (ngx_terminate) { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | if (ngx_quit) { | 
|  | ngx_quit = 0; | 
|  |  | 
|  | if (!ngx_exiting) { | 
|  | ngx_close_listening_sockets(cycle); | 
|  | ngx_exiting = 1; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (ngx_reopen) { | 
|  | ngx_reopen = 0; | 
|  | ngx_reopen_files(cycle, -1); | 
|  | } | 
|  | } | 
|  |  | 
|  | ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting"); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  |  | 
|  | static void | 
|  | ngx_worker_process_exit(ngx_cycle_t *cycle) | 
|  | { | 
|  | ngx_uint_t         i; | 
|  | ngx_connection_t  *c; | 
|  |  | 
|  | ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exit"); | 
|  |  | 
|  | for (i = 0; ngx_modules[i]; i++) { | 
|  | if (ngx_modules[i]->exit_process) { | 
|  | ngx_modules[i]->exit_process(cycle); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (ngx_exiting) { | 
|  | c = cycle->connections; | 
|  | for (i = 0; i < cycle->connection_n; i++) { | 
|  | if (c[i].fd != -1 | 
|  | && c[i].read | 
|  | && !c[i].read->accept | 
|  | && !c[i].read->channel | 
|  | && !c[i].read->resolver) | 
|  | { | 
|  | ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, | 
|  | "open socket #%d left in connection %ui", | 
|  | c[i].fd, i); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | ngx_destroy_pool(cycle->pool); | 
|  |  | 
|  | exit(0); | 
|  | } | 
|  |  | 
|  |  | 
|  | static ngx_thread_value_t __stdcall | 
|  | ngx_cache_manager_thread(void *data) | 
|  | { | 
|  | u_long        ev; | 
|  | HANDLE        events[2]; | 
|  | ngx_err_t     err; | 
|  | ngx_cycle_t  *cycle; | 
|  |  | 
|  | cycle = (ngx_cycle_t *) ngx_cycle; | 
|  |  | 
|  | events[0] = ngx_cache_manager_event; | 
|  | events[1] = ngx_cache_manager_mutex; | 
|  |  | 
|  | for ( ;; ) { | 
|  | ev = WaitForMultipleObjects(2, events, 0, INFINITE); | 
|  |  | 
|  | err = ngx_errno; | 
|  | ngx_time_update(); | 
|  |  | 
|  | ngx_log_debug1(NGX_LOG_DEBUG_CORE, cycle->log, 0, | 
|  | "cache manager WaitForMultipleObjects: %ul", ev); | 
|  |  | 
|  | if (ev == WAIT_FAILED) { | 
|  | ngx_log_error(NGX_LOG_ALERT, cycle->log, err, | 
|  | "WaitForMultipleObjects() failed"); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * ev == WAIT_OBJECT_0 | 
|  | * ev == WAIT_OBJECT_0 + 1 | 
|  | * ev == WAIT_ABANDONED_0 + 1 | 
|  | */ | 
|  |  | 
|  | if (ngx_terminate || ngx_quit) { | 
|  | ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting"); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | break; | 
|  | } | 
|  |  | 
|  | for ( ;; ) { | 
|  |  | 
|  | if (ngx_terminate || ngx_quit) { | 
|  | ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "exiting"); | 
|  | break; | 
|  | } | 
|  |  | 
|  | ngx_cache_manager_process_handler(); | 
|  | } | 
|  |  | 
|  | if (ReleaseMutex(ngx_cache_manager_mutex) == 0) { | 
|  | ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, | 
|  | "ReleaseMutex() failed"); | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  |  | 
|  | static void | 
|  | ngx_cache_manager_process_handler(void) | 
|  | { | 
|  | u_long        ev; | 
|  | time_t        next, n; | 
|  | ngx_uint_t    i; | 
|  | ngx_path_t  **path; | 
|  |  | 
|  | next = 60 * 60; | 
|  |  | 
|  | path = ngx_cycle->paths.elts; | 
|  | for (i = 0; i < ngx_cycle->paths.nelts; i++) { | 
|  |  | 
|  | if (path[i]->manager) { | 
|  | n = path[i]->manager(path[i]->data); | 
|  |  | 
|  | next = (n <= next) ? n : next; | 
|  |  | 
|  | ngx_time_update(); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (next == 0) { | 
|  | next = 1; | 
|  | } | 
|  |  | 
|  | ev = WaitForSingleObject(ngx_cache_manager_event, (u_long) next * 1000); | 
|  |  | 
|  | if (ev != WAIT_TIMEOUT) { | 
|  |  | 
|  | ngx_time_update(); | 
|  |  | 
|  | ngx_log_debug1(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, | 
|  | "cache manager WaitForSingleObject: %ul", ev); | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | static ngx_thread_value_t __stdcall | 
|  | ngx_cache_loader_thread(void *data) | 
|  | { | 
|  | ngx_uint_t     i; | 
|  | ngx_path_t   **path; | 
|  | ngx_cycle_t   *cycle; | 
|  |  | 
|  | ngx_msleep(60000); | 
|  |  | 
|  | cycle = (ngx_cycle_t *) ngx_cycle; | 
|  |  | 
|  | path = cycle->paths.elts; | 
|  | for (i = 0; i < cycle->paths.nelts; i++) { | 
|  |  | 
|  | if (ngx_terminate || ngx_quit) { | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (path[i]->loader) { | 
|  | path[i]->loader(path[i]->data); | 
|  | ngx_time_update(); | 
|  | } | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  |  | 
|  | void | 
|  | ngx_single_process_cycle(ngx_cycle_t *cycle) | 
|  | { | 
|  | ngx_int_t  i; | 
|  | ngx_tid_t  tid; | 
|  |  | 
|  | for (i = 0; ngx_modules[i]; i++) { | 
|  | if (ngx_modules[i]->init_process) { | 
|  | if (ngx_modules[i]->init_process(cycle) == NGX_ERROR) { | 
|  | /* fatal */ | 
|  | exit(2); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | ngx_process_init(cycle); | 
|  |  | 
|  | ngx_console_init(cycle); | 
|  |  | 
|  | if (ngx_create_signal_events(cycle) != NGX_OK) { | 
|  | exit(2); | 
|  | } | 
|  |  | 
|  | if (ngx_create_thread(&tid, ngx_worker_thread, NULL, cycle->log) != 0) { | 
|  | /* fatal */ | 
|  | exit(2); | 
|  | } | 
|  |  | 
|  | /* STUB */ | 
|  | WaitForSingleObject(ngx_stop_event, INFINITE); | 
|  | } | 
|  |  | 
|  |  | 
|  | ngx_int_t | 
|  | ngx_os_signal_process(ngx_cycle_t *cycle, char *sig, ngx_int_t pid) | 
|  | { | 
|  | HANDLE     ev; | 
|  | ngx_int_t  rc; | 
|  | char       evn[NGX_PROCESS_SYNC_NAME]; | 
|  |  | 
|  | ngx_sprintf((u_char *) evn, "Global\\ngx_%s_%ul%Z", sig, pid); | 
|  |  | 
|  | ev = OpenEvent(EVENT_MODIFY_STATE, 0, evn); | 
|  | if (ev == NULL) { | 
|  | ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, | 
|  | "OpenEvent(\"%s\") failed", evn); | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | if (SetEvent(ev) == 0) { | 
|  | ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, | 
|  | "SetEvent(\"%s\") failed", evn); | 
|  | rc = 1; | 
|  |  | 
|  | } else { | 
|  | rc = 0; | 
|  | } | 
|  |  | 
|  | ngx_close_handle(ev); | 
|  |  | 
|  | return rc; | 
|  | } | 
|  |  | 
|  |  | 
|  | void | 
|  | ngx_close_handle(HANDLE h) | 
|  | { | 
|  | if (CloseHandle(h) == 0) { | 
|  | ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_errno, | 
|  | "CloseHandle(%p) failed", h); | 
|  | } | 
|  | } |