diff src/event/modules/ngx_select_module.c @ 484:ed5e10fb40fc NGINX_0_7_54

nginx 0.7.54 *) Feature: the ngx_http_image_filter_module. *) Feature: the "proxy_ignore_headers" and "fastcgi_ignore_headers" directives. *) Bugfix: a segmentation fault might occur in worker process, if an "open_file_cache_errors off" directive was used; the bug had appeared in 0.7.53. *) Bugfix: the "port_in_redirect off" directive did not work; the bug had appeared in 0.7.39. *) Bugfix: improve handling of "select" method errors. *) Bugfix: of "select() failed (10022: ...)" error in nginx/Windows. *) Bugfix: in error text descriptions in nginx/Windows; the bug had appeared in 0.7.53.
author Igor Sysoev <http://sysoev.ru>
date Fri, 01 May 2009 00:00:00 +0400
parents 12defd37f578
children 6484cbba0222
line wrap: on
line diff
--- a/src/event/modules/ngx_select_module.c
+++ b/src/event/modules/ngx_select_module.c
@@ -18,6 +18,7 @@ static ngx_int_t ngx_select_del_event(ng
     ngx_uint_t flags);
 static ngx_int_t ngx_select_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
     ngx_uint_t flags);
+static void ngx_select_repair_fd_sets(ngx_cycle_t *cycle);
 static char *ngx_select_init_conf(ngx_cycle_t *cycle, void *conf);
 
 
@@ -248,12 +249,12 @@ static ngx_int_t
 ngx_select_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
     ngx_uint_t flags)
 {
-    int                 ready, nready;
-    ngx_uint_t          i, found;
-    ngx_err_t           err;
-    ngx_event_t        *ev, **queue;
-    ngx_connection_t   *c;
-    struct timeval      tv, *tp;
+    int                ready, nready;
+    ngx_err_t          err;
+    ngx_uint_t         i, found;
+    ngx_event_t       *ev, **queue;
+    struct timeval     tv, *tp;
+    ngx_connection_t  *c;
 
 #if !(NGX_WIN32)
 
@@ -302,19 +303,23 @@ ngx_select_process_events(ngx_cycle_t *c
     work_read_fd_set = master_read_fd_set;
     work_write_fd_set = master_write_fd_set;
 
-#if 1
-    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
-                   /*
-                    * (void *) disables "dereferencing type-punned
-                    * pointer will break strict-aliasing rules
-                    */
-                   "select read fd_set: %08Xd",
-                   *(int *) (void *) &work_read_fd_set);
-#endif
-
 #if (NGX_WIN32)
 
-    ready = select(0, &work_read_fd_set, &work_write_fd_set, NULL, tp);
+    if (max_read || max_write) {
+        ready = select(0, &work_read_fd_set, &work_write_fd_set, NULL, tp);
+
+    } else {
+
+        /*
+         * Winsock select() requires that at least one descriptor set must be
+         * be non-null, and any non-null descriptor set must contain at least
+         * one handle to a socket.  Otherwise select() returns WSAEINVAL.
+         */
+
+        ngx_msleep(timer);
+
+        ready = 0;
+    }
 
 #else
 
@@ -339,6 +344,11 @@ ngx_select_process_events(ngx_cycle_t *c
 
     if (err) {
         ngx_log_error(NGX_LOG_ALERT, cycle->log, err, "select() failed");
+
+        if (err == WSAENOTSOCK) {
+            ngx_select_repair_fd_sets(cycle);
+        }
+
         return NGX_ERROR;
     }
 
@@ -361,6 +371,11 @@ ngx_select_process_events(ngx_cycle_t *c
         }
 
         ngx_log_error(level, cycle->log, err, "select() failed");
+
+        if (err == EBADF) {
+            ngx_select_repair_fd_sets(cycle);
+        }
+
         return NGX_ERROR;
     }
 
@@ -414,13 +429,101 @@ ngx_select_process_events(ngx_cycle_t *c
     ngx_mutex_unlock(ngx_posted_events_mutex);
 
     if (ready != nready) {
-        ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "select ready != events");
+        ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
+                      "select ready != events: %d:%d", ready, nready);
+
+        ngx_select_repair_fd_sets(cycle);
     }
 
     return NGX_OK;
 }
 
 
+static void
+ngx_select_repair_fd_sets(ngx_cycle_t *cycle)
+{
+    int           n;
+    socklen_t     len;
+    ngx_err_t     err;
+    ngx_socket_t  s;
+
+#if (NGX_WIN32)
+    u_int         i;
+
+    for (i = 0; i < master_read_fd_set.fd_count; i++) {
+
+        s = master_read_fd_set.fd_array[i];
+        len = sizeof(int);
+
+        if (getsockopt(s, SOL_SOCKET, SO_TYPE, (char *) &n, &len) == -1) {
+            err = ngx_socket_errno;
+
+            ngx_log_error(NGX_LOG_ALERT, cycle->log, err,
+                          "invalid descriptor #%d in read fd_set", s);
+
+            FD_CLR(s, &master_read_fd_set);
+        }
+    }
+
+    for (i = 0; i < master_write_fd_set.fd_count; i++) {
+
+        s = master_write_fd_set.fd_array[i];
+        len = sizeof(int);
+
+        if (getsockopt(s, SOL_SOCKET, SO_TYPE, (char *) &n, &len) == -1) {
+            err = ngx_socket_errno;
+
+            ngx_log_error(NGX_LOG_ALERT, cycle->log, err,
+                          "invalid descriptor #%d in write fd_set", s);
+
+            FD_CLR(s, &master_write_fd_set);
+        }
+    }
+
+#else
+
+    for (s = 0; s <= max_fd; s++) {
+
+        if (FD_ISSET(s, &master_read_fd_set) == 0) {
+            continue;
+        }
+
+        len = sizeof(int);
+
+        if (getsockopt(s, SOL_SOCKET, SO_TYPE, &n, &len) == -1) {
+            err = ngx_socket_errno;
+
+            ngx_log_error(NGX_LOG_ALERT, cycle->log, err,
+                          "invalid descriptor #%d in read fd_set", s);
+
+            FD_CLR(s, &master_read_fd_set);
+        }
+    }
+
+    for (s = 0; s <= max_fd; s++) {
+
+        if (FD_ISSET(s, &master_write_fd_set) == 0) {
+            continue;
+        }
+
+        len = sizeof(int);
+
+        if (getsockopt(s, SOL_SOCKET, SO_TYPE, &n, &len) == -1) {
+            err = ngx_socket_errno;
+
+            ngx_log_error(NGX_LOG_ALERT, cycle->log, err,
+                          "invalid descriptor #%d in write fd_set", s);
+
+            FD_CLR(s, &master_write_fd_set);
+        }
+    }
+
+    max_fd = -1;
+
+#endif
+}
+
+
 static char *
 ngx_select_init_conf(ngx_cycle_t *cycle, void *conf)
 {