diff --git a/ghc/includes/TSO.h b/ghc/includes/TSO.h
index 282e9c47c3472af881e3f36795dc5232521928ef..509e55f7841c1dd977017f13382b466a58116e69 100644
--- a/ghc/includes/TSO.h
+++ b/ghc/includes/TSO.h
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
- * $Id: TSO.h,v 1.17 2000/08/15 14:18:43 simonmar Exp $
+ * $Id: TSO.h,v 1.18 2000/08/25 13:12:07 simonmar Exp $
  *
  * (c) The GHC Team, 1998-1999
  *
@@ -134,11 +134,7 @@ typedef union {
   StgClosure *closure;
   struct StgTSO_ *tso;
   int fd;
-#if defined(HAVE_SETITIMER) || defined(mingw32_TARGET_OS)
-  unsigned int delay;
-#else
   unsigned int target;
-#endif
 } StgTSOBlockInfo;
 
 /*
diff --git a/ghc/rts/Itimer.c b/ghc/rts/Itimer.c
index c327528e1295903c4b57b1eec81ce5190fc0121c..07d6dcd6fe80e572df9bb10ddf7189aebc15cf0c 100644
--- a/ghc/rts/Itimer.c
+++ b/ghc/rts/Itimer.c
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
- * $Id: Itimer.c,v 1.16 2000/08/03 11:28:35 simonmar Exp $
+ * $Id: Itimer.c,v 1.17 2000/08/25 13:12:07 simonmar Exp $
  *
  * (c) The GHC Team, 1995-1999
  *
@@ -80,8 +80,10 @@ handle_tick(int unused STG_UNUSED)
   handleProfTick();
 #endif
 
-  /* For threadDelay etc., see Select.c */
-  ticks_since_select++;
+  /* so we can get a rough indication of the current time at any point
+   * without having to call gettimeofday() (see Select.c):
+   */
+  ticks_since_timestamp++;
 
   ticks_to_ctxt_switch--;
   if (ticks_to_ctxt_switch <= 0) {
@@ -156,6 +158,9 @@ initialize_virtual_timer(nat ms)
 # else
     struct itimerval it;
 
+    timestamp = getourtimeofday();
+    ticks_since_timestamp = 0;
+
     it.it_value.tv_sec = ms / 1000;
     it.it_value.tv_usec = 1000 * (ms - (1000 * it.it_value.tv_sec));
     it.it_interval = it.it_value;
@@ -174,6 +179,9 @@ initialize_virtual_timer(nat ms)
     struct itimerspec it;
     timer_t tid;
 
+    timestamp = getourtimeofday();
+    ticks_since_timestamp = 0;
+
     se.sigev_notify = SIGEV_SIGNAL;
     se.sigev_signo = SIGVTALRM;
     se.sigev_value.sival_int = SIGVTALRM;
@@ -232,12 +240,14 @@ unblock_vtalrm_signal(void)
 }
 #endif
 
-#if !defined(HAVE_SETITIMER) && !defined(mingw32_TARGET_OS)
+/* gettimeofday() takes around 1us on our 500MHz PIII.  Since we're
+ * only calling it 50 times/s, it shouldn't have any great impact.
+ */
 unsigned int 
 getourtimeofday(void)
 {
   struct timeval tv;
   gettimeofday(&tv, (struct timezone *) NULL);
-  return (tv.tv_sec * 1000000 + tv.tv_usec);
+  return (tv.tv_sec * TICK_FREQUENCY +
+	  tv.tv_usec * TICK_FREQUENCY / 1000000);
 }
-#endif
diff --git a/ghc/rts/Itimer.h b/ghc/rts/Itimer.h
index 257d2748e618cae5307e8455429ca80e2f340d41..2430ec1a3868d584748af059258c5030200bf583 100644
--- a/ghc/rts/Itimer.h
+++ b/ghc/rts/Itimer.h
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
- * $Id: Itimer.h,v 1.6 2000/08/03 11:28:35 simonmar Exp $
+ * $Id: Itimer.h,v 1.7 2000/08/25 13:12:07 simonmar Exp $
  *
  * (c) The GHC Team 1998-1999
  *
