--- a/DirectoryStream.st Mon Feb 13 21:29:46 2017 +0000
+++ b/DirectoryStream.st Thu May 04 15:31:33 2017 +0200
@@ -579,10 +579,17 @@
hitEOF := false.
%{
+ enum {
+ PASS_INITIAL = 1,
+ PASS_RETRY_AFTER_SCAVENGE = 2,
+ PASS_RETRY_AFTER_GARBAGE_COLLECT = 3,
+ PASS_FINAL = PASS_RETRY_AFTER_GARBAGE_COLLECT
+ } pass = PASS_INITIAL;
#ifdef HAS_OPENDIR
DIR *d;
OBJ path, dp;
+retry:
ok = false;
if (__INST(dirPointer) == nil) {
if (__isStringLike(encodedPathName)) {
@@ -614,6 +621,7 @@
WIN32_FIND_DATAW wdata;
} uD;
+retry:
ok = false;
if (__INST(dirPointer) == nil) {
path = __INST(pathName);
@@ -681,6 +689,32 @@
}
#endif
#endif
+ /*
+ * If no filedescriptors available, try to finalize
+ * possibly collected fd's and try again.
+ */
+ if ((__threadErrno == ENFILE || __threadErrno == EMFILE) && pass < PASS_FINAL) {
+ switch (pass) {
+ case PASS_INITIAL:
+ {
+ pass = PASS_RETRY_AFTER_SCAVENGE;
+ __SSEND0(@global(ObjectMemory), @symbol(scavenge), 0);
+ __SSEND0(@global(ObjectMemory), @symbol(finalize), 0);
+ }
+ goto retry;
+ case PASS_RETRY_AFTER_SCAVENGE:
+ {
+ pass = PASS_RETRY_AFTER_GARBAGE_COLLECT;
+ __SSEND0(@global(ObjectMemory), @symbol(garbageCollect), 0);
+ __SSEND0(@global(ObjectMemory), @symbol(finalize), 0);
+ }
+ goto retry;
+ case PASS_RETRY_AFTER_GARBAGE_COLLECT:
+ /* Should never be reached */
+ goto getOutOfHere;
+ }
+ }
+ getOutOfHere:;
%}.
ok == true ifTrue:[
--- a/FileStream.st Mon Feb 13 21:29:46 2017 +0000
+++ b/FileStream.st Thu May 04 15:31:33 2017 +0200
@@ -1363,7 +1363,12 @@
%{
HFILE f = NULL;
- int pass = 0;
+ enum {
+ PASS_INITIAL = 1,
+ PASS_RETRY_AFTER_SCAVENGE = 2,
+ PASS_RETRY_AFTER_GARBAGE_COLLECT = 3,
+ PASS_FINAL = PASS_RETRY_AFTER_GARBAGE_COLLECT
+ } pass = PASS_INITIAL;
if (!__isNonNilObject(encodedPathName)
|| !(__isStringLike(openmode) || __isArrayLike(openmode)))
@@ -1742,11 +1747,26 @@
* If no filedescriptors available, try to finalize
* possibly collected fd's and try again.
*/
- if ((__threadErrno == ENFILE || __threadErrno == EMFILE) && pass == 0) {
- pass = 1;
- __SSEND0(@global(ObjectMemory), @symbol(scavenge), 0);
- __SSEND0(@global(ObjectMemory), @symbol(finalize), 0);
- goto retry;
+ if ((__threadErrno == ENFILE || __threadErrno == EMFILE) && pass < PASS_FINAL) {
+ switch (pass) {
+ case PASS_INITIAL:
+ {
+ pass = PASS_RETRY_AFTER_SCAVENGE;
+ __SSEND0(@global(ObjectMemory), @symbol(scavenge), 0);
+ __SSEND0(@global(ObjectMemory), @symbol(finalize), 0);
+ }
+ goto retry;
+ case PASS_RETRY_AFTER_SCAVENGE:
+ {
+ pass = PASS_RETRY_AFTER_GARBAGE_COLLECT;
+ __SSEND0(@global(ObjectMemory), @symbol(garbageCollect), 0);
+ __SSEND0(@global(ObjectMemory), @symbol(finalize), 0);
+ }
+ goto retry;
+ case PASS_RETRY_AFTER_GARBAGE_COLLECT:
+ /* Should never be reached */
+ goto getOutOfHere;
+ }
}
badArgument:
getOutOfHere:
--- a/ProcessorScheduler.st Mon Feb 13 21:29:46 2017 +0000
+++ b/ProcessorScheduler.st Thu May 04 15:31:33 2017 +0200
@@ -1208,7 +1208,7 @@
status of the OS process changes (e.g. the process terminates).
The method returns the value from aBlockReturningPid (i.e. a pid or nil)."
- |pid wasBlocked exitStatus|
+ |pid wasBlocked|
"/ aBlock will be evaluated:
"/ on unix: as soon as a SIGCHLD interrupt for pid has been received.
@@ -1219,14 +1219,7 @@
"/ start the OS-Process
pid := aBlockReturningPid value.
pid notNil ifTrue:[
- osChildExitActions at:pid put:actionBlock.
- ].
- "check for a race, that SIGCHILD was received before we could register the actionBlock"
- exitStatus := OperatingSystem childProcessWait:false pid:pid.
- exitStatus notNil ifTrue:[
- self unmonitorPid:pid.
- wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
- actionBlock value:exitStatus.
+ osChildExitActions at:pid put:actionBlock.
].
wasBlocked ifFalse:[OperatingSystem unblockInterrupts].
^ pid
--- a/Win32OperatingSystem.st Mon Feb 13 21:29:46 2017 +0000
+++ b/Win32OperatingSystem.st Thu May 04 15:31:33 2017 +0200
@@ -12033,7 +12033,10 @@
//#define SELECTDEBUGWIN32
//#define SELECT3DEBUGWIN32
#define MAXHANDLE 128
- int i;
+ int i, idx;
+ INT t;
+ int numHandles;
+ DWORD res;
HANDLE hArray[MAXHANDLE+1];
int retArray[MAXHANDLE];
int readCount, writeCount, exceptCount;
@@ -12043,7 +12046,8 @@
fd_set readFds;
fd_set writeFds;
fd_set exceptFds;
- int numHandles, numSockets, numPipes;
+ int hasSockets;
+ int hasPipes;
int pass = 1; // perform up to 2 passes
if (readableResultFdArray != nil) {
@@ -12100,7 +12104,7 @@
FD_ZERO(&readFds);
FD_ZERO(&writeFds);
FD_ZERO(&exceptFds);
- numHandles = numSockets = numPipes = 0;
+ numHandles = hasSockets = hasPipes = 0;
for (i = 0; (i < readCount) && (numHandles < MAXHANDLE); i++) {
OBJ fd = __arrayVal(readFdArray)[i];
@@ -12108,7 +12112,7 @@
if (fd != nil) {
if (__Class(fd) == @global(Win32SocketHandle)) {
FD_SET (_HANDLEVal(fd), &readFds);
- numSockets++;
+ hasSockets++;
} else if (__isSmallInteger(fd)) {
DWORD canRead;
if (PeekNamedPipe(_get_osfhandle(__intVal(fd)), 0, 0, 0, &canRead, 0)) {
@@ -12122,7 +12126,7 @@
@global(LastErrorNumber) = __mkSmallInteger(EBADF);
RETURN (__mkSmallInteger(-1));
}
- numPipes++;
+ hasPipes++;
} else {
hArray [numHandles] = _HANDLEVal(fd);
retArray[numHandles] = i;
@@ -12137,7 +12141,7 @@
if (fd != nil) {
if (__Class(fd) == @global(Win32SocketHandle)) {
FD_SET (_HANDLEVal(fd), &writeFds);
- numSockets++;
+ hasSockets++;
} else if (__isSmallInteger(fd)) {
// kludge: assume that pipes can alway be written
if (*pcntW < resultSizeWritable) {
@@ -12159,7 +12163,7 @@
if (fdOrPid != nil) {
if (__Class(fdOrPid) == @global(Win32SocketHandle)) {
FD_SET (_HANDLEVal(fdOrPid), &exceptFds);
- numSockets++;
+ hasSockets++;
} else if (__isExternalAddressLike(fdOrPid)) {
// a PID
hArray [numHandles] = _HANDLEVal(fdOrPid);
@@ -12169,37 +12173,96 @@
}
}
- // +++++ 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
+ 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)) {
+ } 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;
+ }
#ifdef SELECT3DEBUGWIN32
console_printf("wait numhandles = %d timeout = %d\n", numHandles, t);
#endif
- res = __vmWait(numHandles, hArray, MAXHANDLE, (int)t);
+ res = __vmWait(numHandles, hArray, MAXHANDLE, t);
if (res == WAIT_TIMEOUT) {
#ifdef SELECT3DEBUGWIN32
- console_printf("- timeOut" );
-#endif
- goto checkSockets;
- }
- if (res == __WAIT_INTERRUPTED) {
-#ifdef SELECT3DEBUGWIN32
- console_printf("- interrupted\n" );
-#endif
+ 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;
}
@@ -12220,15 +12283,18 @@
}
}
- if ((res < 0) || (res >= numHandles)) {
+ 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");
}
- } else {
- console_printf("- res=%d error1 %d\n", res, GetLastError());
- }
+ goto done;
+ }
+ if ((res < 0) || (res >= numHandles)) {
+#ifdef SELECTDEBUGWIN32
+ console_printf("- res=%d error1 %d\n", res, GetLastError());
+#endif
goto done;
}
@@ -12274,81 +12340,11 @@
#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("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
+ if (t != 0 && (hasSockets || hasPipes)) {
+ // back after timeout, maybe some sockets or pipes did wake up
// in the meantime?
pass = 2;
goto pollAgain;
- }
}
done:
@@ -12374,8 +12370,6 @@
or not supported by OS
"
^ self primitiveFailed
-
- "Modified: / 15-01-2017 / 03:04:41 / stefan"
!
setBlocking:aBoolean on:fd