X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=ghc%2Frts%2FSelect.c;h=418e48cb7a3dfcae7ce7a7a6e64d80542c0b8388;hb=fa9a03c15ad5ba9f05b90026031933da10a08fd8;hp=644bb41035f18ce2cd82e858c5a7b8f97f4ee958;hpb=6339f4b081ea645bbba52d2c8a2dd38713b9ef2a;p=ghc-hetmet.git diff --git a/ghc/rts/Select.c b/ghc/rts/Select.c index 644bb41..418e48c 100644 --- a/ghc/rts/Select.c +++ b/ghc/rts/Select.c @@ -1,21 +1,23 @@ /* ----------------------------------------------------------------------------- - * $Id: Select.c,v 1.15 2001/02/27 12:43:45 rrt 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" #include "RtsUtils.h" #include "RtsFlags.h" +#include "Timer.h" #include "Itimer.h" #include "Signals.h" +#include "Capability.h" # ifdef HAVE_SYS_TYPES_H # include @@ -25,19 +27,16 @@ # include # endif -# ifdef mingw32_TARGET_OS -# include -# endif +#include +#include + +#ifdef HAVE_UNISTD_H +#include +#endif /* 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 @@ -61,7 +60,7 @@ wakeUpSleepingThreads(nat ticks) sleeping_queue = tso->link; tso->why_blocked = NotBlocked; tso->link = END_TSO_QUEUE; - IF_DEBUG(scheduler,belch("Waking up sleeping thread %d\n", tso->id)); + IF_DEBUG(scheduler,debugBelch("Waking up sleeping thread %d\n", tso->id)); PUSH_ON_RUN_QUEUE(tso); flag = rtsTrue; } @@ -87,23 +86,22 @@ awaitEvent(rtsBool wait) 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"); + debugBelch("scheduler: checking for threads blocked on I/O"); if (wait) { - belch(" (waiting)"); + debugBelch(" (waiting)"); } - belch("\n"); + debugBelch("\n"); ); /* loop until we've woken up some threads. This loop is needed @@ -114,7 +112,6 @@ awaitEvent(rtsBool wait) do { ticks = timestamp = getourtimeofday(); - ticks_since_timestamp = 0; if (wakeUpSleepingThreads(ticks)) { return; } @@ -128,7 +125,6 @@ awaitEvent(rtsBool wait) min = 0x7ffffff; } -#ifndef mingw32_TARGET_OS /* * Collect all of the fd's that we're interested in */ @@ -160,20 +156,6 @@ awaitEvent(rtsBool wait) } } - /* Release the scheduler lock while we do the poll. - * this means that someone might muck with the blocked_queue - * while we do this, but it shouldn't matter: - * - * - another task might poll for I/O and remove one - * or more threads from the blocked_queue. - * - more I/O threads may be added to blocked_queue. - * - more delayed threads may be added to blocked_queue. We'll - * just subtract delta from their delays after the poll. - * - * I believe none of these cases lead to trouble --SDM. - */ - RELEASE_LOCK(&sched_mutex); - /* Check for any interesting events */ tv.tv_sec = min / 1000000; @@ -181,28 +163,40 @@ awaitEvent(rtsBool wait) while ((numFound = select(maxfd+1, &rfd, &wfd, NULL, &tv)) < 0) { if (errno != EINTR) { - - printf("%d\n", errno); - 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 { + 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 * serviced. */ +#if defined(RTS_USER_SIGNALS) if (signals_pending()) { - RELEASE_LOCK(&sched_mutex); /* ToDo: kill */ - start_signal_handlers(); - ACQUIRE_LOCK(&sched_mutex); + startSignalHandlers(); return; /* still hold the lock */ } #endif @@ -223,33 +217,29 @@ awaitEvent(rtsBool wait) if (run_queue_hd != END_TSO_QUEUE) { return; /* still hold the lock */ } - - RELEASE_LOCK(&sched_mutex); } - ACQUIRE_LOCK(&sched_mutex); - /* Step through the waiting queue, unblocking every thread that now has * a file descriptor in a ready state. */ 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"); } if (ready) { - IF_DEBUG(scheduler,belch("Waking up blocked thread %d\n", tso->id)); + IF_DEBUG(scheduler,debugBelch("Waking up blocked thread %d\n", tso->id)); tso->why_blocked = NotBlocked; tso->link = END_TSO_QUEUE; PUSH_ON_RUN_QUEUE(tso); @@ -269,6 +259,6 @@ awaitEvent(rtsBool wait) blocked_queue_tl = prev; } } - + } while (wait && !interrupted && run_queue_hd == END_TSO_QUEUE); }