# HG changeset patch # User Igor Sysoev # Date 1240207727 0 # Node ID d43d73277c5c63263c3d251f4cb0fdbe0877c245 # Parent 9fd2f12fee0a40353a1a3b3871762f65789bef33 Win32 master/workers model diff --git a/auto/cc/bcc b/auto/cc/bcc --- a/auto/cc/bcc +++ b/auto/cc/bcc @@ -46,7 +46,7 @@ NGX_USE_PCH="-Hu -H=$NGX_OBJS/ngx_config # Win32 GUI mode application -LINK="\$(CC) -laa" +#LINK="\$(CC) -laa" # the resource file diff --git a/auto/cc/msvc b/auto/cc/msvc --- a/auto/cc/msvc +++ b/auto/cc/msvc @@ -86,11 +86,14 @@ LIBC="-MT" CFLAGS="$CFLAGS $LIBC" +CORE_LIBS="$CORE_LIBS kernel32.lib user32.lib" + # Win32 GUI mode application -CORE_LIBS="$CORE_LIBS kernel32.lib user32.lib" -CORE_LINK="$CORE_LINK -subsystem:windows -entry:mainCRTStartup" +#CORE_LINK="$CORE_LINK -subsystem:windows -entry:mainCRTStartup" # debug +# msvc8 under Wine issues +# Program database manager mismatch; please check your installation if [ $NGX_CC_NAME != msvc8 ]; then CFLAGS="$CFLAGS -Zi" CORE_LINK="$CORE_LINK -debug" diff --git a/auto/cc/owc b/auto/cc/owc --- a/auto/cc/owc +++ b/auto/cc/owc @@ -71,7 +71,7 @@ NGX_USE_PCH="-fh=$NGX_OBJS/ngx_config.pc # the link flags, built target is NT GUI mode application -CORE_LINK="$CORE_LINK -l=nt_win" +#CORE_LINK="$CORE_LINK -l=nt_win" # the resource file diff --git a/auto/sources b/auto/sources --- a/auto/sources +++ b/auto/sources @@ -215,8 +215,6 @@ WIN32_DEPS="$CORE_DEPS $EVENT_DEPS \ src/os/win32/ngx_socket.h \ src/os/win32/ngx_os.h \ src/os/win32/ngx_user.h \ - src/os/win32/ngx_gui.h \ - src/os/win32/ngx_gui_resources.h \ src/os/win32/ngx_process_cycle.h" WIN32_CONFIG=src/os/win32/ngx_win32_config.h @@ -233,14 +231,15 @@ WIN32_SRCS="$CORE_SRCS $EVENT_SRCS \ src/os/win32/ngx_wsarecv.c \ src/os/win32/ngx_wsarecv_chain.c \ src/os/win32/ngx_udp_wsarecv.c \ + src/os/win32/ngx_wsasend.c \ src/os/win32/ngx_wsasend_chain.c \ src/os/win32/ngx_win32_init.c \ src/os/win32/ngx_user.c \ - src/os/win32/ngx_gui.c \ + src/os/win32/ngx_event_log.c \ src/os/win32/ngx_process_cycle.c \ src/event/ngx_event_acceptex.c" -NGX_WIN32_ICONS="src/os/win32/nginx.ico src/os/win32/nginx_tray.ico" +NGX_WIN32_ICONS="src/os/win32/nginx.ico" NGX_WIN32_RC="src/os/win32/nginx.rc" diff --git a/misc/GNUmakefile b/misc/GNUmakefile --- a/misc/GNUmakefile +++ b/misc/GNUmakefile @@ -1,8 +1,13 @@ -VER= $(shell grep 'define NGINX_VERSION' src/core/nginx.h \ - | sed -e 's/^.*\"\(.*\)\"/\1/') -NGINX= nginx-$(VER) -TEMP= tmp +VER = $(shell grep 'define NGINX_VERSION' src/core/nginx.h \ + | sed -e 's/^.*\"\(.*\)\"/\1/') +NGINX = nginx-$(VER) +TEMP = tmp + +OBJS = objs.msvc8 +OPENSSL = openssl-0.9.8k +ZLIB = zlib-1.2.3 +PCRE = pcre-4.4 release: @@ -64,7 +69,45 @@ snapshot: tar -c -z -f $(NGINX).tar.gz --directory $(TEMP) $(NGINX) -icons: src/os/win32/nginx.ico src/os/win32/nginx_tray.ico +zip: + rm -rf $(TEMP) + rm -f $(NGINX).zip + + mkdir -p $(TEMP)/$(NGINX)/docs + mkdir -p $(TEMP)/$(NGINX)/logs + mkdir -p $(TEMP)/$(NGINX)/temp + + svn export -rHEAD conf $(TEMP)/$(NGINX)/conf/ + perl -pi -e 's/$$/\r/' $(TEMP)/$(NGINX)/conf/* + + svn export -rHEAD contrib $(TEMP)/$(NGINX)/contrib/ + svn export -rHEAD docs/html $(TEMP)/$(NGINX)/html/ + + $(MAKE) -f docs/GNUmakefile changes + + cp -p $(OBJS)/nginx.exe $(TEMP)/$(NGINX) + + cp -p docs/text/LICENSE $(TEMP)/$(NGINX)/docs/ + cp -p docs/text/README $(TEMP)/$(NGINX)/docs/ + mv $(TEMP)/$(NGINX)/CHANGES* $(TEMP)/$(NGINX)/docs/ + + cp -p $(OBJS)/lib/$(OPENSSL)/LICENSE \ + $(TEMP)/$(NGINX)/docs/OpenSSL.LICENSE + + cp -p $(OBJS)/lib/$(PCRE)/COPYING \ + $(TEMP)/$(NGINX)/docs/PCRE.COPYING + + perl -ne 'print if /^ \(C\) 1995-2004/ .. /^ jloup\@gzip.org/' \ + $(OBJS)/lib/$(ZLIB)/README \ + > $(TEMP)/$(NGINX)/docs/zlib.LICENSE + + touch -r $(OBJS)/lib/$(ZLIB)/README \ + $(TEMP)/$(NGINX)/docs/zlib.LICENSE + + cd $(TEMP) && zip -r ../$(NGINX).zip $(NGINX) + + +icons: src/os/win32/nginx.ico # 32x32 and 16x16 icons @@ -82,15 +125,3 @@ src/os/win32/nginx.ico: src/os/win32/ngi ppmtowinicon -output src/os/win32/nginx.ico -andpgms \ $(TEMP)/nginx32.ppm $(TEMP)/nginx32.pbm \ $(TEMP)/nginx16.ppm $(TEMP)/nginx16.pbm - -# tray icon - -src/os/win32/nginx_tray.ico: src/os/win32/nginx_tray.xpm - - test -d $(TEMP) || mkdir $(TEMP) - - xpmtoppm --alphaout=$(TEMP)/nginx_tray.pbm \ - src/os/win32/nginx_tray.xpm > $(TEMP)/nginx_tray.ppm - - ppmtowinicon -output src/os/win32/nginx_tray.ico -andpgms \ - $(TEMP)/nginx_tray.ppm $(TEMP)/nginx_tray.pbm diff --git a/src/core/nginx.c b/src/core/nginx.c --- a/src/core/nginx.c +++ b/src/core/nginx.c @@ -180,10 +180,14 @@ ngx_module_t ngx_core_module = { }; -ngx_uint_t ngx_max_module; +ngx_uint_t ngx_max_module; -static ngx_uint_t ngx_show_version; -static ngx_uint_t ngx_show_configure; +static ngx_uint_t ngx_show_version; +static ngx_uint_t ngx_show_configure; +#if (NGX_WIN32) +static char *ngx_signal; +#endif + static char **ngx_os_environ; @@ -303,22 +307,15 @@ main(int argc, char *const *argv) ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); - ngx_process = ccf->master ? NGX_PROCESS_MASTER : NGX_PROCESS_SINGLE; + if (ccf->master && ngx_process == NGX_PROCESS_SINGLE) { + ngx_process = NGX_PROCESS_MASTER; + } #if (NGX_WIN32) -#if 0 - - TODO: - - if (ccf->run_as_service) { - if (ngx_service(cycle->log) != NGX_OK) { - return 1; - } - - return 0; + if (ngx_signal) { + return ngx_signal_process(cycle, ngx_signal); } -#endif #else @@ -334,17 +331,17 @@ main(int argc, char *const *argv) ngx_daemonized = 1; } +#endif + if (ngx_create_pidfile(&ccf->pid, cycle->log) != NGX_OK) { return 1; } -#endif - - if (ngx_process == NGX_PROCESS_MASTER) { - ngx_master_process_cycle(cycle); + if (ngx_process == NGX_PROCESS_SINGLE) { + ngx_single_process_cycle(cycle); } else { - ngx_single_process_cycle(cycle); + ngx_master_process_cycle(cycle); } return 0; @@ -645,6 +642,29 @@ ngx_getopt(ngx_cycle_t *cycle, int argc, cycle->conf_param.len = ngx_strlen(cycle->conf_param.data); break; +#if (NGX_WIN32) + case 's': + if (argv[++i] == NULL) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, + "the option \"-s\" requires parameter"); + return NGX_ERROR; + } + + if (ngx_strcmp(argv[i], "stop") == 0 + || ngx_strcmp(argv[i], "quit") == 0 + || ngx_strcmp(argv[i], "reopen") == 0 + || ngx_strcmp(argv[i], "reload") == 0) + { + ngx_process = NGX_PROCESS_SIGNALLER; + ngx_signal = argv[i]; + break; + } + + ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, + "invalid option: \"-s %s\"", argv[i]); + return NGX_ERROR; +#endif + default: ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, "invalid option: \"%s\"", argv[i]); @@ -786,6 +806,27 @@ ngx_core_module_init_conf(ngx_cycle_t *c #endif + + if (ccf->pid.len == 0) { + ccf->pid.len = sizeof(NGX_PID_PATH) - 1; + ccf->pid.data = (u_char *) NGX_PID_PATH; + } + + if (ngx_conf_full_name(cycle, &ccf->pid, 0) != NGX_OK) { + return NGX_CONF_ERROR; + } + + ccf->oldpid.len = ccf->pid.len + sizeof(NGX_OLDPID_EXT); + + ccf->oldpid.data = ngx_pnalloc(cycle->pool, ccf->oldpid.len); + if (ccf->oldpid.data == NULL) { + return NGX_CONF_ERROR; + } + + ngx_memcpy(ngx_cpymem(ccf->oldpid.data, ccf->pid.data, ccf->pid.len), + NGX_OLDPID_EXT, sizeof(NGX_OLDPID_EXT)); + + #if !(NGX_WIN32) if (ccf->user == (uid_t) NGX_CONF_UNSET_UINT && geteuid() == 0) { @@ -814,25 +855,6 @@ ngx_core_module_init_conf(ngx_cycle_t *c ccf->group = grp->gr_gid; } - if (ccf->pid.len == 0) { - ccf->pid.len = sizeof(NGX_PID_PATH) - 1; - ccf->pid.data = (u_char *) NGX_PID_PATH; - } - - if (ngx_conf_full_name(cycle, &ccf->pid, 0) != NGX_OK) { - return NGX_CONF_ERROR; - } - - ccf->oldpid.len = ccf->pid.len + sizeof(NGX_OLDPID_EXT); - - ccf->oldpid.data = ngx_pnalloc(cycle->pool, ccf->oldpid.len); - if (ccf->oldpid.data == NULL) { - return NGX_CONF_ERROR; - } - - ngx_memcpy(ngx_cpymem(ccf->oldpid.data, ccf->pid.data, ccf->pid.len), - NGX_OLDPID_EXT, sizeof(NGX_OLDPID_EXT)); - if (ccf->lock_file.len == 0) { ccf->lock_file.len = sizeof(NGX_LOCK_PATH) - 1; diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c --- a/src/core/ngx_connection.c +++ b/src/core/ngx_connection.c @@ -557,29 +557,31 @@ ngx_close_listening_sockets(ngx_cycle_t c = ls[i].connection; - if (c->read->active) { - if (ngx_event_flags & NGX_USE_RTSIG_EVENT) { - ngx_del_conn(c, NGX_CLOSE_EVENT); + if (c) { + if (c->read->active) { + if (ngx_event_flags & NGX_USE_RTSIG_EVENT) { + ngx_del_conn(c, NGX_CLOSE_EVENT); - } else if (ngx_event_flags & NGX_USE_EPOLL_EVENT) { + } else if (ngx_event_flags & NGX_USE_EPOLL_EVENT) { - /* - * it seems that Linux-2.6.x OpenVZ sends events - * for closed shared listening sockets unless - * the events was explicity deleted - */ + /* + * it seems that Linux-2.6.x OpenVZ sends events + * for closed shared listening sockets unless + * the events was explicity deleted + */ - ngx_del_event(c->read, NGX_READ_EVENT, 0); + ngx_del_event(c->read, NGX_READ_EVENT, 0); - } else { - ngx_del_event(c->read, NGX_READ_EVENT, NGX_CLOSE_EVENT); + } else { + ngx_del_event(c->read, NGX_READ_EVENT, NGX_CLOSE_EVENT); + } } + + ngx_free_connection(c); + + c->fd = (ngx_socket_t) -1; } - ngx_free_connection(c); - - c->fd = (ngx_socket_t) -1; - ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0, "close listening %V #%d ", &ls[i].addr_text, ls[i].fd); diff --git a/src/core/ngx_cycle.c b/src/core/ngx_cycle.c --- a/src/core/ngx_cycle.c +++ b/src/core/ngx_cycle.c @@ -295,8 +295,6 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); -#if !(NGX_WIN32) - if (ngx_test_config) { if (ngx_create_pidfile(&ccf->pid, log) != NGX_OK) { @@ -325,8 +323,6 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) } } -#endif - if (ngx_test_lockfile(cycle->lock_file.data, log) != NGX_OK) { goto failed; @@ -928,8 +924,6 @@ ngx_init_zone_pool(ngx_cycle_t *cycle, n } -#if !(NGX_WIN32) - ngx_int_t ngx_create_pidfile(ngx_str_t *name, ngx_log_t *log) { @@ -938,6 +932,10 @@ ngx_create_pidfile(ngx_str_t *name, ngx_ ngx_file_t file; u_char pid[NGX_INT64_LEN + 2]; + if (ngx_process > NGX_PROCESS_MASTER) { + return NGX_OK; + } + ngx_memzero(&file, sizeof(ngx_file_t)); file.name = *name; @@ -987,8 +985,6 @@ ngx_delete_pidfile(ngx_cycle_t *cycle) } } -#endif - static ngx_int_t ngx_test_lockfile(u_char *file, ngx_log_t *log) diff --git a/src/core/ngx_log.c b/src/core/ngx_log.c --- a/src/core/ngx_log.c +++ b/src/core/ngx_log.c @@ -227,9 +227,9 @@ ngx_log_init(void) NGX_FILE_DEFAULT_ACCESS); if (ngx_stderr.fd == NGX_INVALID_FILE) { - ngx_message_box("nginx", MB_OK, ngx_errno, - "Could not open error log file: " - ngx_open_file_n " \"" NGX_ERROR_LOG_PATH "\" failed"); + ngx_event_log(ngx_errno, + "Could not open error log file: " + ngx_open_file_n " \"" NGX_ERROR_LOG_PATH "\" failed"); return NULL; } diff --git a/src/event/ngx_event.c b/src/event/ngx_event.c --- a/src/event/ngx_event.c +++ b/src/event/ngx_event.c @@ -442,7 +442,7 @@ ngx_event_module_init(ngx_cycle_t *cycle ecf = (*cf)[ngx_event_core_module.ctx_index]; - if (!ngx_test_config) { + if (!ngx_test_config && ngx_process <= NGX_PROCESS_MASTER) { ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "using the \"%s\" event method", ecf->name); } diff --git a/src/os/win32/nginx.rc b/src/os/win32/nginx.rc --- a/src/os/win32/nginx.rc +++ b/src/os/win32/nginx.rc @@ -1,16 +1,5 @@ // Copyright (C) Igor Sysoev -#include nginx icon discardable "src\\os\\win32\\nginx.ico" -tray icon discardable "src\\os\\win32\\nginx_tray.ico" - -nginx menu discardable -begin - popup "&nginx" - begin - menuitem "&Exit", NGX_WM_EXIT - menuitem "&About", NGX_WM_ABOUT - end -end diff --git a/src/os/win32/nginx_tray.ico b/src/os/win32/nginx_tray.ico deleted file mode 100644 index b39e5241c1297162d2a6eacd4ea2be64bca0f53a..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@ +#include + + +#define NGX_MAX_ERROR_STR 2048 + + +void ngx_cdecl +ngx_event_log(ngx_err_t err, const char *fmt, ...) +{ + u_char *p, *last; + long types; + HKEY key; + HANDLE ev; + va_list args; + u_char text[NGX_MAX_ERROR_STR]; + const char *msgarg[9]; + static u_char netmsg[] = "%SystemRoot%\\System32\\netmsg.dll"; + + p = text + GetModuleFileName(NULL, (char *) text, NGX_MAX_ERROR_STR - 50); + + *p++ = ':'; + ngx_linefeed(p); + + va_start(args, fmt); + p = ngx_vsnprintf(p, NGX_MAX_ERROR_STR, fmt, args); + va_end(args); + + last = text + NGX_MAX_ERROR_STR; + + if (err) { + + if (p > last - 50) { + + /* leave a space for an error code */ + + p = last - 50; + *p++ = '.'; + *p++ = '.'; + *p++ = '.'; + } + + p = ngx_snprintf(p, last - p, ((unsigned) err < 0x80000000) + ? " (%d: " : " (%Xd: ", err); + p = ngx_strerror_r(err, p, last - p); + + if (p < last) { + *p++ = ')'; + } + } + + if (p > last - NGX_LINEFEED_SIZE - 1) { + p = last - NGX_LINEFEED_SIZE - 1; + } + + ngx_linefeed(p); + + *p = '\0'; + + /* + * we do not log errors here since we use + * Event Log only to log our own logs open errors + */ + + if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, + "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\nginx", + 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &key, NULL) + != 0) + { + return; + } + + if (RegSetValueEx(key, "EventMessageFile", 0, REG_EXPAND_SZ, + netmsg, sizeof(netmsg) - 1) + != 0) + { + return; + } + + types = EVENTLOG_ERROR_TYPE; + + if (RegSetValueEx(key, "TypesSupported", 0, REG_DWORD, + (u_char *) &types, sizeof(long)) + != 0) + { + return; + } + + RegCloseKey(key); + + ev = RegisterEventSource(NULL, "nginx"); + + msgarg[0] = (char *) text; + msgarg[1] = NULL; + msgarg[2] = NULL; + msgarg[3] = NULL; + msgarg[4] = NULL; + msgarg[5] = NULL; + msgarg[6] = NULL; + msgarg[7] = NULL; + msgarg[8] = NULL; + + /* + * the 3299 event id in netmsg.dll has the generic message format: + * "%1 %2 %3 %4 %5 %6 %7 %8 %9" + */ + + ReportEvent(ev, EVENTLOG_ERROR_TYPE, 0, 3299, NULL, 9, 0, msgarg, NULL); + + DeregisterEventSource(ev); +} diff --git a/src/os/win32/ngx_gui.c b/src/os/win32/ngx_gui.c deleted file mode 100644 --- a/src/os/win32/ngx_gui.c +++ /dev/null @@ -1,81 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - */ - - -#include -#include - - -#define NGX_MAX_TEXT 2048 - - -void __cdecl -ngx_message_box(char *title, ngx_uint_t type, ngx_err_t err, - const char *fmt, ...) -{ - va_list args; - u_char text[NGX_MAX_TEXT], *p, *last; - - last = text + NGX_MAX_TEXT; - - va_start(args, fmt); - p = ngx_vsnprintf(text, NGX_MAX_TEXT, fmt, args); - va_end(args); - - if (err) { - - if (p > last - 50) { - - /* leave a space for an error code */ - - p = last - 50; - *p++ = '.'; - *p++ = '.'; - *p++ = '.'; - } - - p = ngx_snprintf(p, last - p, ((unsigned) err < 0x80000000) - ? " (%d: " : " (%Xd: ", err); - p = ngx_strerror_r(err, p, last - p); - - if (p < last) { - *p++ = ')'; - } - } - - if (p == last) { - p--; - } - - *p = '\0'; - - MessageBox(NULL, (char *) text, title, type); -} - - -ngx_int_t -ngx_system_tray_icon(HWND window, u_long action, HICON icon, u_char *tip) -{ - NOTIFYICONDATA ni; - - ni.cbSize = sizeof(NOTIFYICONDATA); - ni.hWnd = window; - ni.uID = 0; - ni.uFlags = NIF_MESSAGE|NIF_ICON|NIF_TIP; - ni.uCallbackMessage = NGX_WM_TRAY; - ni.hIcon = icon; - - if (tip) { - ngx_cpystrn((u_char *) ni.szTip, tip, 64); - } else { - ni.szTip[0] = '\0'; - } - - if (Shell_NotifyIcon(action, &ni) == 0) { - return NGX_ERROR; - } - - return NGX_OK; -} diff --git a/src/os/win32/ngx_gui.h b/src/os/win32/ngx_gui.h deleted file mode 100644 --- a/src/os/win32/ngx_gui.h +++ /dev/null @@ -1,23 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - */ - - -#ifndef _NGX_GUI_H_INCLUDED_ -#define _NGX_GUI_H_INCLUDED_ - - -#include -#include -#include - - -void ngx_cdecl ngx_message_box(char *title, ngx_uint_t type, ngx_err_t err, - const char *fmt, ...); - -ngx_int_t ngx_system_tray_icon(HWND window, u_long action, - HICON icon, u_char *tip); - - -#endif /* _NGX_GUI_H_INCLUDED_ */ diff --git a/src/os/win32/ngx_gui_resources.h b/src/os/win32/ngx_gui_resources.h deleted file mode 100644 --- a/src/os/win32/ngx_gui_resources.h +++ /dev/null @@ -1,19 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - */ - - -#ifndef _NGX_GUI_RESOURCES_H_INCLUDED_ -#define _NGX_GUI_RESOURCES_H_INCLUDED_ - - -#include - - -#define NGX_WM_TRAY WM_USER -#define NGX_WM_EXIT WM_USER + 1 -#define NGX_WM_ABOUT WM_USER + 2 - - -#endif /* _NGX_GUI_RESOURCES_H_INCLUDED_ */ diff --git a/src/os/win32/ngx_os.h b/src/os/win32/ngx_os.h --- a/src/os/win32/ngx_os.h +++ b/src/os/win32/ngx_os.h @@ -10,7 +10,6 @@ #include #include -#include #define NGX_IO_SENDFILE 1 @@ -40,11 +39,15 @@ ssize_t ngx_udp_wsarecv(ngx_connection_t ssize_t ngx_udp_overlapped_wsarecv(ngx_connection_t *c, u_char *buf, size_t size); ssize_t ngx_wsarecv_chain(ngx_connection_t *c, ngx_chain_t *chain); +ssize_t ngx_wsasend(ngx_connection_t *c, u_char *buf, size_t size); +ssize_t ngx_overlapped_wsasend(ngx_connection_t *c, u_char *buf, size_t size); ngx_chain_t *ngx_wsasend_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit); ngx_chain_t *ngx_overlapped_wsasend_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit); +void ngx_cdecl ngx_event_log(ngx_err_t err, const char *fmt, ...); + extern ngx_os_io_t ngx_os_io; extern ngx_uint_t ngx_ncpu; @@ -57,6 +60,4 @@ extern ngx_fd_t ngx_stderr_fileno; extern char ngx_unique[]; - #endif /* _NGX_OS_H_INCLUDED_ */ - diff --git a/src/os/win32/ngx_process.c b/src/os/win32/ngx_process.c --- a/src/os/win32/ngx_process.c +++ b/src/os/win32/ngx_process.c @@ -8,12 +8,212 @@ #include -int ngx_argc; -char **ngx_argv; -char **ngx_os_argv; +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_execute(ngx_cycle_t *cycle, ngx_exec_ctx_t *ctx) +ngx_pid_t +ngx_spawn_process(ngx_cycle_t *cycle, char *name, ngx_int_t respawn) { - return /* STUB */ 0; + u_long rc, n; + ngx_int_t s; + ngx_pid_t pid; + ngx_exec_ctx_t ctx; + 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.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); + + rc = WaitForSingleObject(ngx_master_process_event, 5000); + + ngx_time_update(0, 0); + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, cycle->log, 0, + "WaitForSingleObject: %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_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_respawn = 0; + break; + + case NGX_PROCESS_JUST_RESPAWN: + ngx_processes[s].just_respawn = 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, /* STUB */ NULL, + 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; +} diff --git a/src/os/win32/ngx_process.h b/src/os/win32/ngx_process.h --- a/src/os/win32/ngx_process.h +++ b/src/os/win32/ngx_process.h @@ -8,38 +8,71 @@ #define _NGX_PROCESS_H_INCLUDED_ -typedef DWORD ngx_pid_t; -#define NGX_INVALID_PID 0 +typedef DWORD ngx_pid_t; +#define NGX_INVALID_PID 0 -#define ngx_getpid GetCurrentProcessId -#define ngx_log_pid ngx_pid +#define ngx_getpid GetCurrentProcessId +#define ngx_log_pid ngx_pid + + +#define NGX_PROCESS_SYNC_NAME \ + (sizeof("ngx_cache_manager_mutex_") + NGX_INT32_LEN) typedef struct { - char *path; - char *name; - char *const *argv; - char *const *envp; + HANDLE handle; + ngx_pid_t pid; + char *name; + + HANDLE term; + HANDLE quit; + HANDLE reopen; + + u_char term_event[NGX_PROCESS_SYNC_NAME]; + u_char quit_event[NGX_PROCESS_SYNC_NAME]; + u_char reopen_event[NGX_PROCESS_SYNC_NAME]; + + unsigned just_respawn:1; + unsigned exiting:1; +} ngx_process_t; + + +typedef struct { + char *path; + char *name; + char *const *argv; + char *const *envp; + HANDLE child; } ngx_exec_ctx_t; -#define NGX_PROCESS_SINGLE 0 -#define NGX_PROCESS_MASTER 1 -#define NGX_PROCESS_WORKER 2 +#define NGX_PROCESS_SINGLE 0 +#define NGX_PROCESS_MASTER 1 +#define NGX_PROCESS_WORKER 2 +ngx_pid_t ngx_spawn_process(ngx_cycle_t *cycle, char *name, ngx_int_t respawn); ngx_pid_t ngx_execute(ngx_cycle_t *cycle, ngx_exec_ctx_t *ctx); #define ngx_debug_point() -#define ngx_sched_yield() Sleep(0) +#define ngx_sched_yield() Sleep(0) + + +#define NGX_MAX_PROCESSES (MAXIMUM_WAIT_OBJECTS - 4) + +#define NGX_PROCESS_RESPAWN -2 +#define NGX_PROCESS_JUST_RESPAWN -3 -extern int ngx_argc; -extern char **ngx_argv; -extern char **ngx_os_argv; +extern int ngx_argc; +extern char **ngx_argv; +extern char **ngx_os_argv; -extern ngx_pid_t ngx_pid; +extern ngx_int_t ngx_last_process; +extern ngx_process_t ngx_processes[NGX_MAX_PROCESSES]; + +extern ngx_pid_t ngx_pid; #endif /* _NGX_PROCESS_H_INCLUDED_ */ diff --git a/src/os/win32/ngx_process_cycle.c b/src/os/win32/ngx_process_cycle.c --- a/src/os/win32/ngx_process_cycle.c +++ b/src/os/win32/ngx_process_cycle.c @@ -10,70 +10,238 @@ #include -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); - -#if 0 -ngx_pid_t ngx_new_binary; - -sig_atomic_t ngx_reap; -sig_atomic_t ngx_timer; - -#endif - -ngx_uint_t ngx_process; -ngx_pid_t ngx_pid; -ngx_uint_t ngx_threaded; -ngx_uint_t ngx_inherited; +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); -sig_atomic_t ngx_terminate; -sig_atomic_t ngx_quit; -ngx_uint_t ngx_exiting; - -#if 0 +ngx_uint_t ngx_process; +ngx_pid_t ngx_pid; +ngx_uint_t ngx_threaded; -sig_atomic_t ngx_noaccept; -sig_atomic_t ngx_reconfigure; -sig_atomic_t ngx_reopen; -sig_atomic_t ngx_change_binary; +ngx_uint_t ngx_inherited; +ngx_pid_t ngx_new_binary; -#endif +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; -static HMENU ngx_menu; +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) { - ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, "master mode is not supported"); + 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_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); + + ngx_start_worker_processes(cycle, NGX_PROCESS_RESPAWN); + + 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(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"); - exit(2); + 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); + } } -void -ngx_single_process_cycle(ngx_cycle_t *cycle) +static void +ngx_process_init(ngx_cycle_t *cycle) { - ngx_int_t i; ngx_err_t err; - ngx_tid_t tid; ngx_core_conf_t *ccf; - 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); - } - } - } - 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) @@ -90,29 +258,288 @@ ngx_single_process_cycle(ngx_cycle_t *cy /* 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; + } + + 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); } - ngx_process_tray(cycle); + 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 ngx_thread_value_t __stdcall -ngx_worker_thread_cycle(void *data) +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_cycle_t *cycle; + 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; - cycle = (ngx_cycle_t *) ngx_cycle; + 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); - while (!ngx_quit) { - ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "worker cycle"); + 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--; + } + } + } - ngx_process_events_and_timers(cycle); + 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) +{ + 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) { - int rc; - MSG message; - HWND window; - HMENU menu; - HICON icon, tray; - WNDCLASS wc; - HINSTANCE instance; + 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; + } + + 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; + } + + for ( ;; ) { + ev = WaitForMultipleObjects(3, events, 0, INFINITE); + + err = ngx_errno; + ngx_time_update(0, 0); - instance = GetModuleHandle(NULL); + 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 */ - icon = LoadIcon(instance, "nginx"); - if (icon == NULL) { - ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, - "LoadIcon(\"nginx\") failed"); - /* fatal */ - exit(2); + 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(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 (ev == WAIT_OBJECT_0 + 2) { + nev = 2; + continue; + } + + if (ev == WAIT_FAILED) { + ngx_log_error(NGX_LOG_ALERT, log, err, + "WaitForMultipleObjects() failed"); + break; + } } - tray = LoadIcon(instance, "tray"); - if (icon == NULL) { - ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, - "LoadIcon(\"tray\") failed"); - /* fatal */ - exit(2); + 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; + + 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; + + 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); + } + } } - menu = LoadMenu(instance, "nginx"); - if (menu == NULL) { - ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, - "LoadMenu() failed"); - /* fatal */ + 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(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); } - ngx_menu = GetSubMenu(menu, 0); - if (ngx_menu == NULL) { - ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, - "GetSubMenu() failed"); - /* fatal */ - exit(2); - } - - - 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); - } - - window = CreateWindow("nginx", "nginx", WS_OVERLAPPEDWINDOW, - CW_USEDEFAULT, CW_USEDEFAULT, - CW_USEDEFAULT, CW_USEDEFAULT, - NULL, NULL, instance, NULL); - - if (window == NULL) { - ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, - "CreateWindow() failed"); + if (ngx_create_thread(&tid, ngx_worker_thread, NULL, cycle->log) != 0) { /* fatal */ exit(2); } - - 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 ( ;; ) { - rc = GetMessage(&message, NULL, 0, 0); - - if (rc == -1) { - ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, - "GetMessage() failed"); - continue; - } - - if (rc == 0) { - exit(0); - } - - TranslateMessage(&message); - DispatchMessage(&message); - } + /* STUB */ + WaitForSingleObject(ngx_stop_event, INFINITE); } -static long __stdcall -ngx_window_procedure(HWND window, u_int message, u_int wparam, long lparam) +ngx_int_t +ngx_signal_process(ngx_cycle_t *cycle, char *sig) { - POINT mouse; + 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]; - switch (message) { + 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; - 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; - } + 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; + } - if (SetForegroundWindow(window) == 0) { - ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_errno, - "SetForegroundWindow() failed"); - return 0; - } + 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 (TrackPopupMenu(ngx_menu, TPM_RIGHTBUTTON, - mouse.x, mouse.y, 0, window, NULL) - == 0) - { - ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_errno, - "TrackPopupMenu() failed"); - return 0; - } - } + 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; + } - return 0; + 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; + } - case WM_COMMAND: - if (wparam == NGX_WM_ABOUT) { - ngx_message_box("nginx", MB_OK, 0, - NGINX_VER CRLF "(C) 2002-2009 Igor Sysoev"); - return 0; - } + 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 (wparam == NGX_WM_EXIT) { - if (ngx_system_tray_icon(window, NIM_DELETE, NULL, NULL) - != NGX_OK) - { - ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_errno, - "Shell_NotifyIcon(NIM_DELETE) 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; +} - PostQuitMessage(0); - return 0; - - default: - return DefWindowProc(window, message, wparam, lparam); +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); } } diff --git a/src/os/win32/ngx_process_cycle.h b/src/os/win32/ngx_process_cycle.h --- a/src/os/win32/ngx_process_cycle.h +++ b/src/os/win32/ngx_process_cycle.h @@ -12,30 +12,33 @@ #include -#define NGX_PROCESS_SINGLE 0 -#define NGX_PROCESS_MASTER 1 -#define NGX_PROCESS_WORKER 2 +#define NGX_PROCESS_SINGLE 0 +#define NGX_PROCESS_MASTER 1 +#define NGX_PROCESS_WORKER 2 +#define NGX_PROCESS_SIGNALLER 3 void ngx_master_process_cycle(ngx_cycle_t *cycle); void ngx_single_process_cycle(ngx_cycle_t *cycle); +ngx_int_t ngx_signal_process(ngx_cycle_t *cycle, char *sig); +void ngx_close_handle(HANDLE h); extern ngx_uint_t ngx_process; extern ngx_pid_t ngx_pid; -extern ngx_pid_t ngx_new_binary; -extern ngx_uint_t ngx_inherited; extern ngx_uint_t ngx_threaded; extern ngx_uint_t ngx_exiting; -extern sig_atomic_t ngx_reap; -extern sig_atomic_t ngx_timer; extern sig_atomic_t ngx_quit; extern sig_atomic_t ngx_terminate; -extern sig_atomic_t ngx_noaccept; -extern sig_atomic_t ngx_reconfigure; extern sig_atomic_t ngx_reopen; -extern sig_atomic_t ngx_change_binary; + +extern ngx_uint_t ngx_inherited; +extern ngx_pid_t ngx_new_binary; + + +extern HANDLE ngx_master_process_event; +extern char ngx_master_process_event_name[]; #endif /* _NGX_PROCESS_CYCLE_H_INCLUDED_ */ diff --git a/src/os/win32/ngx_thread.c b/src/os/win32/ngx_thread.c --- a/src/os/win32/ngx_thread.c +++ b/src/os/win32/ngx_thread.c @@ -18,11 +18,14 @@ ngx_err_t ngx_create_thread(ngx_tid_t *tid, ngx_thread_value_t (__stdcall *func)(void *arg), void *arg, ngx_log_t *log) { + u_long id; ngx_err_t err; - *tid = CreateThread(NULL, stack_size, func, arg, 0, NULL); + *tid = CreateThread(NULL, stack_size, func, arg, 0, &id); if (*tid != NULL) { + ngx_log_error(NGX_LOG_NOTICE, log, 0, + "create thread " NGX_TID_T_FMT, id); return 0; } diff --git a/src/os/win32/ngx_win32_init.c b/src/os/win32/ngx_win32_init.c --- a/src/os/win32/ngx_win32_init.c +++ b/src/os/win32/ngx_win32_init.c @@ -24,7 +24,7 @@ ngx_os_io_t ngx_os_io = { ngx_wsarecv, ngx_wsarecv_chain, ngx_udp_wsarecv, - NULL, + ngx_wsasend, ngx_wsasend_chain, 0 }; @@ -56,7 +56,8 @@ static GUID cx_guid = WSAID_CONNECTEX; static GUID dx_guid = WSAID_DISCONNECTEX; -ngx_int_t ngx_os_init(ngx_log_t *log) +ngx_int_t +ngx_os_init(ngx_log_t *log) { DWORD bytes; SOCKET s; @@ -207,7 +208,7 @@ ngx_int_t ngx_os_init(ngx_log_t *log) ngx_close_socket_n " failed"); } - if (GetEnvironmentVariable("nginx_unique", ngx_unique, NGX_INT32_LEN + 1) + if (GetEnvironmentVariable("ngx_unique", ngx_unique, NGX_INT32_LEN + 1) != 0) { ngx_process = NGX_PROCESS_WORKER; @@ -217,7 +218,7 @@ ngx_int_t ngx_os_init(ngx_log_t *log) if (err != ERROR_ENVVAR_NOT_FOUND) { ngx_log_error(NGX_LOG_EMERG, log, err, - "GetEnvironmentVariable(\"nginx_unique\") failed"); + "GetEnvironmentVariable(\"ngx_unique\") failed"); return NGX_ERROR; } @@ -228,7 +229,8 @@ ngx_int_t ngx_os_init(ngx_log_t *log) } -void ngx_os_status(ngx_log_t *log) +void +ngx_os_status(ngx_log_t *log) { ngx_osviex_stub_t *osviex_stub; diff --git a/src/os/win32/ngx_wsasend.c b/src/os/win32/ngx_wsasend.c new file mode 100644 --- /dev/null +++ b/src/os/win32/ngx_wsasend.c @@ -0,0 +1,183 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include +#include + + +ssize_t +ngx_wsasend(ngx_connection_t *c, u_char *buf, size_t size) +{ + int n; + u_long sent; + ngx_err_t err; + ngx_event_t *wev; + WSABUF wsabuf; + + wev = c->write; + + if (!wev->ready) { + return NGX_AGAIN; + } + + /* + * WSABUF must be 4-byte aligned otherwise + * WSASend() will return undocumented WSAEINVAL error. + */ + + wsabuf.buf = (char *) buf; + wsabuf.len = size; + + sent = 0; + + n = WSASend(c->fd, &wsabuf, 1, &sent, 0, NULL, NULL); + + ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, + "WSASend: fd:%d, %d, %ul of %uz", c->fd, n, sent, size); + + if (n == 0) { + if (sent < size) { + wev->ready = 0; + } + + c->sent += sent; + + return sent; + } + + err = ngx_socket_errno; + + if (err == WSAEWOULDBLOCK) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, "WSASend() not ready"); + return NGX_AGAIN; + } + + wev->error = 1; + ngx_connection_error(c, err, "WSASend() failed"); + + return NGX_ERROR; +} + + +ssize_t +ngx_overlapped_wsasend(ngx_connection_t *c, u_char *buf, size_t size) +{ + int n; + u_long sent; + ngx_err_t err; + ngx_event_t *wev; + LPWSAOVERLAPPED ovlp; + WSABUF wsabuf; + + wev = c->write; + + if (!wev->ready) { + return NGX_AGAIN; + } + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "wev->complete: %d", wev->complete); + + if (!wev->complete) { + + /* post the overlapped WSASend() */ + + /* + * WSABUFs must be 4-byte aligned otherwise + * WSASend() will return undocumented WSAEINVAL error. + */ + + wsabuf.buf = (char *) buf; + wsabuf.len = size; + + sent = 0; + + ovlp = (LPWSAOVERLAPPED) &c->write->ovlp; + ngx_memzero(ovlp, sizeof(WSAOVERLAPPED)); + + n = WSASend(c->fd, &wsabuf, 1, &sent, 0, ovlp, NULL); + + ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0, + "WSASend: fd:%d, %d, %ul of %uz", c->fd, n, sent, size); + + wev->complete = 0; + + if (n == 0) { + if (ngx_event_flags & NGX_USE_IOCP_EVENT) { + + /* + * if a socket was bound with I/O completion port then + * GetQueuedCompletionStatus() would anyway return its status + * despite that WSASend() was already complete + */ + + wev->active = 1; + return NGX_AGAIN; + } + + if (sent < size) { + wev->ready = 0; + } + + c->sent += sent; + + return sent; + } + + err = ngx_socket_errno; + + if (err == WSA_IO_PENDING) { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, + "WSASend() posted"); + wev->active = 1; + return NGX_AGAIN; + } + + wev->error = 1; + ngx_connection_error(c, err, "WSASend() failed"); + + return NGX_ERROR; + } + + /* the overlapped WSASend() complete */ + + wev->complete = 0; + wev->active = 0; + + if (ngx_event_flags & NGX_USE_IOCP_EVENT) { + + if (wev->ovlp.error) { + ngx_connection_error(c, wev->ovlp.error, "WSASend() failed"); + return NGX_ERROR; + } + + sent = wev->available; + + } else { + if (WSAGetOverlappedResult(c->fd, (LPWSAOVERLAPPED) &wev->ovlp, + &sent, 0, NULL) + == 0) + { + ngx_connection_error(c, ngx_socket_errno, + "WSASend() or WSAGetOverlappedResult() failed"); + + return NGX_ERROR; + } + } + + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, + "WSAGetOverlappedResult: fd:%d, %ul of %uz", + c->fd, sent, size); + + if (sent < size) { + wev->ready = 0; + } + + c->sent += sent; + + return sent; +}