select: wake up readFDs if readable only;
authorClaus Gittinger <cg@exept.de>
Tue, 15 Jul 2003 16:03:28 +0200
changeset 7510 46a848d466b5
parent 7509 c8964822d8fd
child 7511 d6b7d28b135e
select: wake up readFDs if readable only; writeFDs if writable. Makes a difference, if an fd is used both for reading and writing.
AbstractOperatingSystem.st
ProcessorScheduler.st
UnixOperatingSystem.st
--- a/AbstractOperatingSystem.st	Tue Jul 15 14:19:45 2003 +0200
+++ b/AbstractOperatingSystem.st	Tue Jul 15 16:03:28 2003 +0200
@@ -5323,16 +5323,23 @@
 !
 
 selectOnAnyReadable:readFdArray writable:writeFdArray exception:exceptFdArray 
-        into:resultFdArray 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..
+        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 filedescriptors which are ready are returned in resultArray.
-
-     Return the number of selected filedescriptors"
+     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."
 
     self subclassResponsibility
 !
@@ -5383,7 +5390,7 @@
 !AbstractOperatingSystem class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libbasic/AbstractOperatingSystem.st,v 1.103 2003-07-15 12:19:28 cg Exp $'
+    ^ '$Header: /cvs/stx/stx/libbasic/AbstractOperatingSystem.st,v 1.104 2003-07-15 14:03:28 cg Exp $'
 ! !
 
 AbstractOperatingSystem initialize!
--- a/ProcessorScheduler.st	Tue Jul 15 14:19:45 2003 +0200
+++ b/ProcessorScheduler.st	Tue Jul 15 16:03:28 2003 +0200
@@ -626,7 +626,7 @@
      handle all timeout actions
     "
     anyTimeouts ifTrue:[
-	self evaluateTimeouts
+        self evaluateTimeouts
     ].
 
     "first do a quick check for semaphores using checkActions - this is needed for
@@ -639,42 +639,42 @@
     any := false.
     nActions := readCheckArray size.
     1 to:nActions do:[:index |
-	checkBlock := readCheckArray at:index.
-	(checkBlock notNil and:[checkBlock value]) ifTrue:[
-	    sema := readSemaphoreArray at:index.
-	    sema notNil ifTrue:[
-		sema signalOnce.
-	    ].
-	    any := true.
-	]
+        checkBlock := readCheckArray at:index.
+        (checkBlock notNil and:[checkBlock value]) ifTrue:[
+            sema := readSemaphoreArray at:index.
+            sema notNil ifTrue:[
+                sema signalOnce.
+            ].
+            any := true.
+        ]
     ].
     nActions := writeCheckArray size.
     1 to:nActions do:[:index |
-	checkBlock := writeCheckArray at:index.
-	(checkBlock notNil and:[checkBlock value]) ifTrue:[
-	    sema := writeSemaphoreArray at:index.
-	    sema notNil ifTrue:[
-		sema signalOnce.
-	    ].
-	    any := true.
-	]
+        checkBlock := writeCheckArray at:index.
+        (checkBlock notNil and:[checkBlock value]) ifTrue:[
+            sema := writeSemaphoreArray at:index.
+            sema notNil ifTrue:[
+                sema signalOnce.
+            ].
+            any := true.
+        ]
     ].
 
     "now, someone might be runnable ..."
 
     p := self highestPriorityRunnableProcess.
     p isNil ifTrue:[
-	"/ no one runnable, hard wait for event or timeout
-
-	self waitForEventOrTimeout.
-
-	"/ check for OS process termination
-	gotChildSignalInterrupt ifTrue:[
-	    gotChildSignalInterrupt := false.
-	    self handleChildSignalInterrupt
-	].
-	wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
-	^ self
+        "/ no one runnable, hard wait for event or timeout
+
+        self waitForEventOrTimeout.
+
+        "/ check for OS process termination
+        gotChildSignalInterrupt ifTrue:[
+            gotChildSignalInterrupt := false.
+            self handleChildSignalInterrupt
+        ].
+        wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
+        ^ self
     ].
 
     pri := p priority.
