File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / php / win32 / select.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:34:34 2012 UTC (12 years, 1 month ago) by misho
Branches: php, MAIN
CVS tags: v5_4_3elwix, v5_4_17p0, HEAD
php 5.4.3+patches

    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,v 1.1.1.2 2012/05/29 12:34:34 misho Exp $ */
   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>