@@ -17,6 +17,9 @@
  
 extern rtsBool do_prof_ticks;	/* profiling ticks on/off */
 
+/* Total number of ticks since startup */
+extern lnat total_ticks;
+
 nat  initialize_virtual_timer  ( nat ms );
 int  install_vtalrm_handler    ( void );
 void block_vtalrm_signal       ( void );
diff --git a/ghc/rts/PrimOps.hc b/ghc/rts/PrimOps.hc
index 015e34a228b267e8e1555c5645dbbf8084c63ef0..74575d7a3efd5c7282683b1ac7b0910e9b9a7804 100644
--- a/ghc/rts/PrimOps.hc
+++ b/ghc/rts/PrimOps.hc
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
- * $Id: PrimOps.hc,v 1.53 2000/08/07 23:37:23 qrczak Exp $
+ * $Id: PrimOps.hc,v 1.54 2000/08/25 13:12:07 simonmar Exp $
  *
  * (c) The GHC Team, 1998-2000
  *
@@ -1049,6 +1049,8 @@ FN_(waitWritezh_fast)
 
 FN_(delayzh_fast)
 {
+  StgTSO *t, *prev;
+  nat target;
   FB_
     /* args: R1.i */
     ASSERT(CurrentTSO->why_blocked == NotBlocked);
@@ -1056,20 +1058,26 @@ FN_(delayzh_fast)
 
     ACQUIRE_LOCK(&sched_mutex);
 
-    /* Add on ticks_since_select, since these will be subtracted at
-     * the next awaitEvent call.
-     */
-#if defined(HAVE_SETITIMER) || defined(mingw32_TARGET_OS)
-    CurrentTSO->block_info.delay = R1.i + ticks_since_select;
-#else
-    CurrentTSO->block_info.target = R1.i + getourtimeofday();
-#endif
+    target = (R1.i / (TICK_MILLISECS*1000)) + timestamp + ticks_since_timestamp;
+    CurrentTSO->block_info.target = target;
 
-    APPEND_TO_BLOCKED_QUEUE(CurrentTSO);
+    /* Insert the new thread in the sleeping queue. */
+    prev = NULL;
+    t = sleeping_queue;
+    while (t != END_TSO_QUEUE && t->block_info.target < target) {
+	prev = t;
+	t = t->link;
+    }
+
+    CurrentTSO->link = t;
+    if (prev == NULL) {
+	sleeping_queue = CurrentTSO;
+    } else {
+	prev->link = CurrentTSO;
+    }
 
     RELEASE_LOCK(&sched_mutex);
     JMP_(stg_block_noregs);
   FE_
 }
 
-
diff --git a/ghc/rts/Schedule.c b/ghc/rts/Schedule.c
index eaf4d45e5596840eff7a12da5792d95eef1188ce..786015cea28e4c7f38918bd1ed5ae87ca055f5ed 100644
--- a/ghc/rts/Schedule.c
+++ b/ghc/rts/Schedule.c
@@ -1,5 +1,5 @@
 /* ---------------------------------------------------------------------------
- * $Id: Schedule.c,v 1.77 2000/08/23 12:51:03 simonmar Exp $
+ * $Id: Schedule.c,v 1.78 2000/08/25 13:12:07 simonmar Exp $
  *
  * (c) The GHC Team, 1998-2000
  *
@@ -144,6 +144,7 @@ StgTSO *ccalling_threadss[MAX_PROC];
 
 StgTSO *run_queue_hd, *run_queue_tl;
 StgTSO *blocked_queue_hd, *blocked_queue_tl;
+StgTSO *sleeping_queue;		/* perhaps replace with a hash table? */
 
 #endif
 
