Back to index

php5  5.3.10
select.c
Go to the documentation of this file.
00001 /*
00002   +----------------------------------------------------------------------+
00003   | PHP Version 5                                                        |
00004   +----------------------------------------------------------------------+
00005   | Copyright (c) 1997-2012 The PHP Group                                |
00006   +----------------------------------------------------------------------+
00007   | This source file is subject to version 3.01 of the PHP license,      |
00008   | that is bundled with this package in the file LICENSE, and is        |
00009   | available through the world-wide-web at the following url:           |
00010   | http://www.php.net/license/3_01.txt                                  |
00011   | If you did not receive a copy of the PHP license and are unable to   |
00012   | obtain it through the world-wide-web, please send a note to          |
00013   | license@php.net so we can mail you a copy immediately.               |
00014   +----------------------------------------------------------------------+
00015   | Author: Wez Furlong <wez@thebrainroom.com>                           |
00016   +----------------------------------------------------------------------+
00017 */
00018 
00019 #include "php.h"
00020 #include "php_network.h"
00021 
00022 #ifdef PHP_WIN32
00023 
00024 /* $Id: select.c 321634 2012-01-01 13:15:04Z felipe $ */
00025 
00026 /* Win32 select() will only work with sockets, so we roll our own implementation here.
00027  * - If you supply only sockets, this simply passes through to winsock select().
00028  * - If you supply file handles, there is no way to distinguish between
00029  *   ready for read/write or OOB, so any set in which the handle is found will
00030  *   be marked as ready.
00031  * - If you supply a mixture of handles and sockets, the system will interleave
00032  *   calls between select() and WaitForMultipleObjects(). The time slicing may
00033  *   cause this function call to take up to 100 ms longer than you specified.
00034  * - Calling this with NULL sets as a portable way to sleep with sub-second
00035  *   accuracy is not supported.
00036  * */
00037 PHPAPI int php_select(int max_fd, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *tv)
00038 {
00039        DWORD ms_total, limit;
00040        HANDLE handles[MAXIMUM_WAIT_OBJECTS];
00041        int handle_slot_to_fd[MAXIMUM_WAIT_OBJECTS];
00042        int n_handles = 0, i;
00043        fd_set sock_read, sock_write, sock_except;
00044        fd_set aread, awrite, aexcept;
00045        int sock_max_fd = -1;
00046        struct timeval tvslice;
00047        int retcode;
00048 
00049 #define SAFE_FD_ISSET(fd, set)     (set != NULL && FD_ISSET(fd, set))
00050        
00051        /* calculate how long we need to wait in milliseconds */
00052        if (tv == NULL) {
00053               ms_total = INFINITE;
00054        } else {
00055               ms_total = tv->tv_sec * 1000;
00056               ms_total += tv->tv_usec / 1000;
00057        }
00058 
00059        FD_ZERO(&sock_read);
00060        FD_ZERO(&sock_write);
00061        FD_ZERO(&sock_except);
00062        
00063        /* build an array of handles for non-sockets */
00064        for (i = 0; i < max_fd; i++) {
00065               if (SAFE_FD_ISSET(i, rfds) || SAFE_FD_ISSET(i, wfds) || SAFE_FD_ISSET(i, efds)) {
00066                      handles[n_handles] = (HANDLE)(zend_uintptr_t)_get_osfhandle(i);
00067                      if (handles[n_handles] == INVALID_HANDLE_VALUE) {
00068                             /* socket */
00069                             if (SAFE_FD_ISSET(i, rfds)) {
00070                                    FD_SET((uint)i, &sock_read);
00071                             }
00072                             if (SAFE_FD_ISSET(i, wfds)) {
00073                                    FD_SET((uint)i, &sock_write);
00074                             }
00075                             if (SAFE_FD_ISSET(i, efds)) {
00076                                    FD_SET((uint)i, &sock_except);
00077                             }
00078                             if (i > sock_max_fd) {
00079                                    sock_max_fd = i;
00080                             }
00081                      } else {
00082                             handle_slot_to_fd[n_handles] = i;
00083                             n_handles++;
00084                      }
00085               }
00086        }
00087 
00088        if (n_handles == 0) {
00089               /* plain sockets only - let winsock handle the whole thing */
00090               return select(max_fd, rfds, wfds, efds, tv);
00091        }
00092        
00093        /* mixture of handles and sockets; lets multiplex between
00094         * winsock and waiting on the handles */
00095 
00096        FD_ZERO(&aread);
00097        FD_ZERO(&awrite);
00098        FD_ZERO(&aexcept);
00099        
00100        limit = GetTickCount() + ms_total;
00101        do {
00102               retcode = 0;
00103        
00104               if (sock_max_fd >= 0) {
00105                      /* overwrite the zero'd sets here; the select call
00106                       * will clear those that are not active */
00107                      aread = sock_read;
00108                      awrite = sock_write;
00109                      aexcept = sock_except;
00110 
00111                      tvslice.tv_sec = 0;
00112                      tvslice.tv_usec = 100000;
00113 
00114                      retcode = select(sock_max_fd+1, &aread, &awrite, &aexcept, &tvslice);
00115               }
00116               if (n_handles > 0) {
00117                      /* check handles */
00118                      DWORD wret;
00119 
00120                      wret = MsgWaitForMultipleObjects(n_handles, handles, FALSE, retcode > 0 ? 0 : 100, QS_ALLEVENTS);
00121 
00122                      if (wret == WAIT_TIMEOUT) {
00123                             /* set retcode to 0; this is the default.
00124                              * select() may have set it to something else,
00125                              * in which case we leave it alone, so this branch
00126                              * does nothing */
00127                             ;
00128                      } else if (wret == WAIT_FAILED) {
00129                             if (retcode == 0) {
00130                                    retcode = -1;
00131                             }
00132                      } else {
00133                             if (retcode < 0) {
00134                                    retcode = 0;
00135                             }
00136                             for (i = 0; i < n_handles; i++) {
00137                                    if (WAIT_OBJECT_0 == WaitForSingleObject(handles[i], 0)) {
00138                                           if (SAFE_FD_ISSET(handle_slot_to_fd[i], rfds)) {
00139                                                  FD_SET((uint)handle_slot_to_fd[i], &aread);
00140                                           }
00141                                           if (SAFE_FD_ISSET(handle_slot_to_fd[i], wfds)) {
00142                                                  FD_SET((uint)handle_slot_to_fd[i], &awrite);
00143                                           }
00144                                           if (SAFE_FD_ISSET(handle_slot_to_fd[i], efds)) {
00145                                                  FD_SET((uint)handle_slot_to_fd[i], &aexcept);
00146                                           }
00147                                           retcode++;
00148                                    }
00149                             }
00150                      }
00151               }
00152        } while (retcode == 0 && (ms_total == INFINITE || GetTickCount() < limit));
00153 
00154        if (rfds) {
00155               *rfds = aread;
00156        }
00157        if (wfds) {
00158               *wfds = awrite;
00159        }
00160        if (efds) {
00161               *efds = aexcept;
00162        }      
00163        
00164        return retcode;
00165 }
00166 
00167 #endif
00168 
00169 /*
00170  * Local variables:
00171  * tab-width: 4
00172  * c-basic-offset: 4
00173  * End:
00174  * vim600: noet sw=4 ts=4 fdm=marker
00175  * vim<600: noet sw=4 ts=4
00176  */