# HG changeset patch # User Stefan Vogel # Date 1481046414 -3600 # Node ID 7b8226c897647972422f387e16e9bfe49bbd5f2f # Parent 12cf2700134c63850344da516c9c881f70029fba #TUNING by stefan class: Win32OperatingSystem changed: #selectOnAnyReadable:writable:exception:readableInto:writableInto:exceptionInto:withTimeOut: Speed up select on sockets diff -r 12cf2700134c -r 7b8226c89764 Win32OperatingSystem.st --- a/Win32OperatingSystem.st Tue Dec 06 14:26:48 2016 +0100 +++ b/Win32OperatingSystem.st Tue Dec 06 18:46:54 2016 +0100 @@ -978,7 +978,6 @@ "Modified: 7.1.1997 / 19:36:11 / stefan" ! ! - !Win32OperatingSystem class methodsFor:'OS signal constants'! sigABRT @@ -12022,10 +12021,7 @@ //#define SELECTDEBUGWIN32 //#define SELECT3DEBUGWIN32 #define MAXHANDLE 128 - int i, idx; - INT t; - int numHandles; - DWORD res; + int i; HANDLE hArray[MAXHANDLE+1]; int retArray[MAXHANDLE]; int readCount, writeCount, exceptCount; @@ -12035,315 +12031,324 @@ fd_set readFds; fd_set writeFds; fd_set exceptFds; - int hasSockets; - int hasPipes; + int numHandles, numSockets, numPipes; int pass = 1; // perform up to 2 passes if (readableResultFdArray != nil) { - if (! __isArrayLike(readableResultFdArray)) { - goto fail; - } - resultSizeReadable = __arraySize(readableResultFdArray); + if (! __isArrayLike(readableResultFdArray)) { + goto fail; + } + resultSizeReadable = __arraySize(readableResultFdArray); } if (writableResultFdArray != nil) { - if (! __isArrayLike(writableResultFdArray)) { - goto fail; - } - resultSizeWritable = __arraySize(writableResultFdArray); - if (readableResultFdArray == writableResultFdArray) { - // allow common result set for read/write/except - pcntW = &cntR; - } + if (! __isArrayLike(writableResultFdArray)) { + goto fail; + } + resultSizeWritable = __arraySize(writableResultFdArray); + if (readableResultFdArray == writableResultFdArray) { + // allow common result set for read/write/except + pcntW = &cntR; + } } if (exceptionResultFdArray != nil) { - if (! __isArrayLike(exceptionResultFdArray)) { - goto fail; - } - resultSizeException = __arraySize(exceptionResultFdArray); - if (exceptionResultFdArray == readableResultFdArray) { - // allow common result set for read/write/except - pcntE = &cntR; - } else if (exceptionResultFdArray == writableResultFdArray) { - pcntE = &cntW; - } + if (! __isArrayLike(exceptionResultFdArray)) { + goto fail; + } + resultSizeException = __arraySize(exceptionResultFdArray); + if (exceptionResultFdArray == readableResultFdArray) { + // allow common result set for read/write/except + pcntE = &cntR; + } else if (exceptionResultFdArray == writableResultFdArray) { + pcntE = &cntW; + } } if (__isNonNilObject(readFdArray)) { - if (! __isArrayLike(readFdArray)) goto fail; - readCount = __arraySize(readFdArray); + if (! __isArrayLike(readFdArray)) goto fail; + readCount = __arraySize(readFdArray); } else { - readCount = 0; + readCount = 0; } if (__isNonNilObject(writeFdArray)) { - if (! __isArrayLike(writeFdArray)) goto fail; - writeCount = __arraySize(writeFdArray); + if (! __isArrayLike(writeFdArray)) goto fail; + writeCount = __arraySize(writeFdArray); } else { - writeCount = 0; + writeCount = 0; } if (__isNonNilObject(exceptFdArray)) { - if (! __isArrayLike(exceptFdArray)) goto fail; - exceptCount = __arraySize(exceptFdArray); + if (! __isArrayLike(exceptFdArray)) goto fail; + exceptCount = __arraySize(exceptFdArray); } else { - exceptCount = 0; + exceptCount = 0; } pollAgain: FD_ZERO(&readFds); FD_ZERO(&writeFds); FD_ZERO(&exceptFds); - numHandles = hasSockets = hasPipes = 0; + numHandles = numSockets = numPipes = 0; for (i = 0; (i < readCount) && (numHandles < MAXHANDLE); i++) { - OBJ fd = __arrayVal(readFdArray)[i]; - - if (fd != nil) { - if (__Class(fd) == @global(Win32SocketHandle)) { - FD_SET (_HANDLEVal(fd), &readFds); - hasSockets++; - } else if (__isSmallInteger(fd)) { - DWORD canRead; - if (PeekNamedPipe(_get_osfhandle(__intVal(fd)), 0, 0, 0, &canRead, 0)) { - if (canRead > 0) { - if (*pcntR < resultSizeReadable) { - __arrayVal(readableResultFdArray)[*pcntR] = fd; - } - (*pcntR)++; cntAll++; - } - } else { - @global(LastErrorNumber) = __mkSmallInteger(EBADF); - RETURN (__mkSmallInteger(-1)); - } - hasPipes++; - } else { - hArray [numHandles] = _HANDLEVal(fd); - retArray[numHandles] = i; - ++numHandles; - } - } + OBJ fd = __arrayVal(readFdArray)[i]; + + if (fd != nil) { + if (__Class(fd) == @global(Win32SocketHandle)) { + FD_SET (_HANDLEVal(fd), &readFds); + numSockets++; + } else if (__isSmallInteger(fd)) { + DWORD canRead; + if (PeekNamedPipe(_get_osfhandle(__intVal(fd)), 0, 0, 0, &canRead, 0)) { + if (canRead > 0) { + if (*pcntR < resultSizeReadable) { + __arrayVal(readableResultFdArray)[*pcntR] = fd; + } + (*pcntR)++; cntAll++; + } + } else { + @global(LastErrorNumber) = __mkSmallInteger(EBADF); + RETURN (__mkSmallInteger(-1)); + } + numPipes++; + } else { + hArray [numHandles] = _HANDLEVal(fd); + retArray[numHandles] = i; + ++numHandles; + } + } } for (i = 0; (i < writeCount) && (numHandles < MAXHANDLE); i++) { - OBJ fd = __arrayVal(writeFdArray)[i]; - - if (fd != nil) { - if (__Class(fd) == @global(Win32SocketHandle)) { - FD_SET (_HANDLEVal(fd), &writeFds); - hasSockets++; - } else if (__isSmallInteger(fd)) { - // kludge: assume that pipes can alway be written - if (*pcntW < resultSizeWritable) { - __arrayVal(writableResultFdArray)[*pcntW] = fd; - } - (*pcntW)++; cntAll++; - // there is no pipe to check - } else { - hArray [numHandles] = _HANDLEVal(fd); - retArray[numHandles] = i + 10000; - ++numHandles; - } - } + OBJ fd = __arrayVal(writeFdArray)[i]; + + if (fd != nil) { + if (__Class(fd) == @global(Win32SocketHandle)) { + FD_SET (_HANDLEVal(fd), &writeFds); + numSockets++; + } else if (__isSmallInteger(fd)) { + // kludge: assume that pipes can alway be written + if (*pcntW < resultSizeWritable) { + __arrayVal(writableResultFdArray)[*pcntW] = fd; + } + (*pcntW)++; cntAll++; + // there is no pipe to check + } else { + hArray [numHandles] = _HANDLEVal(fd); + retArray[numHandles] = i + 10000; + ++numHandles; + } + } } for (i = 0; (i < exceptCount) && (numHandles < MAXHANDLE); i++) { - OBJ fdOrPid = __arrayVal(exceptFdArray)[i]; - - if (fdOrPid != nil) { - if (__Class(fdOrPid) == @global(Win32SocketHandle)) { - FD_SET (_HANDLEVal(fdOrPid), &exceptFds); - hasSockets++; - } else if (__isExternalAddressLike(fdOrPid)) { - // a PID - hArray [numHandles] = _HANDLEVal(fdOrPid); - retArray[numHandles] = i + 20000; - ++numHandles; - } - } - } - - if (hasSockets) { - struct timeval tv = {0, 0}; - int nReady; - -#ifdef SELECT3DEBUGWIN32 - console_printf("select hasSockets = %d\n", hasSockets); -#endif - nReady = select(1 , &readFds, &writeFds, &exceptFds, &tv); // first parameter to select is ignored in windows - if (nReady < 0) { -#ifdef SELECTDEBUGWIN32 - console_printf("error in select %d %d\n", nReady, GetLastError()); -#endif - @global(LastErrorNumber) = __mkSmallInteger(EBADF); - RETURN (__mkSmallInteger(-1)); - } - if (nReady > 0) { -#ifdef SELECT3DEBUGWIN32 - console_printf("select nReady %d of %d\n", nReady, hasSockets); -#endif - for (i = 0; i < readCount; i++) { - OBJ fd = __arrayVal(readFdArray)[i]; - if ((__Class(fd) == @global(Win32SocketHandle)) && FD_ISSET(_HANDLEVal(fd), &readFds)) { - if (*pcntR < resultSizeReadable) { - __arrayVal(readableResultFdArray)[*pcntR] = fd; - __STORE(readableResultFdArray, fd); - } - (*pcntR)++; cntAll++; - } - } - for (i = 0; i < writeCount; i++) { - OBJ fd = __arrayVal(writeFdArray)[i]; - if ((__Class(fd) == @global(Win32SocketHandle)) && FD_ISSET(_HANDLEVal(fd), &writeFds)) { - if (*pcntW < resultSizeWritable) { - __arrayVal(writableResultFdArray)[*pcntW] = fd; - __STORE(writableResultFdArray, fd); - } - (*pcntW)++; cntAll++; - } - } - for (i = 0; i < exceptCount; i++) { - OBJ fd = __arrayVal(exceptFdArray)[i]; - if ((__Class(fd) == @global(Win32SocketHandle)) && FD_ISSET(_HANDLEVal(fd), &exceptFds)) { - if (*pcntE < resultSizeException) { - __arrayVal(exceptionResultFdArray)[*pcntE] = fd; - __STORE(exceptionResultFdArray, fd); - } - (*pcntE)++; cntAll++; - } - } - - } - } - if (pass > 1) // perform maximum 2 passes - goto done; - - if (cntAll) { - // check for other handles and return immediately, no timeout - t = 0; - } else { - if (__isSmallInteger(millis)) { - t = __intVal(millis); - - if (t <= 0 && numHandles == 0) { - RETURN (__mkSmallInteger(0)); - } - } else { - t = INFINITE; - } - } - - if (numHandles == 0 && t == 0) { - // nothing to do and no wait - goto done; - } + OBJ fdOrPid = __arrayVal(exceptFdArray)[i]; + + if (fdOrPid != nil) { + if (__Class(fdOrPid) == @global(Win32SocketHandle)) { + FD_SET (_HANDLEVal(fdOrPid), &exceptFds); + numSockets++; + } else if (__isExternalAddressLike(fdOrPid)) { + // a PID + hArray [numHandles] = _HANDLEVal(fdOrPid); + retArray[numHandles] = i + 20000; + ++numHandles; + } + } + } + + // +++++ checking for Windows Handles +++++++++++++++++++++++++++++++++++++++++ + if (numHandles != 0) { + DWORD res; + int idx; + INT t; + + if (numSockets || pass > 1) { + // do not wait - wait when checking for sockets + t = 0; + } else if (__isSmallInteger(millis)) { + t = __intVal(millis); + } else { + t = INFINITE; + } #ifdef SELECT3DEBUGWIN32 - console_printf("wait numhandles = %d timeout = %d\n", numHandles, t); -#endif - - res = __vmWait(numHandles, hArray, MAXHANDLE, t); - - if (res == WAIT_TIMEOUT) { + console_printf("wait numhandles = %d timeout = %d\n", numHandles, t); +#endif + + res = __vmWait(numHandles, hArray, MAXHANDLE, (int)t); + + if (res == WAIT_TIMEOUT) { #ifdef SELECT3DEBUGWIN32 - console_printf("- timeOut; ret nil\n" ); -#endif - if (t != 0 && (hasSockets || hasPipes)) { - // if not a single handle is ready, poll sockets an pipes again - pass = 2; - goto pollAgain; - } - goto done; - } - - if (res == WAIT_FAILED) { + console_printf("- timeOut" ); +#endif + goto checkSockets; + } + if (res == __WAIT_INTERRUPTED) { +#ifdef SELECT3DEBUGWIN32 + console_printf("- interrupted\n" ); +#endif + goto done; + } + + if (res == WAIT_FAILED) { #ifdef SELECT2DEBUGWIN32 - console_printf("- error %d (last %d); ret -1\n", __threadErrno, GetLastError()); -#endif - if (__threadErrno == EINTR) { - @global(LastErrorNumber) = nil; - RETURN (__mkSmallInteger(0)); - } else { - if (@global(InfoPrinting) == true) { -// console_fprintf(stderr, "Win32OS [info]: select errno = %d (last %d)\n", __threadErrno, GetLastError()); - console_printf("Win32OS [info]: select errno = %d (last %d)\n", __threadErrno, GetLastError()); - } - @global(LastErrorNumber) = __mkSmallInteger(EBADF); - RETURN (__mkSmallInteger(-1)); - } - } - - if (numHandles) { - if (res == numHandles) { - // vmwait() added an IRQ event to the handles, and this one has been triggered - if (1 /* @global(InfoPrinting) == true */) { - console_fprintf(stderr, "Win32OS [info]: plugIn event has been handled\n"); - } - goto done; - } - if ((res < 0) || (res >= numHandles)) { - console_printf("- res=%d error1 %d\n", res, GetLastError()); - goto done; - } - - idx = retArray[res]; - cntAll++; + console_printf("- error %d (last %d); ret -1\n", __threadErrno, GetLastError()); +#endif + if (__threadErrno == EINTR) { + @global(LastErrorNumber) = nil; + RETURN (__mkSmallInteger(0)); + } else { + if (@global(InfoPrinting) == true) { +// console_fprintf(stderr, "Win32OS [info]: select errno = %d (last %d)\n", __threadErrno, GetLastError()); + console_printf("Win32OS [info]: select errno = %d (last %d)\n", __threadErrno, GetLastError()); + } + @global(LastErrorNumber) = __mkSmallInteger(EBADF); + RETURN (__mkSmallInteger(-1)); + } + } + + if (res == numHandles) { + // vmwait() added an IRQ event to the handles, and this one has been triggered + if (1 /* @global(InfoPrinting) == true */) { + console_fprintf(stderr, "Win32OS [info]: plugIn event has been handled\n"); + } + goto done; + } + if ((res < 0) || (res >= numHandles)) { + console_printf("- res=%d error1 %d\n", res, GetLastError()); + goto done; + } + + idx = retArray[res]; + cntAll++; #ifdef SELECTDEBUGWIN32 - console_printf("wait Handles res %d idx %d numHandles %d --- ", res, idx, numHandles); -#endif - if (idx < 10000) { - if (*pcntR < resultSizeReadable) { - OBJ temp = __arrayVal(readFdArray)[idx]; - __arrayVal(readableResultFdArray)[*pcntR] = temp; - __STORE(readableResultFdArray, temp); + console_printf("wait Handles res %d idx %d numHandles %d --- ", res, idx, numHandles); +#endif + if (idx < 10000) { + if (*pcntR < resultSizeReadable) { + OBJ temp = __arrayVal(readFdArray)[idx]; + __arrayVal(readableResultFdArray)[*pcntR] = temp; + __STORE(readableResultFdArray, temp); #ifdef SELECTDEBUGWIN32 - console_printf("read ready: %x\n", __externalAddressVal(temp)); -#endif - (*pcntR)++; - } - } else if (idx < 20000) { - if (*pcntW < resultSizeWritable) { - OBJ temp = __arrayVal(writeFdArray)[idx-10000]; - __arrayVal(writableResultFdArray)[*pcntW] = temp; - __STORE(writableResultFdArray, temp); + console_printf("read ready: %x\n", __externalAddressVal(temp)); +#endif + (*pcntR)++; + } + } else if (idx < 20000) { + if (*pcntW < resultSizeWritable) { + OBJ temp = __arrayVal(writeFdArray)[idx-10000]; + __arrayVal(writableResultFdArray)[*pcntW] = temp; + __STORE(writableResultFdArray, temp); +#ifdef SELECTDEBUGWIN32 + console_printf("write ready: %x\n", temp); +#endif + (*pcntW)++; + } + } else { + if (*pcntE < resultSizeException) { + OBJ temp = __arrayVal(exceptFdArray)[idx-20000]; + __arrayVal(exceptionResultFdArray)[*pcntE] = temp; + __STORE(exceptionResultFdArray, temp); +#ifdef SELECTDEBUGWIN32 + console_printf("except ready: %x\n", temp); +#endif + (*pcntE)++; + } #ifdef SELECTDEBUGWIN32 - console_printf("write ready: %x\n", temp); -#endif - (*pcntW)++; - } - } else { - if (*pcntE < resultSizeException) { - OBJ temp = __arrayVal(exceptFdArray)[idx-20000]; - __arrayVal(exceptionResultFdArray)[*pcntE] = temp; - __STORE(exceptionResultFdArray, temp); + else + console_printf("cntE: %d, resultSizeException: %d\n", *pcntE, resultSizeException); +#endif + } + } + + +// ++++++++++ Check Sockets +++++++++++++++++++++++++++++++++++ +checkSockets: + if (pass > 1) // perform maximum 2 passes + goto done; + + if (numSockets) { + struct timeval tv = {0, 0}; + struct timeval *tvp = &tv; + int nReady; + + // do not wait, if there are threads that can be resumed + if (!__vmTestIfAnyThreadMustBeResumed() && cntAll == 0) { + // no ready handles found yet - do wait + if (__isSmallInteger(millis)) { + tv.tv_usec = __intVal(millis) * 1000; + } else { + // no timeout + tvp = 0; + } + } + +#ifdef SELECT3DEBUGWIN32 + console_printf("select numSockets = %d\n", numSockets); +#endif + nReady = select(1 , &readFds, &writeFds, &exceptFds, tvp); // first parameter to select is ignored in windows + if (nReady < 0) { #ifdef SELECTDEBUGWIN32 - console_printf("except ready: %x\n", temp); -#endif - (*pcntE)++; - } -#ifdef SELECTDEBUGWIN32 - else - console_printf("cntE: %d, resultSizeException: %d\n", *pcntE, resultSizeException); -#endif - } - } - if (t != 0 && (hasSockets || hasPipes)) { - // back after timeout, maybe some sockets or pipes did wake up - // in the meantime? - pass = 2; - goto pollAgain; + console_printf("error in select %d %d\n", nReady, GetLastError()); +#endif + @global(LastErrorNumber) = __mkSmallInteger(EBADF); + RETURN (__mkSmallInteger(-1)); + } + if (nReady > 0) { +#ifdef SELECT3DEBUGWIN32 + console_printf("select nReady %d of %d\n", nReady, numSockets); +#endif + for (i = 0; i < readCount; i++) { + OBJ fd = __arrayVal(readFdArray)[i]; + if ((__Class(fd) == @global(Win32SocketHandle)) && FD_ISSET(_HANDLEVal(fd), &readFds)) { + if (*pcntR < resultSizeReadable) { + __arrayVal(readableResultFdArray)[*pcntR] = fd; + __STORE(readableResultFdArray, fd); + } + (*pcntR)++; cntAll++; + } + } + for (i = 0; i < writeCount; i++) { + OBJ fd = __arrayVal(writeFdArray)[i]; + if ((__Class(fd) == @global(Win32SocketHandle)) && FD_ISSET(_HANDLEVal(fd), &writeFds)) { + if (*pcntW < resultSizeWritable) { + __arrayVal(writableResultFdArray)[*pcntW] = fd; + __STORE(writableResultFdArray, fd); + } + (*pcntW)++; cntAll++; + } + } + for (i = 0; i < exceptCount; i++) { + OBJ fd = __arrayVal(exceptFdArray)[i]; + if ((__Class(fd) == @global(Win32SocketHandle)) && FD_ISSET(_HANDLEVal(fd), &exceptFds)) { + if (*pcntE < resultSizeException) { + __arrayVal(exceptionResultFdArray)[*pcntE] = fd; + __STORE(exceptionResultFdArray, fd); + } + (*pcntE)++; cntAll++; + } + } + } + if (tvp && tv.tv_usec != 0 && (numHandles != 0 || numPipes != 0)) { + // back after timeout, maybe some handles or pipes did wake up + // in the meantime? + pass = 2; + goto pollAgain; + } } done: /* add a delimiter */ if (*pcntR < resultSizeReadable) { - __arrayVal(readableResultFdArray)[*pcntR] = nil; + __arrayVal(readableResultFdArray)[*pcntR] = nil; } if (*pcntW < resultSizeWritable) { - __arrayVal(writableResultFdArray)[*pcntW] = nil; + __arrayVal(writableResultFdArray)[*pcntW] = nil; } if (*pcntE < resultSizeException) { - __arrayVal(exceptionResultFdArray)[*pcntE] = nil; + __arrayVal(exceptionResultFdArray)[*pcntE] = nil; } @global(LastErrorNumber) = nil;