Annotation of embedaddon/php/win32/select.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:   +----------------------------------------------------------------------+
                      3:   | PHP Version 5                                                        |
                      4:   +----------------------------------------------------------------------+
                      5:   | Copyright (c) 1997-2012 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: select.c 321634 2012-01-01 13:15:04Z felipe $ */
                     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:        DWORD 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 = GetTickCount() + 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 || GetTickCount() < 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:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>