diff options
author | Igor Sysoev <igor@sysoev.ru> | 2009-04-20 06:08:47 +0000 |
---|---|---|
committer | Igor Sysoev <igor@sysoev.ru> | 2009-04-20 06:08:47 +0000 |
commit | bd91999ea577266b0d899ea206cdaa8d19f486b2 (patch) | |
tree | 6936e209210662a34db4f9b9c63d03b95e7d9956 /src/os/win32/ngx_process_cycle.c | |
parent | b533e9825295a0855d78912dae9d8f1180df0900 (diff) | |
download | nginx-bd91999ea577266b0d899ea206cdaa8d19f486b2.tar.gz nginx-bd91999ea577266b0d899ea206cdaa8d19f486b2.zip |
Win32 master/workers model
Diffstat (limited to 'src/os/win32/ngx_process_cycle.c')
-rw-r--r-- | src/os/win32/ngx_process_cycle.c | 1133 |
1 files changed, 970 insertions, 163 deletions
diff --git a/src/os/win32/ngx_process_cycle.c b/src/os/win32/ngx_process_cycle.c index 6e7c28688..22d70c6fe 100644 --- a/src/os/win32/ngx_process_cycle.c +++ b/src/os/win32/ngx_process_cycle.c @@ -10,69 +10,237 @@ #include <nginx.h> -static ngx_thread_value_t __stdcall ngx_worker_thread_cycle(void *data); -static void ngx_process_tray(ngx_cycle_t *cycle); -static long __stdcall ngx_window_procedure(HWND window, u_int message, - u_int wparam, long lparam); +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_events(ngx_cycle_t *cycle); +static void 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); + + +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; -#if 0 -ngx_pid_t ngx_new_binary; -sig_atomic_t ngx_reap; -sig_atomic_t ngx_timer; +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]; -#endif + ngx_process_init(cycle); -ngx_uint_t ngx_process; -ngx_pid_t ngx_pid; -ngx_uint_t ngx_threaded; -ngx_uint_t ngx_inherited; + 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; + } -sig_atomic_t ngx_terminate; -sig_atomic_t ngx_quit; -ngx_uint_t ngx_exiting; + ngx_log_debug0(NGX_LOG_DEBUG_CORE, cycle->log, 0, "master started"); -#if 0 + ngx_console_init(cycle); -sig_atomic_t ngx_noaccept; -sig_atomic_t ngx_reconfigure; -sig_atomic_t ngx_reopen; -sig_atomic_t ngx_change_binary; + SetEnvironmentVariable("ngx_unique", ngx_unique); -#endif + 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_events(cycle) != NGX_OK) { + exit(2); + } -static HMENU ngx_menu; + 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); + } -void -ngx_master_process_cycle(ngx_cycle_t *cycle) -{ - ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, "master mode is not supported"); - 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); -void -ngx_single_process_cycle(ngx_cycle_t *cycle) -{ - ngx_int_t i; - ngx_err_t err; - ngx_tid_t tid; - ngx_core_conf_t *ccf; + ngx_start_worker_processes(cycle, NGX_PROCESS_RESPAWN); - ngx_init_temp_number(); + timer = 0; + timeout = INFINITE; - 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); + 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(0, 0); + + 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); + } + + 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); @@ -90,29 +258,288 @@ ngx_single_process_cycle(ngx_cycle_t *cycle) /* fatal */ exit(2); } +} - if (ngx_create_thread(&tid, ngx_worker_thread_cycle, NULL, cycle->log) - != 0) - { - /* 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; } - ngx_process_tray(cycle); + if (SetConsoleCtrlHandler(ngx_console_handler, 1) == 0) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "SetConsoleCtrlHandler() failed"); + } } -static ngx_thread_value_t __stdcall -ngx_worker_thread_cycle(void *data) +static int __stdcall +ngx_console_handler(u_long type) { - ngx_cycle_t *cycle; + char *msg; - cycle = (ngx_cycle_t *) ngx_cycle; + switch (type) { - while (!ngx_quit) { - ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "worker cycle"); + case CTRL_C_EVENT: + msg = "Ctrl-C pressed, exiting"; + break; - ngx_process_events_and_timers(cycle); + 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_events(ngx_cycle_t *cycle) +{ + ngx_sprintf((u_char *) ngx_stop_event_name, "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, "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, + "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, + "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 void +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) { + return; + } + } +} + + +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 t:%d r:%d j:%d", + n, + ngx_processes[n].pid, + ngx_processes[n].handle, + ngx_processes[n].exiting, + ngx_processes[n].just_respawn); + + if (old && ngx_processes[n].just_respawn) { + ngx_processes[n].just_respawn = 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, 0, + "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, + "can 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 t:%d r:%d j:%d", + n, + ngx_processes[n].pid, + ngx_processes[n].handle, + ngx_processes[n].exiting, + ngx_processes[n].just_respawn); + + if (ngx_processes[n].handle) { + return 1; + } } return 0; @@ -120,164 +547,544 @@ ngx_worker_thread_cycle(void *data) static void -ngx_process_tray(ngx_cycle_t *cycle) +ngx_master_process_exit(ngx_cycle_t *cycle) { - int rc; - MSG message; - HWND window; - HMENU menu; - HICON icon, tray; - WNDCLASS wc; - HINSTANCE instance; - - instance = GetModuleHandle(NULL); - - icon = LoadIcon(instance, "nginx"); - if (icon == NULL) { - ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, - "LoadIcon(\"nginx\") failed"); - /* fatal */ - exit(2); + 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); + } } - tray = LoadIcon(instance, "tray"); - if (icon == NULL) { - ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, - "LoadIcon(\"tray\") failed"); - /* fatal */ - exit(2); + 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; + 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; } - menu = LoadMenu(instance, "nginx"); - if (menu == NULL) { - ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, - "LoadMenu() failed"); - /* fatal */ - exit(2); + 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_menu = GetSubMenu(menu, 0); - if (ngx_menu == NULL) { - ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, - "GetSubMenu() failed"); - /* fatal */ - exit(2); + 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; + } - wc.style = CS_HREDRAW|CS_VREDRAW; - wc.lpfnWndProc = ngx_window_procedure; - wc.cbClsExtra = 0; - wc.cbWndExtra = 0; - wc.hInstance = instance; - wc.hIcon = icon; - wc.hCursor = NULL; - wc.hbrBackground = NULL; - wc.lpszMenuName = NULL; - wc.lpszClassName = "nginx"; - if (RegisterClass(&wc) == 0) { - ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, - "RegisterClass() failed"); - /* fatal */ - exit(2); + 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; } - window = CreateWindow("nginx", "nginx", WS_OVERLAPPEDWINDOW, - CW_USEDEFAULT, CW_USEDEFAULT, - CW_USEDEFAULT, CW_USEDEFAULT, - NULL, NULL, instance, NULL); + 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 (window == NULL) { - ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, - "CreateWindow() failed"); - /* fatal */ - exit(2); + + 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_system_tray_icon(window, NIM_ADD, tray, (u_char *) " nginx") - != NGX_OK) - { - ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, - "Shell_NotifyIcon(NIM_ADD) failed"); - /* fatal */ - exit(2); + for ( ;; ) { + ev = WaitForMultipleObjects(3, events, 0, INFINITE); + + err = ngx_errno; + ngx_time_update(0, 0); + + 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 ( ;; ) { - rc = GetMessage(&message, NULL, 0, 0); + ev = WaitForMultipleObjects(nev, events, 0, INFINITE); - if (rc == -1) { - ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, - "GetMessage() failed"); + err = ngx_errno; + ngx_time_update(0, 0); + + 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 (rc == 0) { - exit(0); + if (ev == WAIT_OBJECT_0 + 2) { + nev = 2; + continue; } - TranslateMessage(&message); - DispatchMessage(&message); + 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 long __stdcall -ngx_window_procedure(HWND window, u_int message, u_int wparam, long lparam) +static ngx_thread_value_t __stdcall +ngx_worker_thread(void *data) { - POINT mouse; + ngx_int_t n; + ngx_uint_t i; + ngx_cycle_t *cycle; + ngx_connection_t *c; - switch (message) { + cycle = (ngx_cycle_t *) ngx_cycle; - case NGX_WM_TRAY: - if (lparam == WM_RBUTTONDOWN) { - if (GetCursorPos(&mouse) == 0) { - ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_errno, - "GetCursorPos() failed"); - return 0; + ngx_init_temp_number(); + + 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; - if (SetForegroundWindow(window) == 0) { - ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_errno, - "SetForegroundWindow() failed"); - return 0; + 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 (TrackPopupMenu(ngx_menu, TPM_RIGHTBUTTON, - mouse.x, mouse.y, 0, window, NULL) - == 0) + if (ngx_event_timer_rbtree.root + == ngx_event_timer_rbtree.sentinel) { - ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_errno, - "TrackPopupMenu() failed"); - return 0; + break; } } - return 0; + ngx_log_debug0(NGX_LOG_DEBUG_CORE, cycle->log, 0, "worker cycle"); - case WM_COMMAND: - if (wparam == NGX_WM_ABOUT) { - ngx_message_box("nginx", MB_OK, 0, - NGINX_VER CRLF "(C) 2002-2009 Igor Sysoev"); + ngx_process_events_and_timers(cycle); + + if (ngx_terminate) { return 0; } - if (wparam == NGX_WM_EXIT) { - if (ngx_system_tray_icon(window, NIM_DELETE, NULL, NULL) - != NGX_OK) + 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, ngx_cycle->log, ngx_errno, - "Shell_NotifyIcon(NIM_DELETE) failed"); + ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, + "open socket #%d left in connection %ui", + c[i].fd, i); } } + } - PostQuitMessage(0); + ngx_destroy_pool(cycle->pool); - return 0; + exit(0); +} - default: - return DefWindowProc(window, message, wparam, lparam); + +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(0, 0); + + 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->pathes.elts; + for (i = 0; i < ngx_cycle->pathes.nelts; i++) { + + if (path[i]->manager) { + n = path[i]->manager(path[i]->data); + + next = (n <= next) ? n : next; + + ngx_time_update(0, 0); + } + } + + if (next == 0) { + next = 1; + } + + ev = WaitForSingleObject(ngx_cache_manager_event, (u_long) next * 1000); + + if (ev != WAIT_TIMEOUT) { + + ngx_time_update(0, 0); + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, + "cache manager WaitForSingleObject: %ul", ev); + } +} + + +void +ngx_single_process_cycle(ngx_cycle_t *cycle) +{ + ngx_int_t i; + ngx_tid_t tid; + + ngx_init_temp_number(); + + 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_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_signal_process(ngx_cycle_t *cycle, char *sig) +{ + size_t n; + HANDLE ev; + ngx_int_t rc, pid; + ngx_file_t file; + ngx_core_conf_t *ccf; + u_char buf[NGX_INT64_LEN + 2]; + char evn[NGX_PROCESS_SYNC_NAME]; + + ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "signal process started"); + + ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); + + file.name = ccf->pid; + file.log = cycle->log; + + file.fd = ngx_open_file(file.name.data, NGX_FILE_RDONLY, + NGX_FILE_OPEN, NGX_FILE_DEFAULT_ACCESS); + + if (file.fd == NGX_INVALID_FILE) { + ngx_log_error(NGX_LOG_ERR, cycle->log, ngx_errno, + ngx_open_file_n " \"%s\" failed", file.name.data); + return 1; + } + + rc = 1; + + n = ngx_read_file(&file, buf, NGX_INT64_LEN + 2, 0); + + if (n == NGX_ERROR) { + goto failed; + } + + while (n-- && (buf[n] == CR || buf[n] == LF)) { /* void */ } + + pid = ngx_atoi(buf, ++n); + + if (pid == NGX_ERROR) { + ngx_log_error(NGX_LOG_ERR, cycle->log, 0, + "invalid PID number \"%*s\" in \"%s\"", + n, buf, file.name.data); + goto failed; + } + + ngx_sprintf((u_char *) evn, "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); + goto failed; + } + + if (SetEvent(ev) == 0) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "SetEvent(\"%s\") failed", evn); + } else { + rc = 0; + } + + ngx_close_handle(ev); + +failed: + + if (ngx_close_file(file.fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + ngx_close_file_n " \"%s\" failed", file.name.data); + } + + 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); } } |