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>