class: Win32OperatingSystem
authorStefan Vogel <sv@exept.de>
Thu, 10 Apr 2014 10:54:27 +0200
changeset 16309 6df7a4841fb6
parent 16308 4f0cb8a09d1d
child 16310 c58c06bf77b6
class: Win32OperatingSystem added: #selectOnAnyReadable:writable:exception:readableInto:writableInto:exceptionInto:withTimeOut:
Win32OperatingSystem.st
--- a/Win32OperatingSystem.st	Wed Apr 09 23:10:05 2014 +0200
+++ b/Win32OperatingSystem.st	Thu Apr 10 10:54:27 2014 +0200
@@ -11110,6 +11110,315 @@
     ^ (self readCheck:fd) ifTrue:[1] ifFalse:[0]
 !
 
+selectOnAnyReadable:readFdArray writable:writeFdArray exception:exceptFdArray
+  readableInto:readableResultFdArray writableInto:writableResultFdArray exceptionInto:exceptionResultFdArray
+  withTimeOut:millis
+    "wait for any fd in readFdArray (an Array of integers) to become ready for reading,
+     writeFdArray to become ready for writing,
+     or exceptFdArray to arrive exceptional data (i.e. out-of-band data).
+     Timeout after t milliseconds or - if the timeout time is 0 - immediately..
+     Empty fd-sets will always wait. Zero time can be used to poll file-
+     descriptors (i.e. to check if I/O possible without blocking).
+     The corresponding filedescriptors which are ready are returned in readableResultFdArray,
+     writableResultFdArray and exceptionResultFdArray respectively.
+
+     Return the (overall) number of selected filedescriptors.
+     readableResultFdArray, writableResultFdArray and exceptionResultFdArray will
+     get a nil-value stored into the slot after the last valid fileDescriptor;
+     Thus, the caller can simply scan these arrays upTo the end or a nil value."
+
+%{
+#define MAXHANDLE 128
+    int i;
+    INT t;
+    OBJ fd, retFd;
+    int ret;
+    int numHandles = 0;
+    DWORD res;
+    HANDLE hArray[MAXHANDLE+1];
+    int retArray[MAXHANDLE];
+    int readCount, writeCount, exceptCount;
+    int resultSizeReadable, resultSizeWritable, resultSizeException;
+    int cntR = 0, cntW = 0, cntE = 0;
+    OBJ *__resultR, *__resultW, *__resultE;
+
+    if (readableResultFdArray != nil) {
+        if (! __isArrayLike(readableResultFdArray)) {
+            goto fail;
+        }
+        resultSizeReadable = __arraySize(readableResultFdArray);
+    }
+    if (writableResultFdArray != nil) {
+        if (! __isArrayLike(writableResultFdArray)) {
+            goto fail;
+        }
+        resultSizeWritable = __arraySize(writableResultFdArray);
+    }
+    if (exceptionResultFdArray != nil) {
+        if (! __isArrayLike(exceptionResultFdArray)) {
+            goto fail;
+        }
+        resultSizeException = __arraySize(exceptionResultFdArray);
+    }
+
+    if (__isNonNilObject(readFdArray)) {
+        if (! __isArrayLike(readFdArray)) goto fail;
+        readCount = __arraySize(readFdArray);
+    } else {
+        readCount = 0;
+    }
+
+    if (__isNonNilObject(writeFdArray)) {
+        if (! __isArrayLike(writeFdArray)) goto fail;
+        writeCount = __arraySize(writeFdArray);
+    } else {
+        writeCount = 0;
+    }
+
+    if (__isNonNilObject(exceptFdArray)) {
+        if (! __isArrayLike(exceptFdArray)) goto fail;
+        exceptCount = __arraySize(exceptFdArray);
+    } else {
+        exceptCount = 0;
+    }
+    __resultR = __arrayVal(readableResultFdArray);
+    __resultW = __arrayVal(writableResultFdArray);
+    __resultE = __arrayVal(exceptionResultFdArray);
+
+    for (i = 0; (i < readCount) && (numHandles < MAXHANDLE); i++) {
+        fd = __arrayVal(readFdArray)[i];
+
+        if (fd != nil) {
+            if (__isExternalAddressLike(fd)) {
+                hArray  [numHandles] = _HANDLEVal(fd);
+                retArray[numHandles] = i;
+                ++numHandles;
+            } else {
+                int canRead = _canReadWithoutBlocking (__intVal(fd) );
+
+                if (canRead > 0 ) {
+                    if (cntR < resultSizeReadable) {
+                        __resultR[cntR] = fd;
+                    }
+                    cntR++;
+                } else {
+                    if (canRead < 0 ) {
+                        @global(LastErrorNumber) = __mkSmallInteger(EBADF);
+                        RETURN (__mkSmallInteger(-1));
+                    }
+                }
+            }
+        }
+    }
+
+    for (i = 0; (i < writeCount) && (numHandles < MAXHANDLE);i++) {
+        fd = __arrayVal(writeFdArray)[i];
+
+        if (fd != nil) {
+            if (__isExternalAddressLike(fd)) {
+                hArray  [numHandles] = _HANDLEVal(fd);
+                retArray[numHandles] = i + 10000;
+                ++numHandles;
+            } else {
+                int canWrite = _canWriteWithoutBlocking (__intVal(fd) );
+
+                if (canWrite > 0 ) {
+                    if (cntW < resultSizeWritable) {
+                        __resultW[cntW] = fd;
+                    }
+                    cntW++;
+                } else {
+                    if (canWrite < 0 ) {
+                        @global(LastErrorNumber) = __mkSmallInteger(EBADF);
+                        RETURN (__mkSmallInteger(-1));
+                    }
+                }
+            }
+        }
+    }
+
+    for (i = 0; (i < exceptCount) && (numHandles < MAXHANDLE);i++) {
+        fd = __arrayVal(exceptFdArray)[i];
+
+        if (fd != nil) {
+            if (__isExternalAddressLike(fd)) {
+                hArray  [numHandles] = _HANDLEVal(fd);
+                retArray[numHandles] = i + 20000;
+                ++numHandles;
+            }
+        }
+    }
+
+    if (cntR || cntW) {
+        // for now: we are done
+        RETURN(__mkSmallInteger(cntR+cntW+cntE));
+        // maybe later: check for other handles immediately
+        t = 0;
+    } else {
+        if (__isSmallInteger(millis)) {
+            t = __intVal(millis);
+
+            if (t <= 0 && numHandles == 0) {
+                RETURN (__mkSmallInteger(0));
+            }
+        } else {
+            t = INFINITE;
+        }
+    }
+
+#ifdef SELECT3DEBUGWIN32
+    console_printf("wait Handles = %d timeout = %d\n",numHandles, t);
+#endif
+
+    res = __vmWait(numHandles, hArray, MAXHANDLE, t);
+
+    // refetch possibly moved pointers after wait
+    __resultR = __arrayVal(readableResultFdArray);
+    __resultW = __arrayVal(writableResultFdArray);
+    __resultE = __arrayVal(exceptionResultFdArray);
+
+    if (numHandles) {
+        if (res == WAIT_FAILED) {
+#ifdef SELECT2DEBUGWIN32
+            console_printf("- error %d; ret nil\n",GetLastError());
+#endif
+            if (__threadErrno == EINTR) {
+                @global(LastErrorNumber) = nil;
+                RETURN (__mkSmallInteger(0));
+            } else {
+                if (@global(InfoPrinting) == true) {
+                    console_fprintf(stderr, "Win32OS [info]: select errno = %d\n", __threadErrno);
+                }
+                @global(LastErrorNumber) = __mkSmallInteger(EBADF);
+                RETURN (__mkSmallInteger(-1));
+            }
+        }
+
+        if (res == WAIT_TIMEOUT) {
+#ifdef SELECT3DEBUGWIN32
+            console_printf("- timeOut; ret nil\n" );
+#endif
+            goto polling;
+        }
+
+        if (res == numHandles) {
+            if (1 /* @global(InfoPrinting) == true */) {
+                console_fprintf(stderr, "Win32OS [info]: plugIn event has been handled\n");
+            }
+            goto done;
+        }
+        if ((res < 0) || (res > numHandles)) {
+#ifdef SELECTDEBUGWIN32
+            console_printf("- res=%d error1 %d\n", res, GetLastError());
+#endif
+            goto done;
+        }
+
+        ret = res;
+
+        if (ret < numHandles) {
+            int fd = retArray[ret];
+
+            @global(LastErrorNumber) = nil;
+
+#ifdef SELECTDEBUGWIN32
+            if (ret) console_printf("wait Handles %d %d ret\n", ret, fd);
+#endif
+            if (fd < 10000) {
+                if (cntR < resultSizeReadable) {
+                    OBJ temp = __arrayVal(readFdArray)[fd];
+                    __resultR[cntR] = temp;
+                    __STORE(readableResultFdArray, temp);
+                }
+                cntR++;
+            }
+            if (fd < 20000) {
+                if (cntW < resultSizeWritable) {
+                    OBJ temp = __arrayVal(writeFdArray)[fd-10000];
+                    __resultW[cntW] = temp;
+                    __STORE(writableResultFdArray, temp);
+                }
+                cntW++;
+            }
+            if (cntE < resultSizeException) {
+                OBJ temp = __arrayVal(exceptFdArray)[fd-20000];
+                __resultE[cntE] = temp;
+                __STORE(exceptionResultFdArray, temp);
+            }
+            cntE++;
+        }
+        console_fprintf(stderr, "Win32OS [info]: wait Handles ret = %d error2 %d\n", ret, GetLastError());
+        goto fail;
+    }
+    if (t == 0) {
+        // if we did not wait, there is no need to check again
+        goto done;
+    }
+
+polling:
+    for (i=0; i < readCount; i++) {
+        fd = __arrayVal(readFdArray)[i];
+        if (fd != nil && ! __isExternalAddressLike(fd)) {
+            int canRead = _canReadWithoutBlocking (__intVal(fd));
+
+            if (canRead > 0 ) {
+                if (cntR < resultSizeReadable) {
+                    __resultR[cntR] = fd;
+                }
+                cntR++;
+            } else {
+                if (canRead < 0 ) {
+                    @global(LastErrorNumber) = __mkSmallInteger(EBADF);
+                    RETURN (__mkSmallInteger(-1));
+                }
+            }
+        }
+    }
+
+    for (i=0; i < writeCount;i++) {
+        fd = __arrayVal(writeFdArray)[i];
+        if (fd != nil && ! __isExternalAddressLike(fd)) {
+            int canWrite = _canWriteWithoutBlocking (__intVal(fd));
+
+            if (canWrite > 0 ) {
+                if (cntW < resultSizeWritable) {
+                    __resultW[cntW] = __mkSmallInteger(i);
+                }
+                cntW++;
+            } else {
+                if (canWrite < 0 ) {
+                    @global(LastErrorNumber) = __mkSmallInteger(EBADF);
+                    RETURN (__mkSmallInteger(-1));
+                }
+            }
+        }
+    }
+
+done:
+    /* add a delimiter */
+    if (cntR < resultSizeReadable) {
+        __resultR[cntR] = nil;
+    }
+    if (cntW < resultSizeWritable) {
+        __resultW[cntW] = nil;
+    }
+    if (cntE < resultSizeException) {
+        __resultE[cntE] = nil;
+    }
+
+    @global(LastErrorNumber) = nil;
+    RETURN (__mkSmallInteger(cntR+cntW+cntE));
+
+fail: ;
+%}.
+    "
+     timeout argument not integer,
+     or any fd-array nonNil and not an array
+     or not supported by OS
+    "
+    ^ self primitiveFailed
+!
+
 selectOnAnyReadable:readFdArray writable:writeFdArray exception:exceptFdArray withTimeOut:millis
     "wait for any fd in readFdArray (an Array of integers) to become ready for
      reading, writeFdArray to become ready for writing, or exceptFdArray to
@@ -17548,15 +17857,15 @@
 !Win32OperatingSystem class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libbasic/Win32OperatingSystem.st,v 1.494 2014-04-04 08:24:43 stefan Exp $'
+    ^ '$Header: /cvs/stx/stx/libbasic/Win32OperatingSystem.st,v 1.495 2014-04-10 08:54:27 stefan Exp $'
 !
 
 version_CVS
-    ^ '$Header: /cvs/stx/stx/libbasic/Win32OperatingSystem.st,v 1.494 2014-04-04 08:24:43 stefan Exp $'
+    ^ '$Header: /cvs/stx/stx/libbasic/Win32OperatingSystem.st,v 1.495 2014-04-10 08:54:27 stefan Exp $'
 !
 
 version_SVN
-    ^ '$Id: Win32OperatingSystem.st,v 1.494 2014-04-04 08:24:43 stefan Exp $'
+    ^ '$Id: Win32OperatingSystem.st,v 1.495 2014-04-10 08:54:27 stefan Exp $'
 
 ! !