wez             Thu Nov 27 13:01:13 2003 EDT

  Modified files:              
    /php-src/win32      select.c 
  Log:
  re-implement the win32 select code.
  The old code implicitly set any sockets into non-blocking mode,
  and since there is no way to probe a socket to determine its
  blocking status using the win32 API, this was a real pain in the ass.
  
  The New implementation will hand off any sockets to winsock and
  use the WaitForObject API in win32 to probe other types of handle.
  
  
  
Index: php-src/win32/select.c
diff -u php-src/win32/select.c:1.5 php-src/win32/select.c:1.6
--- php-src/win32/select.c:1.5  Mon Aug 11 20:58:52 2003
+++ php-src/win32/select.c      Thu Nov 27 13:01:12 2003
@@ -19,158 +19,153 @@
 #include "php.h"
 #include "php_network.h"
 
-/* $Id: select.c,v 1.5 2003/08/12 00:58:52 iliaa Exp $ */
+#ifdef PHP_WIN32
 
-/* Win32 select() will only work with sockets, so we roll our own implementation that 
will
- * get the OS file handle from regular fd's and sockets and then use 
WaitForMultipleObjects().
- * This implementation is not as feature-full as posix select, but it works for our 
purposes
- */
+/* $Id: select.c,v 1.6 2003/11/27 18:01:12 wez Exp $ */
+
+/* Win32 select() will only work with sockets, so we roll our own implementation here.
+ * - If you supply only sockets, this simply passes through to winsock select().
+ * - If you supply file handles, there is no way to distinguish between
+ *   ready for read/write or OOB, so any set in which the handle is found will
+ *   be marked as ready.
+ * - If you supply a mixture of handles and sockets, the system will interleave
+ *   calls between select() and WaitForMultipleObjects(). The time slicing may
+ *   cause this function call to take up to 100 ms longer than you specified.
+ * - Calling this with NULL sets as a portable way to sleep with sub-second
+ *   accuracy is not supported.
+ * */
 PHPAPI int php_select(php_socket_t max_fd, fd_set *rfds, fd_set *wfds, fd_set *efds, 
struct timeval *tv)
 {
-       HANDLE *handles;
-       DWORD waitret;
-       DWORD ms_total;
-       int f, s, fd_count = 0, sock_count = 0;
-       int retval;
-       php_socket_t i;
-       fd_set ard, awr, aex; /* active fd sets */
-
-       for (i = 0; i < max_fd; i++) {
-               if (FD_ISSET(i, rfds) || FD_ISSET(i, wfds) || FD_ISSET(i, efds)) {
-                       if (_get_osfhandle(i) == 0xffffffff) {
-                               /* it is a socket */
-                               sock_count++;
-                       } else {
-                               fd_count++;
-                       }
-               }
-       }
+       DWORD ms_total, limit, slice;
+       HANDLE handles[MAXIMUM_WAIT_OBJECTS];
+       int handle_slot_to_fd[MAXIMUM_WAIT_OBJECTS];
+       int n_handles = 0, i;
+       fd_set sock_read, sock_write, sock_except;
+       fd_set aread, awrite, aexcept;
+       int sock_max_fd = -1;
+       struct timeval tvslice;
+       int retcode;
 
-       if (fd_count + sock_count == 0) {
-               return 0;
+#define SAFE_FD_ISSET(fd, set) (set != NULL && FD_ISSET(fd, set))
+       
+       /* calculate how long we need to wait in milliseconds */
+       if (tv == NULL) {
+               ms_total = INFINITE;
+       } else {
+               ms_total = tv->tv_sec * 1000;
+               ms_total += tv->tv_usec / 1000;
        }
 
-       handles = (HANDLE*)safe_emalloc((fd_count + sock_count), sizeof(HANDLE), 0);
-
-       /* populate the events and handles arrays */
-       f = 0;
-       s = 0;
+       FD_ZERO(&sock_read);
+       FD_ZERO(&sock_write);
+       FD_ZERO(&sock_except);
+       
+       /* build an array of handles for non-sockets */
        for (i = 0; i < max_fd; i++) {
-               if (FD_ISSET(i, rfds) || FD_ISSET(i, wfds) || FD_ISSET(i, efds)) {
-                       long h = _get_osfhandle(i);
-                       if (h == 0xFFFFFFFF) {
-                               HANDLE evt;
-                               long evt_flags = 0;
-
-                               if (FD_ISSET(i, rfds)) {
-                                       evt_flags |= 
FD_READ|FD_CONNECT|FD_ACCEPT|FD_CLOSE;
+               if (SAFE_FD_ISSET(i, rfds) || SAFE_FD_ISSET(i, wfds) || 
SAFE_FD_ISSET(i, efds)) {
+                       handles[n_handles] = (HANDLE)_get_osfhandle(i);
+                       if ((DWORD)handles[n_handles] == 0xffffffff) {
+                               /* socket */
+                               if (SAFE_FD_ISSET(i, rfds)) {
+                                       FD_SET(i, &sock_read);
                                }
-                               if (FD_ISSET(i, wfds)) {
-                                       evt_flags |= FD_WRITE;
+                               if (SAFE_FD_ISSET(i, wfds)) {
+                                       FD_SET(i, &sock_write);
                                }
-                               if (FD_ISSET(i, efds)) {
-                                       evt_flags |= FD_OOB;
+                               if (SAFE_FD_ISSET(i, efds)) {
+                                       FD_SET(i, &sock_except);
+                               }
+                               if (i > sock_max_fd) {
+                                       sock_max_fd = i;
                                }
-
-                               evt = WSACreateEvent();
-                               WSAEventSelect(i, evt, evt_flags); 
-
-                               handles[fd_count + s] = evt;
-                               s++;
                        } else {
-                               handles[f++] = (HANDLE)h;
+                               handle_slot_to_fd[n_handles] = i;
+                               n_handles++;
                        }
                }
        }
 
-       /* calculate how long we need to wait in milliseconds */
-       if (tv == NULL) {
-               ms_total = INFINITE;
-       } else {
-               ms_total = tv->tv_sec * 1000;
-               ms_total += tv->tv_usec / 1000;
+       if (n_handles == 0) {
+               /* plain sockets only - let winsock handle the whole thing */
+               return select(max_fd, rfds, wfds, efds, tv);
        }
-
-       waitret = MsgWaitForMultipleObjects(fd_count + sock_count, handles, FALSE, 
ms_total, QS_ALLEVENTS);
-
-       if (waitret == WAIT_TIMEOUT) {
-               retval = 0;
-       } else if (waitret == 0xFFFFFFFF) {
-               retval = -1;
-       } else {
-
-               FD_ZERO(&ard);
-               FD_ZERO(&awr);
-               FD_ZERO(&aex);
-
-               f = 0;
-               retval = 0;
-               for (i = 0; i < max_fd; i++) {
-                       if (FD_ISSET(i, rfds) || FD_ISSET(i, wfds) || FD_ISSET(i, 
efds)) {
-                               if (f >= fd_count) {
-                                       /* socket event */
-                                       HANDLE evt = handles[f];
-
-                                       if (WAIT_OBJECT_0 == WaitForSingleObject(evt, 
0)) {
-                                               /* check for various signal states */
-                                               if (FD_ISSET(i, rfds)) {
-                                                       WSAEventSelect(i, evt, 
FD_READ|FD_CONNECT|FD_ACCEPT|FD_CLOSE);
-                                                       if (WAIT_OBJECT_0 == 
WaitForSingleObject(evt, 0)) {
-                                                               FD_SET(i, &ard);
-                                                       }
-                                               }
-                                               if (FD_ISSET(i, wfds)) {
-                                                       WSAEventSelect(i, evt, 
FD_WRITE);
-                                                       if (WAIT_OBJECT_0 == 
WaitForSingleObject(evt, 0)) {
-                                                               FD_SET(i, &awr);
-                                                       }
-                                               }
-                                               if (FD_ISSET(i, efds)) {
-                                                       WSAEventSelect(i, evt, FD_OOB);
-                                                       if (WAIT_OBJECT_0 == 
WaitForSingleObject(evt, 0)) {
-                                                               FD_SET(i, &aex);
-                                                       }
-                                               }
-                                               retval++;
-                                       }
-
-                                       WSACloseEvent(evt);
-
-                               } else {
-                                       if (WAIT_OBJECT_0 == 
WaitForSingleObject(handles[f], 0)) {
-                                               if (FD_ISSET(i, rfds)) {
-                                                       FD_SET(i, &ard);
+       
+       /* mixture of handles and sockets; lets multiplex between
+        * winsock and waiting on the handles */
+
+       FD_ZERO(&aread);
+       FD_ZERO(&awrite);
+       FD_ZERO(&aexcept);
+       
+       limit = GetTickCount() + ms_total;
+       do {
+               retcode = 0;
+       
+               if (sock_max_fd >= 0) {
+                       /* overwrite the zero'd sets here; the select call
+                        * will clear those that are not active */
+                       aread = sock_read;
+                       awrite = sock_write;
+                       aexcept = sock_except;
+
+                       tvslice.tv_sec = 0;
+                       tvslice.tv_usec = 100000;
+
+                       retcode = select(sock_max_fd+1, &aread, &awrite, &aexcept, 
&tvslice);
+               }
+               if (n_handles > 0) {
+                       /* check handles */
+                       DWORD wret;
+
+                       wret = MsgWaitForMultipleObjects(n_handles, handles, FALSE, 
retcode > 0 ? 0 : 100, QS_ALLEVENTS);
+
+                       if (wret == WAIT_TIMEOUT) {
+                               /* set retcode to 0; this is the default.
+                                * select() may have set it to something else,
+                                * in which case we leave it alone, so this branch
+                                * does nothing */
+                               ;
+                       } else if (wret == WAIT_FAILED) {
+                               if (retcode == 0) {
+                                       retcode = -1;
+                               }
+                       } else {
+                               if (retcode < 0) {
+                                       retcode = 0;
+                               }
+                               for (i = 0; i < n_handles; i++) {
+                                       if (WAIT_OBJECT_0 == 
WaitForSingleObject(handles[i], 0)) {
+                                               if 
(SAFE_FD_ISSET(handle_slot_to_fd[i], rfds)) {
+                                                       FD_SET(handle_slot_to_fd[i], 
&aread);
                                                }
-                                               if (FD_ISSET(i, wfds)) {
-                                                       FD_SET(i, &awr);
+                                               if 
(SAFE_FD_ISSET(handle_slot_to_fd[i], wfds)) {
+                                                       FD_SET(handle_slot_to_fd[i], 
&awrite);
                                                }
-                                               if (FD_ISSET(i, efds)) {
-                                                       FD_SET(i, &aex);
+                                               if 
(SAFE_FD_ISSET(handle_slot_to_fd[i], efds)) {
+                                                       FD_SET(handle_slot_to_fd[i], 
&aexcept);
                                                }
-                                               retval++;
+                                               retcode++;
                                        }
-
                                }
-                               f++;
                        }
                }
+       } while (retcode == 0 && (ms_total == INFINITE || GetTickCount() < limit));
 
-               if (rfds) {
-                       *rfds = ard;
-               }
-               if (wfds) {
-                       *wfds = awr;
-               }
-               if (efds) {
-                       *efds = aex;
-               }
+       if (rfds) {
+               *rfds = aread;
        }
-
-       efree(handles);
-
-       return retval;
+       if (wfds) {
+               *wfds = awrite;
+       }
+       if (efds) {
+               *efds = aexcept;
+       }       
+       
+       return retcode;
 }
 
+#endif
+
 /*
  * Local variables:
  * tab-width: 4

-- 
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to