root/win32/select.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. php_select

   1 /*
   2   +----------------------------------------------------------------------+
   3   | PHP Version 7                                                        |
   4   +----------------------------------------------------------------------+
   5   | Copyright (c) 1997-2016 The PHP Group                                |
   6   +----------------------------------------------------------------------+
   7   | This source file is subject to version 3.01 of the PHP license,      |
   8   | that is bundled with this package in the file LICENSE, and is        |
   9   | available through the world-wide-web at the following url:           |
  10   | http://www.php.net/license/3_01.txt                                  |
  11   | If you did not receive a copy of the PHP license and are unable to   |
  12   | obtain it through the world-wide-web, please send a note to          |
  13   | license@php.net so we can mail you a copy immediately.               |
  14   +----------------------------------------------------------------------+
  15   | Author: Wez Furlong <wez@thebrainroom.com>                           |
  16   +----------------------------------------------------------------------+
  17 */
  18 
  19 #include "php.h"
  20 #include "php_network.h"
  21 
  22 #ifdef PHP_WIN32
  23 
  24 /* $Id$ */
  25 
  26 /* Win32 select() will only work with sockets, so we roll our own implementation here.
  27  * - If you supply only sockets, this simply passes through to winsock select().
  28  * - If you supply file handles, there is no way to distinguish between
  29  *   ready for read/write or OOB, so any set in which the handle is found will
  30  *   be marked as ready.
  31  * - If you supply a mixture of handles and sockets, the system will interleave
  32  *   calls between select() and WaitForMultipleObjects(). The time slicing may
  33  *   cause this function call to take up to 100 ms longer than you specified.
  34  * - Calling this with NULL sets as a portable way to sleep with sub-second
  35  *   accuracy is not supported.
  36  * */
  37 PHPAPI int php_select(int max_fd, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *tv)
  38 {
  39         ULONGLONG ms_total, limit;
  40         HANDLE handles[MAXIMUM_WAIT_OBJECTS];
  41         int handle_slot_to_fd[MAXIMUM_WAIT_OBJECTS];
  42         int n_handles = 0, i;
  43         fd_set sock_read, sock_write, sock_except;
  44         fd_set aread, awrite, aexcept;
  45         int sock_max_fd = -1;
  46         struct timeval tvslice;
  47         int retcode;
  48 
  49 #define SAFE_FD_ISSET(fd, set)  (set != NULL && FD_ISSET(fd, set))
  50 
  51         /* calculate how long we need to wait in milliseconds */
  52         if (tv == NULL) {
  53                 ms_total = INFINITE;
  54         } else {
  55                 ms_total = tv->tv_sec * 1000;
  56                 ms_total += tv->tv_usec / 1000;
  57         }
  58 
  59         FD_ZERO(&sock_read);
  60         FD_ZERO(&sock_write);
  61         FD_ZERO(&sock_except);
  62 
  63         /* build an array of handles for non-sockets */
  64         for (i = 0; i < max_fd; i++) {
  65                 if (SAFE_FD_ISSET(i, rfds) || SAFE_FD_ISSET(i, wfds) || SAFE_FD_ISSET(i, efds)) {
  66                         handles[n_handles] = (HANDLE)(zend_uintptr_t)_get_osfhandle(i);
  67                         if (handles[n_handles] == INVALID_HANDLE_VALUE) {
  68                                 /* socket */
  69                                 if (SAFE_FD_ISSET(i, rfds)) {
  70                                         FD_SET((uint)i, &sock_read);
  71                                 }
  72                                 if (SAFE_FD_ISSET(i, wfds)) {
  73                                         FD_SET((uint)i, &sock_write);
  74                                 }
  75                                 if (SAFE_FD_ISSET(i, efds)) {
  76                                         FD_SET((uint)i, &sock_except);
  77                                 }
  78                                 if (i > sock_max_fd) {
  79                                         sock_max_fd = i;
  80                                 }
  81                         } else {
  82                                 handle_slot_to_fd[n_handles] = i;
  83                                 n_handles++;
  84                         }
  85                 }
  86         }
  87 
  88         if (n_handles == 0) {
  89                 /* plain sockets only - let winsock handle the whole thing */
  90                 return select(max_fd, rfds, wfds, efds, tv);
  91         }
  92 
  93         /* mixture of handles and sockets; lets multiplex between
  94          * winsock and waiting on the handles */
  95 
  96         FD_ZERO(&aread);
  97         FD_ZERO(&awrite);
  98         FD_ZERO(&aexcept);
  99 
 100         limit = GetTickCount64() + ms_total;
 101         do {
 102                 retcode = 0;
 103 
 104                 if (sock_max_fd >= 0) {
 105                         /* overwrite the zero'd sets here; the select call
 106                          * will clear those that are not active */
 107                         aread = sock_read;
 108                         awrite = sock_write;
 109                         aexcept = sock_except;
 110 
 111                         tvslice.tv_sec = 0;
 112                         tvslice.tv_usec = 100000;
 113 
 114                         retcode = select(sock_max_fd+1, &aread, &awrite, &aexcept, &tvslice);
 115                 }
 116                 if (n_handles > 0) {
 117                         /* check handles */
 118                         DWORD wret;
 119 
 120                         wret = MsgWaitForMultipleObjects(n_handles, handles, FALSE, retcode > 0 ? 0 : 100, QS_ALLEVENTS);
 121 
 122                         if (wret == WAIT_TIMEOUT) {
 123                                 /* set retcode to 0; this is the default.
 124                                  * select() may have set it to something else,
 125                                  * in which case we leave it alone, so this branch
 126                                  * does nothing */
 127                                 ;
 128                         } else if (wret == WAIT_FAILED) {
 129                                 if (retcode == 0) {
 130                                         retcode = -1;
 131                                 }
 132                         } else {
 133                                 if (retcode < 0) {
 134                                         retcode = 0;
 135                                 }
 136                                 for (i = 0; i < n_handles; i++) {
 137                                         if (WAIT_OBJECT_0 == WaitForSingleObject(handles[i], 0)) {
 138                                                 if (SAFE_FD_ISSET(handle_slot_to_fd[i], rfds)) {
 139                                                         FD_SET((uint)handle_slot_to_fd[i], &aread);
 140                                                 }
 141                                                 if (SAFE_FD_ISSET(handle_slot_to_fd[i], wfds)) {
 142                                                         FD_SET((uint)handle_slot_to_fd[i], &awrite);
 143                                                 }
 144                                                 if (SAFE_FD_ISSET(handle_slot_to_fd[i], efds)) {
 145                                                         FD_SET((uint)handle_slot_to_fd[i], &aexcept);
 146                                                 }
 147                                                 retcode++;
 148                                         }
 149                                 }
 150                         }
 151                 }
 152         } while (retcode == 0 && (ms_total == INFINITE || GetTickCount64() < limit));
 153 
 154         if (rfds) {
 155                 *rfds = aread;
 156         }
 157         if (wfds) {
 158                 *wfds = awrite;
 159         }
 160         if (efds) {
 161                 *efds = aexcept;
 162         }
 163 
 164         return retcode;
 165 }
 166 
 167 #endif
 168 
 169 /*
 170  * Local variables:
 171  * tab-width: 4
 172  * c-basic-offset: 4
 173  * End:
 174  * vim600: noet sw=4 ts=4 fdm=marker
 175  * vim<600: noet sw=4 ts=4
 176  */

/* [<][>][^][v][top][bottom][index][help] */