@@ -379,14 +380,7 @@ schedule( void )
      */
     if (interrupted) {
       IF_DEBUG(scheduler, sched_belch("interrupted"));
-      for (t = run_queue_hd; t != END_TSO_QUEUE; t = t->link) {
-	deleteThread(t);
-      }
-      for (t = blocked_queue_hd; t != END_TSO_QUEUE; t = t->link) {
-	deleteThread(t);
-      }
-      run_queue_hd = run_queue_tl = END_TSO_QUEUE;
-      blocked_queue_hd = blocked_queue_tl = END_TSO_QUEUE;
+      deleteAllThreads();
       interrupted = rtsFalse;
       was_interrupted = rtsTrue;
     }
@@ -506,7 +500,7 @@ schedule( void )
      * ToDo: what if another client comes along & requests another
      * main thread?
      */
-    if (blocked_queue_hd != END_TSO_QUEUE) {
+    if (blocked_queue_hd != END_TSO_QUEUE || sleeping_queue != END_TSO_QUEUE) {
       awaitEvent(
 	   (run_queue_hd == END_TSO_QUEUE)
 #ifdef SMP
@@ -538,6 +532,7 @@ schedule( void )
 #ifdef SMP
     if (blocked_queue_hd == END_TSO_QUEUE
 	&& run_queue_hd == END_TSO_QUEUE
+	&& sleeping_queue == END_TSO_QUEUE
 	&& (n_free_capabilities == RtsFlags.ParFlags.nNodes))
     {
 	IF_DEBUG(scheduler, sched_belch("deadlocked, checking for black holes..."));
@@ -554,7 +549,8 @@ schedule( void )
     }
 #else /* ! SMP */
     if (blocked_queue_hd == END_TSO_QUEUE
-	&& run_queue_hd == END_TSO_QUEUE)
+	&& run_queue_hd == END_TSO_QUEUE
+	&& sleeping_queue == END_TSO_QUEUE)
     {
 	IF_DEBUG(scheduler, sched_belch("deadlocked, checking for black holes..."));
 	detectBlackHoles();
@@ -858,7 +854,8 @@ schedule( void )
      */
     if (RtsFlags.ConcFlags.ctxtSwitchTicks == 0
 	&& (run_queue_hd != END_TSO_QUEUE
-	    || blocked_queue_hd != END_TSO_QUEUE))
+	    || blocked_queue_hd != END_TSO_QUEUE
+	    || sleeping_queue != END_TSO_QUEUE))
 	context_switch = 1;
     else
 	context_switch = 0;
@@ -1152,19 +1149,29 @@ schedule( void )
   } /* end of while(1) */
 }
 
-/* A hack for Hugs concurrency support.  Needs sanitisation (?) */
+/* ---------------------------------------------------------------------------
+ * deleteAllThreads():  kill all the live threads.
+ *
+ * This is used when we catch a user interrupt (^C), before performing
+ * any necessary cleanups and running finalizers.
+ * ------------------------------------------------------------------------- */
+   
 void deleteAllThreads ( void )
 {
   StgTSO* t;
-  IF_DEBUG(scheduler,sched_belch("deleteAllThreads()"));
+  IF_DEBUG(scheduler,sched_belch("deleting all threads"));
   for (t = run_queue_hd; t != END_TSO_QUEUE; t = t->link) {
-    deleteThread(t);
+      deleteThread(t);
   }
   for (t = blocked_queue_hd; t != END_TSO_QUEUE; t = t->link) {
-    deleteThread(t);
+      deleteThread(t);
+  }
+  for (t = sleeping_queue; t != END_TSO_QUEUE; t = t->link) {
+      deleteThread(t);
   }
   run_queue_hd = run_queue_tl = END_TSO_QUEUE;
   blocked_queue_hd = blocked_queue_tl = END_TSO_QUEUE;
+  sleeping_queue = END_TSO_QUEUE;
 }
 
 /* startThread and  insertThread are now in GranSim.c -- HWL */
@@ -1582,12 +1589,14 @@ initScheduler(void)
     blocked_queue_hds[i]  = END_TSO_QUEUE;
     blocked_queue_tls[i]  = END_TSO_QUEUE;
     ccalling_threadss[i]  = END_TSO_QUEUE;
