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>