Annotation of embedaddon/php/win32/select.c, revision 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>