+    sleeping_queue        = END_TSO_QUEUE;
   }
 #else
   run_queue_hd      = END_TSO_QUEUE;
   run_queue_tl      = END_TSO_QUEUE;
   blocked_queue_hd  = END_TSO_QUEUE;
   blocked_queue_tl  = END_TSO_QUEUE;
+  sleeping_queue    = END_TSO_QUEUE;
 #endif 
 
   suspended_ccalling_threads  = END_TSO_QUEUE;
@@ -1743,6 +1752,8 @@ howManyThreadsAvail ( void )
       i++;
    for (q = blocked_queue_hd; q != END_TSO_QUEUE; q = q->link)
       i++;
+   for (q = sleeping_queue; q != END_TSO_QUEUE; q = q->link)
+      i++;
    return i;
 }
 
@@ -1756,9 +1767,13 @@ finishAllThreads ( void )
       while (blocked_queue_hd != END_TSO_QUEUE) {
          waitThread ( blocked_queue_hd, NULL );
       }
+      while (sleeping_queue != END_TSO_QUEUE) {
+         waitThread ( blocked_queue_hd, NULL );
+      }
    } while 
       (blocked_queue_hd != END_TSO_QUEUE || 
-        run_queue_hd != END_TSO_QUEUE);
+       run_queue_hd     != END_TSO_QUEUE ||
+       sleeping_queue   != END_TSO_QUEUE);
 }
 
 SchedulerStatus
@@ -1924,6 +1939,7 @@ take_off_run_queue(StgTSO *tso) {
 
         - all the threads on the runnable queue
         - all the threads on the blocked queue
+        - all the threads on the sleeping queue
 	- all the thread currently executing a _ccall_GC
         - all the "main threads"
      
@@ -1970,6 +1986,10 @@ static void GetRoots(void)
     blocked_queue_hd  = (StgTSO *)MarkRoot((StgClosure *)blocked_queue_hd);
     blocked_queue_tl  = (StgTSO *)MarkRoot((StgClosure *)blocked_queue_tl);
   }
+
+  if (sleeping_queue != END_TSO_QUEUE) {
+    sleeping_queue  = (StgTSO *)MarkRoot((StgClosure *)sleeping_queue);
+  }
 #endif 
 
   for (m = main_threads; m != NULL; m = m->link) {
@@ -2128,8 +2148,6 @@ threadStackOverflow(StgTSO *tso)
    Wake up a queue that was blocked on some resource.
    ------------------------------------------------------------------------ */
 
-/* ToDo: check push_on_run_queue vs. PUSH_ON_RUN_QUEUE */
-
 #if defined(GRAN)
 static inline void
 unblockCount ( StgBlockingQueueElement *bqe, StgClosure *node )
@@ -2500,7 +2518,6 @@ unblockThread(StgTSO *tso)
       barf("unblockThread (Exception): TSO not found");
     }
 
-  case BlockedOnDelay:
   case BlockedOnRead:
   case BlockedOnWrite:
     {
@@ -2525,6 +2542,23 @@ unblockThread(StgTSO *tso)
       barf("unblockThread (I/O): TSO not found");
     }
 
+  case BlockedOnDelay:
+    {
+      StgBlockingQueueElement *prev = NULL;
+      for (t = (StgBlockingQueueElement *)sleeping_queue; t != END_BQ_QUEUE; 
+	   prev = t, t = t->link) {
+	if (t == (StgBlockingQueueElement *)tso) {
+	  if (prev == NULL) {
+	    sleeping_queue = (StgTSO *)t->link;
+	  } else {
+	    prev->link = t->link;
+	  }
+	  goto done;
+	}
+      }
+      barf("unblockThread (I/O): TSO not found");
+    }
+
   default:
     barf("unblockThread");
   }
@@ -2603,7 +2637,6 @@ unblockThread(StgTSO *tso)
       barf("unblockThread (Exception): TSO not found");
     }
 