@@ -705,13 +705,13 @@
 
 "
     pri < TimingPriority ifTrue:[
-	anyTimeouts ifTrue:[
-	    millis := self timeToNextTimeout.
-	    millis == 0 ifTrue:[
-		wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
-		^ self
-	    ]
-	]
+        anyTimeouts ifTrue:[
+            millis := self timeToNextTimeout.
+            millis == 0 ifTrue:[
+                wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
+                ^ self
+            ]
+        ]
     ].
 "
 
@@ -724,37 +724,37 @@
     pri < UserInterruptPriority ifTrue:[
     
 "comment out this if above is uncommented"
-	anyTimeouts ifTrue:[
-	    millis := self timeToNextTimeout.
-	    millis == 0 ifTrue:[
-		wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
-		^ self
-	    ].
-	].
+        anyTimeouts ifTrue:[
+            millis := self timeToNextTimeout.
+            millis == 0 ifTrue:[
+                wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
+                ^ self
+            ].
+        ].
 "---"
 
-	useIOInterrupts ifTrue:[
+        useIOInterrupts ifTrue:[
 "/            readFdArray do:[:fd |
 "/                (fd notNil and:[fd >= 0]) ifTrue:[
 "/                    OperatingSystem enableIOInterruptsOn:fd
 "/                ].
 "/            ].
-	] ifFalse:[
-	    millis notNil ifTrue:[
-		millis := millis min:EventPollingInterval
-	    ] ifFalse:[
-		millis := EventPollingInterval
-	    ]
-	]
+        ] ifFalse:[
+            millis notNil ifTrue:[
+                millis := millis min:EventPollingInterval
+            ] ifFalse:[
+                millis := EventPollingInterval
+            ]
+        ]
     ].
 
     millis notNil ifTrue:[
-	"schedule a clock interrupt after millis milliseconds"
-	OperatingSystem enableTimer:millis rounded.
+        "schedule a clock interrupt after millis milliseconds"
+        OperatingSystem enableTimer:millis rounded.
     ].
 
     scheduledProcesses notNil ifTrue:[
-	scheduledProcesses add:p
+        scheduledProcesses add:p
     ].
 
     "
@@ -764,17 +764,17 @@
     self threadSwitch:p.
 
     "... when we arrive here, we are back on stage.
-	 Either by an ALARM or IO signal, or by a suspend of another process
+         Either by an ALARM or IO signal, or by a suspend of another process
     "
 
     millis notNil ifTrue:[
-	OperatingSystem disableTimer.
+        OperatingSystem disableTimer.
     ].
 
     "/ check for OS process termination
     gotChildSignalInterrupt ifTrue:[
-	gotChildSignalInterrupt := false.
-	self handleChildSignalInterrupt
+        gotChildSignalInterrupt := false.
+        self handleChildSignalInterrupt
     ].
 
     "/ check for new input
@@ -782,8 +782,8 @@
     OperatingSystem unblockInterrupts.
 
     (gotIOInterrupt or:[useIOInterrupts not]) ifTrue:[
-	gotIOInterrupt := false.
-	self checkForInputWithTimeout:0.
+        gotIOInterrupt := false.
+        self checkForIOWithTimeout:0.
     ].
 
     wasBlocked ifTrue:[OperatingSystem blockInterrupts].
@@ -2909,11 +2909,13 @@
 
 !ProcessorScheduler methodsFor:'waiting'!
 
-checkForInputWithTimeout:millis
+checkForIOWithTimeout:millis
     "this is called, when there is absolutely nothing to do;
-     hard wait for either input to arrive or a timeout to occur."
-
-    |nSelected index sema action wasBlocked err resultFdArray newProcessMaybeReady|
+     hard wait for either input to arrive, or output to be possible
+     or a timeout to occur."
+
+    |nReady index sema action wasBlocked err fd readyIndex
+     readableResultFdArray writableResultFdArray newProcessMaybeReady|
 
     "/ must enable interrupts, to be able to get out of a
     "/ long wait (especially, to handle sigChild in the meantime)
@@ -2923,19 +2925,23 @@
     ].
 
     newProcessMaybeReady := false.
