# HG changeset patch # User Maxim Dounin # Date 1548355881 -10800 # Node ID 4089b3d2cb597e709cf1f125913295f0cb0f4bea # Parent f3ff79ae31d90436c11b48e3beb7f72fe6640918 Win32: added WSAPoll() support. WSAPoll() is only available with Windows Vista and newer (and only available during compilation if _WIN32_WINNT >= 0x0600). To make sure the code works with Windows XP, we do not redefine _WIN32_WINNT, but instead load WSAPoll() dynamically if it is not available during compilation. Also, sockets are not guaranteed to be small integers on Windows. So an index array is used instead of NGX_USE_FD_EVENT to map events to connections. diff --git a/auto/os/win32 b/auto/os/win32 --- a/auto/os/win32 +++ b/auto/os/win32 @@ -11,6 +11,7 @@ CORE_SRCS="$WIN32_SRCS $IOCP_SRCS" OS_CONFIG="$WIN32_CONFIG" NGX_ICONS="$NGX_WIN32_ICONS" SELECT_SRCS=$WIN32_SELECT_SRCS +POLL_SRCS=$WIN32_POLL_SRCS ngx_pic_opt= ngx_binext=".exe" diff --git a/auto/sources b/auto/sources --- a/auto/sources +++ b/auto/sources @@ -106,6 +106,7 @@ WIN32_SELECT_SRCS=src/event/modules/ngx_ POLL_MODULE=ngx_poll_module POLL_SRCS=src/event/modules/ngx_poll_module.c +WIN32_POLL_SRCS=src/event/modules/ngx_win32_poll_module.c KQUEUE_MODULE=ngx_kqueue_module KQUEUE_SRCS=src/event/modules/ngx_kqueue_module.c diff --git a/src/event/modules/ngx_poll_module.c b/src/event/modules/ngx_win32_poll_module.c copy from src/event/modules/ngx_poll_module.c copy to src/event/modules/ngx_win32_poll_module.c --- a/src/event/modules/ngx_poll_module.c +++ b/src/event/modules/ngx_win32_poll_module.c @@ -1,6 +1,7 @@ /* * Copyright (C) Igor Sysoev + * Copyright (C) Maxim Dounin * Copyright (C) Nginx, Inc. */ @@ -21,8 +22,9 @@ static ngx_int_t ngx_poll_process_events static char *ngx_poll_init_conf(ngx_cycle_t *cycle, void *conf); -static struct pollfd *event_list; -static ngx_uint_t nevents; +static struct pollfd *event_list; +static ngx_connection_t **event_index; +static ngx_uint_t nevents; static ngx_str_t poll_name = ngx_string("poll"); @@ -67,7 +69,8 @@ ngx_module_t ngx_poll_module = { static ngx_int_t ngx_poll_init(ngx_cycle_t *cycle, ngx_msec_t timer) { - struct pollfd *list; + struct pollfd *list; + ngx_connection_t **index; if (event_list == NULL) { nevents = 0; @@ -89,13 +92,27 @@ ngx_poll_init(ngx_cycle_t *cycle, ngx_ms } event_list = list; + + index = ngx_alloc(sizeof(ngx_connection_t *) * cycle->connection_n, + cycle->log); + if (index == NULL) { + return NGX_ERROR; + } + + if (event_index) { + ngx_memcpy(index, event_index, + sizeof(ngx_connection_t *) * nevents); + ngx_free(event_index); + } + + event_index = index; } ngx_io = ngx_os_io; ngx_event_actions = ngx_poll_module_ctx.actions; - ngx_event_flags = NGX_USE_LEVEL_EVENT|NGX_USE_FD_EVENT; + ngx_event_flags = NGX_USE_LEVEL_EVENT; return NGX_OK; } @@ -105,8 +122,10 @@ static void ngx_poll_done(ngx_cycle_t *cycle) { ngx_free(event_list); + ngx_free(event_index); event_list = NULL; + event_index = NULL; } @@ -143,10 +162,13 @@ ngx_poll_add_event(ngx_event_t *ev, ngx_ "poll add event: fd:%d ev:%i", c->fd, event); if (e == NULL || e->index == NGX_INVALID_INDEX) { + event_list[nevents].fd = c->fd; event_list[nevents].events = (short) event; event_list[nevents].revents = 0; + event_index[nevents] = c; + ev->index = nevents; nevents++; @@ -204,10 +226,11 @@ ngx_poll_del_event(ngx_event_t *ev, ngx_ "index: copy event %ui to %i", nevents, ev->index); event_list[ev->index] = event_list[nevents]; + event_index[ev->index] = event_index[nevents]; - c = ngx_cycle->files[event_list[nevents].fd]; + c = event_index[ev->index]; - if (c->fd == -1) { + if (c->fd == (ngx_socket_t) -1) { ngx_log_error(NGX_LOG_ALERT, ev->log, 0, "unexpected last event"); @@ -240,7 +263,7 @@ ngx_poll_process_events(ngx_cycle_t *cyc { int ready, revents; ngx_err_t err; - ngx_uint_t i, found, level; + ngx_uint_t i, found; ngx_event_t *ev; ngx_queue_t *queue; ngx_connection_t *c; @@ -259,7 +282,7 @@ ngx_poll_process_events(ngx_cycle_t *cyc ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "poll timer: %M", timer); - ready = poll(event_list, (u_int) nevents, (int) timer); + ready = WSAPoll(event_list, (u_int) nevents, (int) timer); err = (ready == -1) ? ngx_errno : 0; @@ -271,20 +294,7 @@ ngx_poll_process_events(ngx_cycle_t *cyc "poll ready %d of %ui", ready, nevents); if (err) { - if (err == NGX_EINTR) { - - if (ngx_event_timer_alarm) { - ngx_event_timer_alarm = 0; - return NGX_OK; - } - - level = NGX_LOG_INFO; - - } else { - level = NGX_LOG_ALERT; - } - - ngx_log_error(level, cycle->log, err, "poll() failed"); + ngx_log_error(NGX_LOG_ALERT, cycle->log, err, "WSAPoll() failed"); return NGX_ERROR; } @@ -294,7 +304,7 @@ ngx_poll_process_events(ngx_cycle_t *cyc } ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, - "poll() returned no events without timeout"); + "WSAPoll() returned no events without timeout"); return NGX_ERROR; } @@ -326,7 +336,7 @@ ngx_poll_process_events(ngx_cycle_t *cyc event_list[i].fd, event_list[i].events, revents); } - if (event_list[i].fd == -1) { + if (event_list[i].fd == (ngx_socket_t) -1) { /* * the disabled event, a workaround for our possible bug, * see the comment below @@ -334,9 +344,9 @@ ngx_poll_process_events(ngx_cycle_t *cyc continue; } - c = ngx_cycle->files[event_list[i].fd]; + c = event_index[i]; - if (c->fd == -1) { + if (c->fd == (ngx_socket_t) -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "unexpected event"); /* @@ -347,7 +357,7 @@ ngx_poll_process_events(ngx_cycle_t *cyc if (i == nevents - 1) { nevents--; } else { - event_list[i].fd = -1; + event_list[i].fd = (ngx_socket_t) -1; } continue; @@ -411,5 +421,15 @@ ngx_poll_init_conf(ngx_cycle_t *cycle, v return NGX_CONF_OK; } +#if (NGX_LOAD_WSAPOLL) + + if (!ngx_have_wsapoll) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, + "poll is not available on this platform"); + return NGX_CONF_ERROR; + } + +#endif + return NGX_CONF_OK; } diff --git a/src/os/win32/ngx_socket.h b/src/os/win32/ngx_socket.h --- a/src/os/win32/ngx_socket.h +++ b/src/os/win32/ngx_socket.h @@ -200,6 +200,49 @@ extern LPFN_CONNECTEX ngx_co extern LPFN_DISCONNECTEX ngx_disconnectex; +#if (NGX_HAVE_POLL && !defined POLLIN) + +/* + * WSAPoll() is only available if _WIN32_WINNT >= 0x0600. + * If it is not available during compilation, we try to + * load it dynamically at runtime. + */ + +#define NGX_LOAD_WSAPOLL 1 + +#define POLLRDNORM 0x0100 +#define POLLRDBAND 0x0200 +#define POLLIN (POLLRDNORM | POLLRDBAND) +#define POLLPRI 0x0400 + +#define POLLWRNORM 0x0010 +#define POLLOUT (POLLWRNORM) +#define POLLWRBAND 0x0020 + +#define POLLERR 0x0001 +#define POLLHUP 0x0002 +#define POLLNVAL 0x0004 + +typedef struct pollfd { + + SOCKET fd; + SHORT events; + SHORT revents; + +} WSAPOLLFD, *PWSAPOLLFD, FAR *LPWSAPOLLFD; + +typedef int (WSAAPI *ngx_wsapoll_pt)( + LPWSAPOLLFD fdArray, + ULONG fds, + INT timeout + ); + +extern ngx_wsapoll_pt WSAPoll; +extern ngx_uint_t ngx_have_wsapoll; + +#endif + + int ngx_tcp_push(ngx_socket_t s); #define ngx_tcp_push_n "tcp_push()" 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 @@ -58,6 +58,12 @@ static GUID cx_guid = WSAID_CONNECTEX; static GUID dx_guid = WSAID_DISCONNECTEX; +#if (NGX_LOAD_WSAPOLL) +ngx_wsapoll_pt WSAPoll; +ngx_uint_t ngx_have_wsapoll; +#endif + + ngx_int_t ngx_os_init(ngx_log_t *log) { @@ -223,6 +229,32 @@ ngx_os_init(ngx_log_t *log) ngx_close_socket_n " failed"); } +#if (NGX_LOAD_WSAPOLL) + { + HMODULE hmod; + + hmod = GetModuleHandle("ws2_32.dll"); + if (hmod == NULL) { + ngx_log_error(NGX_LOG_NOTICE, log, ngx_errno, + "GetModuleHandle(\"ws2_32.dll\") failed"); + goto nopoll; + } + + WSAPoll = (ngx_wsapoll_pt) GetProcAddress(hmod, "WSAPoll"); + if (WSAPoll == NULL) { + ngx_log_error(NGX_LOG_NOTICE, log, ngx_errno, + "GetProcAddress(\"WSAPoll\") failed"); + goto nopoll; + } + + ngx_have_wsapoll = 1; + + } + +nopoll: + +#endif + if (GetEnvironmentVariable("ngx_unique", ngx_unique, NGX_INT32_LEN + 1) != 0) {