-  case BlockedOnDelay:
   case BlockedOnRead:
   case BlockedOnWrite:
     {
@@ -2628,6 +2661,23 @@ unblockThread(StgTSO *tso)
       barf("unblockThread (I/O): TSO not found");
     }
 
+  case BlockedOnDelay:
+    {
+      StgTSO *prev = NULL;
+      for (t = sleeping_queue; t != END_TSO_QUEUE; 
+	   prev = t, t = t->link) {
+	if (t == tso) {
+	  if (prev == NULL) {
+	    sleeping_queue = t->link;
+	  } else {
+	    prev->link = t->link;
+	  }
+	  goto done;
+	}
+      }
+      barf("unblockThread (I/O): TSO not found");
+    }
+
   default:
     barf("unblockThread");
   }
@@ -2864,7 +2914,7 @@ raiseAsync(StgTSO *tso, StgClosure *exception)
       tso->su = (StgUpdateFrame *)(sp+1);
       tso->sp = sp;
       return;
-      
+
     default:
       barf("raiseAsync");
     }
@@ -2986,12 +3036,7 @@ printThreadBlockage(StgTSO *tso)
     fprintf(stderr,"blocked on write to fd %d", tso->block_info.fd);
     break;
   case BlockedOnDelay:
-#if defined(HAVE_SETITIMER) || defined(mingw32_TARGET_OS)
-    fprintf(stderr,"blocked on delay of %d ms", tso->block_info.delay);
-#else
-    fprintf(stderr,"blocked on delay of %d ms", 
-	    tso->block_info.target - getourtimeofday());
-#endif
+    fprintf(stderr,"blocked until %d", tso->block_info.target);
     break;
   case BlockedOnMVar:
     fprintf(stderr,"blocked on an MVar");
diff --git a/ghc/rts/Schedule.h b/ghc/rts/Schedule.h
index d0c3f9923dc5d9f4e2db873205a674eda5a6cac4..c2627e9d4da5a281a0f2e38ec5bc59edece9b0a5 100644
--- a/ghc/rts/Schedule.h
+++ b/ghc/rts/Schedule.h
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
- * $Id: Schedule.h,v 1.18 2000/04/14 15:18:07 sewardj Exp $
+ * $Id: Schedule.h,v 1.19 2000/08/25 13:12:07 simonmar Exp $
  *
  * (c) The GHC Team 1998-1999
  *
@@ -85,6 +85,15 @@ void raiseAsync(StgTSO *tso, StgClosure *exception);
  */
 void awaitEvent(rtsBool wait);  /* In Select.c */
 
+/* wakeUpSleepingThreads(nat ticks)
+ *
+ * Wakes up any sleeping threads whose timers have expired.
+ *
+ * Called from STG :  NO
+ * Locks assumed   :  sched_mutex
+ */
+rtsBool wakeUpSleepingThreads(nat);  /* In Select.c */
+
 // ToDo: check whether all fcts below are used in the SMP version, too
 //@cindex awaken_blocked_queue
 #if defined(GRAN)
@@ -112,7 +121,9 @@ void    initThread(StgTSO *tso, nat stack_size);
 extern nat context_switch;
 extern rtsBool interrupted;
 
-extern  nat ticks_since_select;
+/* In Select.c */
+extern nat timestamp;
+extern nat ticks_since_timestamp;
 
 //@cindex Capability
 /* Capability type
@@ -139,6 +150,7 @@ extern Capability MainRegTable;
 #else
 extern  StgTSO *run_queue_hd, *run_queue_tl;
 extern  StgTSO *blocked_queue_hd, *blocked_queue_tl;
+extern  StgTSO *sleeping_queue;
 #endif
 /* Linked list of all threads. */
 extern  StgTSO *all_threads;
