X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=ghc%2Frts%2FSelect.c;h=dc19cbfa635c676fac8e45edfe4b3fdb6ff76b4f;hb=73641e01ee9dfbe83f8c6225c1f6ae2e7d621b63;hp=486ccbaccc0139a3ca21e027f26e705b136c793a;hpb=5a4ec9379ff8e96ab7a75ea1854bf2005db01050;p=ghc-hetmet.git diff --git a/ghc/rts/Select.c b/ghc/rts/Select.c index 486ccba..dc19cbf 100644 --- a/ghc/rts/Select.c +++ b/ghc/rts/Select.c @@ -1,14 +1,14 @@ /* ----------------------------------------------------------------------------- - * $Id: Select.c,v 1.14 2000/08/25 13:12:07 simonmar Exp $ + * $Id: Select.c,v 1.22 2002/07/24 03:38:58 sof Exp $ * - * (c) The GHC Team 1995-1999 + * (c) The GHC Team 1995-2002 * * Support for concurrent non-blocking I/O and thread waiting. * * ---------------------------------------------------------------------------*/ /* we're outside the realms of POSIX here... */ -#define NON_POSIX_SOURCE +/* #include "PosixSource.h" */ #include "Rts.h" #include "Schedule.h" @@ -17,7 +17,7 @@ #include "Itimer.h" #include "Signals.h" -# if defined(HAVE_SYS_TYPES_H) +# ifdef HAVE_SYS_TYPES_H # include # endif @@ -25,15 +25,16 @@ # include # endif +# ifdef mingw32_TARGET_OS +# include +# endif + +#include +#include + /* last timestamp */ nat timestamp = 0; -/* keep track of the number of ticks since we last called - * gettimeofday(), to avoid having to call it every time we need - * a timestamp. - */ -nat ticks_since_timestamp = 0; - /* There's a clever trick here to avoid problems when the time wraps * around. Since our maximum delay is smaller than 31 bits of ticks * (it's actually 31 bits of microseconds), we can safely check @@ -70,31 +71,31 @@ wakeUpSleepingThreads(nat ticks) * otherwise we wait (see Schedule.c). * * SMP note: must be called with sched_mutex locked. + * + * Windows: select only works on sockets, so this doesn't really work, + * though it makes things better than before. MsgWaitForMultipleObjects + * should really be used, though it only seems to work for read handles, + * not write handles. + * */ void awaitEvent(rtsBool wait) { -#ifdef mingw32_TARGET_OS -/* - * Win32 doesn't support select(). ToDo: use MsgWaitForMultipleObjects() - * to achieve (similar) effect. - * - */ - return; -#else - StgTSO *tso, *prev, *next; rtsBool ready; fd_set rfd,wfd; +#ifndef mingw32_TARGET_OS int numFound; int maxfd = -1; +#endif rtsBool select_succeeded = rtsTrue; + rtsBool unblock_all = rtsFalse; struct timeval tv; lnat min, ticks; tv.tv_sec = 0; tv.tv_usec = 0; - + IF_DEBUG(scheduler, belch("scheduler: checking for threads blocked on I/O"); if (wait) { @@ -111,7 +112,6 @@ awaitEvent(rtsBool wait) do { ticks = timestamp = getourtimeofday(); - ticks_since_timestamp = 0; if (wakeUpSleepingThreads(ticks)) { return; } @@ -125,6 +125,7 @@ awaitEvent(rtsBool wait) min = 0x7ffffff; } +#ifndef mingw32_TARGET_OS /* * Collect all of the fd's that we're interested in */ @@ -176,14 +177,41 @@ awaitEvent(rtsBool wait) tv.tv_usec = min % 1000000; while ((numFound = select(maxfd+1, &rfd, &wfd, NULL, &tv)) < 0) { - if (errno != EINTR) { - /* fflush(stdout); */ - perror("select"); + /* Handle bad file descriptors by unblocking all the + waiting threads. Why? Because a thread might have been + a bit naughty and closed a file descriptor while another + was blocked waiting. This is less-than-good programming + practice, but having the RTS as a result fall over isn't + acceptable, so we simply unblock all the waiting threads + should we see a bad file descriptor & give the threads + a chance to clean up their act. + + Note: assume here that threads becoming unblocked + will try to read/write the file descriptor before trying + to issue a threadWaitRead/threadWaitWrite again (==> an + IOError will result for the thread that's got the bad + file descriptor.) Hence, there's no danger of a bad + file descriptor being repeatedly select()'ed on, so + the RTS won't loop. + */ + if ( errno == EBADF ) { + unblock_all = rtsTrue; + break; + } else { + fprintf(stderr,"%d\n", errno); + fflush(stderr); + perror("select"); barf("select failed"); + } } +#else /* on mingwin */ + while (1) { + Sleep(0); /* don't busy wait */ +#endif /* mingw32_TARGET_OS */ ACQUIRE_LOCK(&sched_mutex); - + +#ifndef mingw32_TARGET_OS /* We got a signal; could be one of ours. If so, we need * to start up the signal handler straight away, otherwise * we could block for a long time before the signal is @@ -191,11 +219,12 @@ awaitEvent(rtsBool wait) */ if (signals_pending()) { RELEASE_LOCK(&sched_mutex); /* ToDo: kill */ - start_signal_handlers(); + startSignalHandlers(); ACQUIRE_LOCK(&sched_mutex); return; /* still hold the lock */ } - +#endif + /* we were interrupted, return to the scheduler immediately. */ if (interrupted) { @@ -223,15 +252,15 @@ awaitEvent(rtsBool wait) */ prev = NULL; - if (select_succeeded) { + if (select_succeeded || unblock_all) { for(tso = blocked_queue_hd; tso != END_TSO_QUEUE; tso = next) { next = tso->link; switch (tso->why_blocked) { case BlockedOnRead: - ready = FD_ISSET(tso->block_info.fd, &rfd); + ready = unblock_all || FD_ISSET(tso->block_info.fd, &rfd); break; case BlockedOnWrite: - ready = FD_ISSET(tso->block_info.fd, &wfd); + ready = unblock_all || FD_ISSET(tso->block_info.fd, &wfd); break; default: barf("awaitEvent"); @@ -260,5 +289,4 @@ awaitEvent(rtsBool wait) } } while (wait && !interrupted && run_queue_hd == END_TSO_QUEUE); -#endif }