-    resultFdArray := Array new:40.
-    nSelected := OperatingSystem 
-              selectOnAnyReadable:readFdArray 
-                         writable:writeFdArray
-                        exception:nil
-                             into:resultFdArray
-                      withTimeOut:millis.
+    readableResultFdArray := Array new:40.
+    writableResultFdArray := Array new:40.
+
+    nReady := OperatingSystem
+        selectOnAnyReadable:readFdArray     
+        writable:writeFdArray 
+        exception:nil 
+        readableInto:readableResultFdArray 
+        writableInto:writableResultFdArray 
+        exceptionInto:nil
+        withTimeOut:millis.
 
     wasBlocked ifTrue:[
         OperatingSystem blockInterrupts.
     ].
 
-    nSelected == 0 ifTrue:[
+    nReady == 0 ifTrue:[
         "/ either still nothing to do,
         "/ or error (which should not happen)
 
@@ -2960,12 +2966,11 @@
             ].
         ]
     ] ifFalse:[
-        nSelected > resultFdArray size ifTrue:[
-            nSelected := resultFdArray size.
-        ].
-        1 to:nSelected do:[:fdIndex| |fd|
-            fd := resultFdArray at:fdIndex.
-
+        readyIndex := 1.
+        [nReady > 0
+             and:[ readyIndex <= readableResultFdArray size
+             and:[ (fd := readableResultFdArray at:readyIndex) notNil ]]]
+        whileTrue:[
             index := readFdArray identityIndexOf:fd.
             index ~~ 0 ifTrue:[
                 sema := readSemaphoreArray at:index.
@@ -2979,6 +2984,15 @@
                     newProcessMaybeReady := true
                 ]
             ].
+            nReady := nReady - 1.
+            index := index + 1.
+        ].
+
+        readyIndex := 1.
+        [nReady > 0
+             and:[ readyIndex <= writableResultFdArray size
+             and:[ (fd := writableResultFdArray at:readyIndex) notNil ]]]
+        whileTrue:[
             index := writeFdArray identityIndexOf:fd.
             index ~~ 0 ifTrue:[
                 sema := writeSemaphoreArray at:index.
@@ -2992,6 +3006,8 @@
                     newProcessMaybeReady := true
                 ]
             ].
+            nReady := nReady - 1.
+            index := index + 1.
         ].
     ].
     ^ newProcessMaybeReady
@@ -3173,7 +3189,7 @@
         ].
 
         doingGC ifTrue:[
-            (self checkForInputWithTimeout:0) ifTrue:[
+            (self checkForIOWithTimeout:0) ifTrue:[
                 ^ self  "go back checking"
             ]
         ]
@@ -3211,7 +3227,7 @@
          waiting always 1 sec in the select - therefore we delay a bit and
          return - effectively polling in 50ms cycles
         "
-        (self checkForInputWithTimeout:0) ifTrue:[
+        (self checkForIOWithTimeout:0) ifTrue:[
             ^ self  "go back checking"
         ].
         OperatingSystem millisecondDelay:EventPollingInterval.
@@ -3230,7 +3246,7 @@
         millis := millis rounded min:dT.
     ].
 
-    self checkForInputWithTimeout:millis
+    self checkForIOWithTimeout:millis
 
     "Modified: 14.12.1995 / 13:37:46 / stefan"
     "Modified: 18.7.1996 / 20:42:17 / cg"
@@ -3239,7 +3255,7 @@
 !ProcessorScheduler class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libbasic/ProcessorScheduler.st,v 1.211 2003-07-12 08:25:04 stefan Exp $'
+    ^ '$Header: /cvs/stx/stx/libbasic/ProcessorScheduler.st,v 1.212 2003-07-15 14:03:17 cg Exp $'
 ! !
 
 ProcessorScheduler initialize!
--- a/UnixOperatingSystem.st	Tue Jul 15 14:19:45 2003 +0200
+++ b/UnixOperatingSystem.st	Tue Jul 15 16:03:28 2003 +0200
@@ -9050,25 +9050,32 @@
 !
 
 selectOnAnyReadable:readFdArray writable:writeFdArray exception:exceptFdArray 
-        into:resultFdArray 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..
+        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 filedescriptors which are ready are returned in resultArray.
-
-     Return the number of selected filedescriptors"
+     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."
 
 %{
     fd_set rset, wset, eset;
     struct timeval wt, et;
-    int f, maxF, i, lX, bX;
+    int maxF;
     INT t;
-    OBJ fd, retFd;
     int ret;
-    int count, resultCount;
+    int cntR = 0, cntW = 0, cntE = 0;
+    int resultSizeReadable = 0, resultSizeWritable = 0, resultSizeException = 0;
     int numFds = 0;
 #ifndef __isArrayLike
 # define __isArrayLike __isArray
@@ -9077,10 +9084,25 @@
     if (!__isSmallInteger(millis)) {
         goto fail;
     }
-    if (! __isArrayLike(resultFdArray)) {
-        goto fail;    
-    }
-    resultCount = __arraySize(resultFdArray);
+
+    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);
+    }
 
     FD_ZERO(&rset);
     FD_ZERO(&wset);