diff --git a/ghc/rts/Select.c b/ghc/rts/Select.c
index 0d1a380047b3d2576136a3baf38c1ed98934301c..486ccbaccc0139a3ca21e027f26e705b136c793a 100644
--- a/ghc/rts/Select.c
+++ b/ghc/rts/Select.c
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
- * $Id: Select.c,v 1.13 2000/08/23 12:51:03 simonmar Exp $
+ * $Id: Select.c,v 1.14 2000/08/25 13:12:07 simonmar Exp $
  *
  * (c) The GHC Team 1995-1999
  *
@@ -25,7 +25,44 @@
 #  include <sys/time.h>
 # endif
 
-nat ticks_since_select = 0;
+/* 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
+ * whether a timer has expired even if our timer will wrap around
+ * before the target is reached, using the following formula:
+ *
+ *        (int)((uint)current_time - (uint)target_time) < 0
+ *
+ * if this is true, then our time has expired.
+ * (idea due to Andy Gill).
+ */
+rtsBool
+wakeUpSleepingThreads(nat ticks)
+{
+    StgTSO *tso;
+    rtsBool flag = rtsFalse;
+
+    while (sleeping_queue != END_TSO_QUEUE &&
+	   (int)(ticks - sleeping_queue->block_info.target) > 0) {
+	tso = sleeping_queue;
+	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));
+	PUSH_ON_RUN_QUEUE(tso);
+	flag = rtsTrue;
+    }
+    return flag;
+}
 
 /* Argument 'wait' says whether to wait for I/O to become available,
  * or whether to just check and return immediately.  If there are
@@ -50,16 +87,21 @@ awaitEvent(rtsBool wait)
     rtsBool ready;
     fd_set rfd,wfd;
     int numFound;
-    nat min, delta;
     int maxfd = -1;
     rtsBool select_succeeded = rtsTrue;
-   
     struct timeval tv;
-#ifndef linux_TARGET_OS
-    struct timeval tv_before,tv_after;
-#endif
+    lnat min, ticks;
+
+    tv.tv_sec  = 0;
+    tv.tv_usec = 0;
 
-    IF_DEBUG(scheduler,belch("Checking for threads blocked on I/O...\n"));
+    IF_DEBUG(scheduler,
+	     belch("scheduler: checking for threads blocked on I/O");
+	     if (wait) {
+		 belch(" (waiting)");
+	     }
+	     belch("\n");
+	     );
 
     /* loop until we've woken up some threads.  This loop is needed
      * because the select timing isn't accurate, we sometimes sleep
@@ -68,18 +110,23 @@ awaitEvent(rtsBool wait)
      */
     do {
 
-      /* see how long it's been since we last checked the blocked queue.
-       * ToDo: make this check atomic, so we don't lose any ticks.
-       */
-      delta = ticks_since_select;
-      ticks_since_select = 0;
-      delta = delta * TICK_MILLISECS * 1000;
+      ticks = timestamp = getourtimeofday();
+      ticks_since_timestamp = 0;
+      if (wakeUpSleepingThreads(ticks)) { 
+	  return;
+      }
 
-      min = wait == rtsTrue ? 0x7fffffff : 0;
+      if (!wait) {
+	  min = 0;
+      } else if (sleeping_queue != END_TSO_QUEUE) {
+	  min = (sleeping_queue->block_info.target - ticks) 
+	      * TICK_MILLISECS * 1000;
+      } else {
+	  min = 0x7ffffff;
+      }
 
       /* 
-       * Collect all of the fd's that we're interested in, and capture
-       * the minimum waiting time (in microseconds) for the delayed threads.
+       * Collect all of the fd's that we're interested in
        */
       FD_ZERO(&rfd);
       FD_ZERO(&wfd);
@@ -104,23 +151,6 @@ awaitEvent(rtsBool wait)
 	    continue;
 	  }
 
