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