@@ -9088,12 +9110,16 @@
 
     maxF = -1;
     if (__isNonNilObject(readFdArray)) {
+        int i, count;
+
         if (! __isArrayLike(readFdArray)) {
             goto fail;    
         }
         count = __arraySize(readFdArray);
 
         for (i=0; i<count;i++) {
+            OBJ fd;
+
             fd = __ArrayInstPtr(readFdArray)->a_element[i];
             if (fd != nil) {
                 if (! __isSmallInteger(fd)) {
@@ -9101,6 +9127,8 @@
                         fprintf(stderr, "[OS] warning: funny read-fd (0x%x) given to select\n", fd);
                     }
                 } else {
+                    int f;
+
                     f = __intVal(fd);
                     if ((unsigned)f < FD_SETSIZE) {
                         FD_SET(f, &rset);
@@ -9117,11 +9145,15 @@
     }
 
     if (__isNonNilObject(writeFdArray)) {
+        int i, count;
+
         if (! __isArrayLike(writeFdArray)) {
             goto fail;    
         }
         count = __arraySize(writeFdArray);
         for (i=0; i<count;i++) {
+            OBJ fd;
+
             fd = __ArrayInstPtr(writeFdArray)->a_element[i];
             if (fd != nil) {
                 if (! __isSmallInteger(fd)) {
@@ -9129,6 +9161,8 @@
                         fprintf(stderr, "[OS] warning: funny write-fd (0x%x) given to select\n", fd);
                     }
                 } else {
+                    int f;
+
                     f = __intVal(fd);
                     if ((unsigned)f < FD_SETSIZE) {
                         FD_SET(f, &wset);       
@@ -9145,11 +9179,15 @@
     }
 
     if (__isNonNilObject(exceptFdArray)) {
+        int i, count;
+
         if (! __isArrayLike(exceptFdArray)) {
             goto fail;    
         }
         count = __arraySize(exceptFdArray);
         for (i=0; i<count;i++) {
+            OBJ fd;
+
             fd = __ArrayInstPtr(exceptFdArray)->a_element[i];
             if (fd != nil) {
                 if (! __isSmallInteger(fd)) {
@@ -9157,6 +9195,8 @@
                         fprintf(stderr, "[OS] warning: funny except-fd (0x%x) given to select\n", fd);
                     }
                 } else {
+                    int f;
+
                     f = __intVal(fd);
                     if ((unsigned)f < FD_SETSIZE) {
                         FD_SET(f, &eset);       
@@ -9208,20 +9248,45 @@
     __END_INTERRUPTABLE__
 
     if (ret > 0) {
-        int cnt = 0;
-        OBJ *__result = __arrayVal(resultFdArray);
+        OBJ *__resultR = __arrayVal(readableResultFdArray);
+        OBJ *__resultW = __arrayVal(writableResultFdArray);
+        OBJ *__resultE = __arrayVal(exceptionResultFdArray);
+        int i;
 
         for (i=0; i <= maxF; i++) {
-            if (FD_ISSET(i, &rset)
-             || FD_ISSET(i, &wset)
-             || FD_ISSET(i, &eset)) {
-                if (cnt < resultCount) {
-                    __result[cnt] = __MKSMALLINT(i);
+            if (FD_ISSET(i, &rset)) {
+                if (cntR < resultSizeReadable) {
+                    __resultR[cntR] = __MKSMALLINT(i);
                 }
-                cnt++;
+                cntR++;
+            }
+
+            if (FD_ISSET(i, &wset)) {
+                if (cntW < resultSizeWritable) {
+                    __resultW[cntW] = __MKSMALLINT(i);
+                }
+                cntW++;
+            }
+
+            if (FD_ISSET(i, &eset)) {
+                if (cntE < resultSizeException) {
+                    __resultE[cntE] = __MKSMALLINT(i);
+                }
+                cntE++;
             }
         }
-        RETURN (__MKSMALLINT(cnt));
+        /* add a delimiter */
+        if (cntR < resultSizeReadable) {
+            __resultR[cntR] = nil;
+        }
+        if (cntW < resultSizeWritable) {
+            __resultW[cntW] = nil;
+        }
+        if (cntE < resultSizeException) {
+            __resultE[cntE] = nil;
+        }
+        
+        RETURN (__MKSMALLINT(cntR+cntW+cntE));
     } else {
         if (ret < 0) {
             if (errno == EINTR) {
@@ -9242,8 +9307,6 @@
      * Return 0 (no filedescriptor ready)
      */
     RETURN (__MKSMALLINT(0));
-
-
 fail: ;
 %}.
     "
@@ -9255,13 +9318,13 @@
 !
 
 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 
-     arrive exceptional data (i.e. out-of-band data).
+    "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).
-     Return first ready fd if I/O ok, nil if timed-out or interrupted."
+     Return the first ready fd if I/O ok, nil if timed-out or interrupted."
 
 %{
     fd_set rset, wset, eset;
@@ -9277,159 +9340,159 @@
 #endif
 
     if (__isSmallInteger(millis)) {
-	FD_ZERO(&rset);
-	FD_ZERO(&wset);
-	FD_ZERO(&eset);
-
-	maxF = -1;
-	if (__isNonNilObject(readFdArray)) {
-	    if (! __isArrayLike(readFdArray)) {
-		goto fail;    
-	    }
-	    count = __arraySize(readFdArray);
-
-	    for (i=0; i<count;i++) {
-		fd = __ArrayInstPtr(readFdArray)->a_element[i];
-		if (fd != nil) {
-		    if (! __isSmallInteger(fd)) {
-			if (@global(InfoPrinting) == true) {
-			    fprintf(stderr, "[OS] warning: funny read-fd (0x%x) given to select\n", fd);
-			}
-		    } else {
-			f = __intVal(fd);
-			if ((unsigned)f < FD_SETSIZE) {
-			    FD_SET(f, &rset);
-			    if (f > maxF) maxF = f;
-			    numFds++;
-			} else {
-			    if (@global(InfoPrinting) == true) {
-				fprintf(stderr, "[OS] warning: huge read-fd (0x%x) given to select\n", fd);
-			    }
-			}
-		    }
-		}
-	    }
-	}
-
-	if (__isNonNilObject(writeFdArray)) {
-	    if (! __isArrayLike(writeFdArray)) {
-		goto fail;    
-	    }
-	    count = __arraySize(writeFdArray);
-	    for (i=0; i<count;i++) {
-		fd = __ArrayInstPtr(writeFdArray)->a_element[i];
-		if (fd != nil) {
-		    if (! __isSmallInteger(fd)) {
-			if (@global(InfoPrinting) == true) {
-			    fprintf(stderr, "[OS] warning: funny write-fd (0x%x) given to select\n", fd);
-			}
-		    } else {
-			f = __intVal(fd);
-			if ((unsigned)f < FD_SETSIZE) {
-			    FD_SET(f, &wset);       
-			    if (f > maxF) maxF = f;
-			    numFds++;
-			} else {
-			    if (@global(InfoPrinting) == true) {
-				fprintf(stderr, "[OS] warning: huge write-fd (0x%x) given to select\n", fd);
-			    }
-			}
-		    }
-		}
-	    }
-	}
-
-	if (__isNonNilObject(exceptFdArray)) {
-	    if (! __isArrayLike(exceptFdArray)) {
-		goto fail;    
-	    }
-	    count = __arraySize(exceptFdArray);
-	    for (i=0; i<count;i++) {
-		fd = __ArrayInstPtr(exceptFdArray)->a_element[i];
-		if (fd != nil) {
-		    if (! __isSmallInteger(fd)) {
-			if (@global(InfoPrinting) == true) {
-			    fprintf(stderr, "[OS] warning: funny except-fd (0x%x) given to select\n", fd);
-			}
-		    } else {
-			f = __intVal(fd);
-			if ((unsigned)f < FD_SETSIZE) {
-			    FD_SET(f, &eset);       
-			    if (f > maxF) maxF = f;
-			    numFds++;
-			} else {
-			    if (@global(InfoPrinting) == true) {
-				fprintf(stderr, "[OS] warning: huge except-fd (0x%x) given to select\n", fd);
-			    }
-			}
-		    }
-		}
-	    }
-	}
-
-	t = __intVal(millis);
-	if (t) {
-	    wt.tv_sec = t / 1000;
-	    wt.tv_usec = (t % 1000) * 1000;
-	} else {
-	    wt.tv_sec = wt.tv_usec = 0;
-	}
-
-	/*
-	 * make certain, that interrupt gets us out of the select
-	 * However, we must then care for moved objects.
-	 */
-	__BEGIN_INTERRUPTABLE__
-	errno = 0;
-
-	if (t == 0) {
-	    /* 
-	     * if there is no timeout time, we can stay here interruptable.
-	     */
-	    do {
-		ret = select(maxF+1, &rset, &wset, &eset, &wt);
-	    } while ((ret < 0) && (errno == EINTR));
-	} else {
-	    do {
-		ret = select(maxF+1, &rset, &wset, &eset, &wt);
-		/* 
-		 * for now: dont loop; if we did, we had to adjust the vt-timeval;
-		 * could otherwise stay in this loop forever ...
-		 * Premature ret (before the time expired) must be handled by the caller.
-		 * A good solution is to update the wt-timeval and redo the select.
-		 */
-	    } while (0 /* (ret < 0) && (errno == EINTR) */ );
-	}
-	__END_INTERRUPTABLE__
-
-	if (ret > 0) {
-	    for (i=0; i <= maxF; i++) {
-		if (FD_ISSET(i, &rset)
-		 || FD_ISSET(i, &wset)
-		 || FD_ISSET(i, &eset)) {
-		    RETURN ( __MKSMALLINT(i) );
-		}
-	    }
-	} else {
-	    if (ret < 0) {
-		if (errno == EINTR) {
-		    errno = 0;
-		    @global(LastErrorNumber) = nil;
-		} else {
-		    if (@global(InfoPrinting) == true) {
-			fprintf(stderr, "OS [info]: select errno = %d\n", errno);
-		    }
-		    @global(LastErrorNumber) = __MKSMALLINT(errno);
-		}
-	    } else {
-		@global(LastErrorNumber) = nil;
-	    }
-	}
-
-	/*
-	 * Return nil (means time expired or interrupted)
-	 */
-	RETURN ( nil );
+        FD_ZERO(&rset);
+        FD_ZERO(&wset);
+        FD_ZERO(&eset);
+
+        maxF = -1;
+        if (__isNonNilObject(readFdArray)) {
+            if (! __isArrayLike(readFdArray)) {
+                goto fail;    
+            }
+            count = __arraySize(readFdArray);
+
+            for (i=0; i<count;i++) {
+                fd = __ArrayInstPtr(readFdArray)->a_element[i];
+                if (fd != nil) {
+                    if (! __isSmallInteger(fd)) {
+                        if (@global(InfoPrinting) == true) {
+                            fprintf(stderr, "[OS] warning: funny read-fd (0x%x) given to select\n", fd);
+                        }
+                    } else {
+                        f = __intVal(fd);
+                        if ((unsigned)f < FD_SETSIZE) {
+                            FD_SET(f, &rset);
+                            if (f > maxF) maxF = f;
+                            numFds++;
+                        } else {
+                            if (@global(InfoPrinting) == true) {
+                                fprintf(stderr, "[OS] warning: huge read-fd (0x%x) given to select\n", fd);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        if (__isNonNilObject(writeFdArray)) {
+            if (! __isArrayLike(writeFdArray)) {
+                goto fail;    
+            }
+            count = __arraySize(writeFdArray);
+            for (i=0; i<count;i++) {
+                fd = __ArrayInstPtr(writeFdArray)->a_element[i];
+                if (fd != nil) {
+                    if (! __isSmallInteger(fd)) {
+                        if (@global(InfoPrinting) == true) {
+                            fprintf(stderr, "[OS] warning: funny write-fd (0x%x) given to select\n", fd);
+                        }
+                    } else {
+                        f = __intVal(fd);
+                        if ((unsigned)f < FD_SETSIZE) {
+                            FD_SET(f, &wset);       
+                            if (f > maxF) maxF = f;
+                            numFds++;
+                        } else {
+                            if (@global(InfoPrinting) == true) {
+                                fprintf(stderr, "[OS] warning: huge write-fd (0x%x) given to select\n", fd);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        if (__isNonNilObject(exceptFdArray)) {
+            if (! __isArrayLike(exceptFdArray)) {
+                goto fail;    
+            }
+            count = __arraySize(exceptFdArray);
+            for (i=0; i<count;i++) {
+                fd = __ArrayInstPtr(exceptFdArray)->a_element[i];
+                if (fd != nil) {
+                    if (! __isSmallInteger(fd)) {
+                        if (@global(InfoPrinting) == true) {
+                            fprintf(stderr, "[OS] warning: funny except-fd (0x%x) given to select\n", fd);
+                        }
+                    } else {
+                        f = __intVal(fd);
+                        if ((unsigned)f < FD_SETSIZE) {
+                            FD_SET(f, &eset);       
+                            if (f > maxF) maxF = f;
+                            numFds++;
+                        } else {
+                            if (@global(InfoPrinting) == true) {
+                                fprintf(stderr, "[OS] warning: huge except-fd (0x%x) given to select\n", fd);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        t = __intVal(millis);
+        if (t) {
+            wt.tv_sec = t / 1000;
+            wt.tv_usec = (t % 1000) * 1000;
+        } else {
+            wt.tv_sec = wt.tv_usec = 0;
+        }
+
+        /*
+         * make certain, that interrupt gets us out of the select
+         * However, we must then care for moved objects.
+         */
+        __BEGIN_INTERRUPTABLE__
+        errno = 0;
+
+        if (t == 0) {
+            /* 
+             * if there is no timeout time, we can stay here interruptable.
+             */
+            do {
+                ret = select(maxF+1, &rset, &wset, &eset, &wt);
+            } while ((ret < 0) && (errno == EINTR));
+        } else {
+            do {
+                ret = select(maxF+1, &rset, &wset, &eset, &wt);
+                /* 
+                 * for now: dont loop; if we did, we had to adjust the vt-timeval;
+                 * could otherwise stay in this loop forever ...
+                 * Premature ret (before the time expired) must be handled by the caller.
+                 * A good solution is to update the wt-timeval and redo the select.
+                 */
+            } while (0 /* (ret < 0) && (errno == EINTR) */ );
+        }
+        __END_INTERRUPTABLE__
+
+        if (ret > 0) {
+            for (i=0; i <= maxF; i++) {
+                if (FD_ISSET(i, &rset)
+                 || FD_ISSET(i, &wset)
+                 || FD_ISSET(i, &eset)) {
+                    RETURN ( __MKSMALLINT(i) );
+                }
+            }
+        } else {
+            if (ret < 0) {
+                if (errno == EINTR) {
+                    errno = 0;
+                    @global(LastErrorNumber) = nil;
+                } else {
+                    if (@global(InfoPrinting) == true) {
+                        fprintf(stderr, "OS [info]: select errno = %d\n", errno);
+                    }
+                    @global(LastErrorNumber) = __MKSMALLINT(errno);
+                }
+            } else {
+                @global(LastErrorNumber) = nil;
+            }
+        }
+
+        /*
+         * Return nil (means time expired or interrupted)
+         */
+        RETURN ( nil );
     }
 
 fail: ;
@@ -12152,7 +12215,7 @@
 !UnixOperatingSystem class methodsFor:'documentation'!
 
 version
-    ^ '$Header: /cvs/stx/stx/libbasic/UnixOperatingSystem.st,v 1.174 2003-07-15 12:19:45 cg Exp $'
+    ^ '$Header: /cvs/stx/stx/libbasic/UnixOperatingSystem.st,v 1.175 2003-07-15 14:03:04 cg Exp $'
 ! !
 
 UnixOperatingSystem initialize!