-	case BlockedOnDelay:
-	  {
-	    int candidate; /* signed int is intentional */
-#if defined(HAVE_SETITIMER) || defined(mingw32_TARGET_OS)
-	    candidate = tso->block_info.delay;
-#else
-	    candidate = tso->block_info.target - getourtimeofday();
-	    if (candidate < 0) {
-	      candidate = 0;
-	    }
-#endif
-	    if ((nat)candidate < min) {
-	      min = candidate;
-	    }
-	    continue;
-	  }
-
 	default:
 	  barf("AwaitEvent");
 	}
@@ -141,139 +171,92 @@ awaitEvent(rtsBool wait)
       RELEASE_LOCK(&sched_mutex);
 
       /* Check for any interesting events */
-
-      tv.tv_sec = min / 1000000;
+      
+      tv.tv_sec  = min / 1000000;
       tv.tv_usec = min % 1000000;
 
-#ifndef linux_TARGET_OS
-      gettimeofday(&tv_before, (struct timezone *) NULL);
-#endif
-
-      while (!interrupted &&
-	     (numFound = select(maxfd+1, &rfd, &wfd, NULL, &tv)) < 0) {
-	if (errno != EINTR) {
-	  /* fflush(stdout); */
-	  perror("select");
-	  barf("select failed");
-	}
-	ACQUIRE_LOCK(&sched_mutex);
+      while ((numFound = select(maxfd+1, &rfd, &wfd, NULL, &tv)) < 0) {
 
-	/* 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 (signals_pending()) {
-	  RELEASE_LOCK(&sched_mutex);
-	  start_signal_handlers();
-	  /* Don't wake up any other threads that were waiting on I/O */
-	  select_succeeded = rtsFalse;
-	  break;
-	}
-
-	if (interrupted) {
-	    RELEASE_LOCK(&sched_mutex);
-	    select_succeeded = rtsFalse;
-	    break;
-	}
-
-	/* If new runnable threads have arrived, stop waiting for
-	 * I/O and run them.
-	 */
-	if (run_queue_hd != END_TSO_QUEUE) {
-	  RELEASE_LOCK(&sched_mutex);
-	  select_succeeded = rtsFalse;
-	  break;
-	}
+	  if (errno != EINTR) {
+	      /* fflush(stdout); */
+	      perror("select");
+	      barf("select failed");
+	  }
+	  ACQUIRE_LOCK(&sched_mutex);
 	
-	RELEASE_LOCK(&sched_mutex);
-      }	
-
-#ifdef linux_TARGET_OS
-      /* on Linux, tv is set to indicate the amount of time not
-       * slept, so we don't need to gettimeofday() to find out.
-       */
-      delta += min - (tv.tv_sec * 1000000 + tv.tv_usec);
-#else
-      gettimeofday(&tv_after, (struct timezone *) NULL);
-      delta += (tv_after.tv_sec - tv_before.tv_sec) * 1000000 +
-	tv_after.tv_usec - tv_before.tv_usec;
-#endif
-
-#if 0
-      if (delta != 0) { fprintf(stderr,"waited: %d %d %d\n", min, delta,
-				interrupted); }
-#endif
+	  /* 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 (signals_pending()) {
+	      RELEASE_LOCK(&sched_mutex); /* ToDo: kill */
+	      start_signal_handlers();
+	      ACQUIRE_LOCK(&sched_mutex);
+	      return; /* still hold the lock */
+	  }
+	  
+	  /* we were interrupted, return to the scheduler immediately.
+	   */
+	  if (interrupted) {
+	      return; /* still hold the lock */
+	  }
+	  
+	  /* check for threads that need waking up 
+	   */
+	  wakeUpSleepingThreads(getourtimeofday());
+	  
+	  /* If new runnable threads have arrived, stop waiting for
+	   * I/O and run them.
+	   */
+	  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.
-	
-       * For the delayed threads, decrement the number of microsecs
-       * we've been blocked for. Unblock the threads that have thusly expired.
        */
 
       prev = NULL;
