[nginx] Win32: added WSAPoll() support.

Maxim Dounin mdounin at mdounin.ru
Thu Jan 24 20:16:20 UTC 2019


details:   https://hg.nginx.org/nginx/rev/4089b3d2cb59
branches:  
changeset: 7444:4089b3d2cb59
user:      Maxim Dounin <mdounin at mdounin.ru>
date:      Thu Jan 24 21:51:21 2019 +0300
description:
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.

diffstat:

 auto/os/win32                             |   1 +
 auto/sources                              |   1 +
 src/event/modules/ngx_win32_poll_module.c |  74 +++++++++++++++++++-----------
 src/os/win32/ngx_socket.h                 |  43 ++++++++++++++++++
 src/os/win32/ngx_win32_init.c             |  32 +++++++++++++
 5 files changed, 124 insertions(+), 27 deletions(-)

diffs (322 lines):

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)
     {


More information about the nginx-devel mailing list