-      for(tso = blocked_queue_hd; tso != END_TSO_QUEUE; tso = next) {
-	next = tso->link;
-	switch (tso->why_blocked) {
-	case BlockedOnRead:
-	  ready = select_succeeded && FD_ISSET(tso->block_info.fd, &rfd);
-	  break;
-	
-	case BlockedOnWrite:
-	  ready = select_succeeded && FD_ISSET(tso->block_info.fd, &wfd);
-	  break;
-	
-	case BlockedOnDelay:
-	  {
-#if defined(HAVE_SETITIMER) || defined(mingw32_TARGET_OS)
-	    if (tso->block_info.delay > delta) {
-	      tso->block_info.delay -= delta;
-	      ready = 0;
-	    } else {
-	      tso->block_info.delay = 0;
-	      ready = 1;
-	    }
-#else
-	    int candidate; /* signed int is intentional */
-	    candidate = tso->block_info.target - getourtimeofday();
-	    if (candidate < 0) {
-	      candidate = 0;
-	    }
-	    if ((nat)candidate > delta) {
-	      ready = 0;
-	    } else {
-	      ready = 1;
-	    }
-#endif
-	    break;
-	  }
-	
-	default:
-	  barf("awaitEvent");
-	}
+      if (select_succeeded) {
+	  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);
+		  break;
+	      case BlockedOnWrite:
+		  ready = FD_ISSET(tso->block_info.fd, &wfd);
+		  break;
+	      default:
+		  barf("awaitEvent");
+	      }
       
-	if (ready) {
-	  IF_DEBUG(scheduler,belch("Waking up thread %d\n", tso->id));
-	  tso->why_blocked = NotBlocked;
-	  tso->link = END_TSO_QUEUE;
-	  PUSH_ON_RUN_QUEUE(tso);
-	} else {
-	  if (prev == NULL)
-	    blocked_queue_hd = tso;
-	  else
-	    prev->link = tso;
-	  prev = tso;
-	}
-      }
+	      if (ready) {
+		  IF_DEBUG(scheduler,belch("Waking up blocked thread %d\n", tso->id));
+		  tso->why_blocked = NotBlocked;
+		  tso->link = END_TSO_QUEUE;
+		  PUSH_ON_RUN_QUEUE(tso);
+	      } else {
+		  if (prev == NULL)
+		      blocked_queue_hd = tso;
+		  else
+		      prev->link = tso;
+		  prev = tso;
+	      }
+	  }
 
-      if (prev == NULL)
-	blocked_queue_hd = blocked_queue_tl = END_TSO_QUEUE;
-      else {
-	prev->link = END_TSO_QUEUE;
-	blocked_queue_tl = prev;
+	  if (prev == NULL)
+	      blocked_queue_hd = blocked_queue_tl = END_TSO_QUEUE;
+	  else {
+	      prev->link = END_TSO_QUEUE;
+	      blocked_queue_tl = prev;
+	  }
       }
 
     } while (wait && !interrupted && run_queue_hd == END_TSO_QUEUE);
diff --git a/ghc/rts/Signals.c b/ghc/rts/Signals.c
index ee5ef810321d69f7217e6bc377cc3ee9d6476be5..3312b153b408557f6bf83aa6896fe778f9ec66b8 100644
--- a/ghc/rts/Signals.c
+++ b/ghc/rts/Signals.c
@@ -1,5 +1,5 @@
 /* -----------------------------------------------------------------------------
- * $Id: Signals.c,v 1.17 2000/04/14 16:47:43 panne Exp $
+ * $Id: Signals.c,v 1.18 2000/08/25 13:12:07 simonmar Exp $
  *
  * (c) The GHC Team, 1998-1999
  *
@@ -7,6 +7,8 @@
  *
  * ---------------------------------------------------------------------------*/
 
+#define NON_POSIX_SOURCE
+
 #include "Rts.h"
 #include "SchedAPI.h"
 #include "Schedule.h"
@@ -299,6 +301,8 @@ init_default_handlers()
       /* Oh well, at least we tried. */
       prog_belch("failed to install SIGINT handler");
     }
+
+    siginterrupt(SIGINT, 1);
 }
 
 #endif /*! mingw32_TARGET_OS */