[project @ 2005-05-23 10:17:22 by simonpj]
[ghc-hetmet.git] / ghc / rts / Schedule.c
index 036c5b0..8e1a43e 100644 (file)
@@ -458,8 +458,6 @@ schedule( StgMainThread *mainThread USED_WHEN_RTS_SUPPORTS_THREADS,
       CurrentTSO = event->tso;
 #endif
 
-      IF_DEBUG(scheduler, printAllThreads());
-
 #if defined(RTS_SUPPORTS_THREADS)
       // Yield the capability to higher-priority tasks if necessary.
       //
@@ -702,6 +700,13 @@ run_thread:
       barf("schedule: invalid what_next field");
     }
 
+#if defined(SMP)
+    // in SMP mode, we might return with a different capability than
+    // we started with, if the Haskell thread made a foreign call.  So
+    // let's find out what our current Capability is:
+    cap = myCapability();
+#endif
+
     // We have run some Haskell code: there might be blackhole-blocked
     // threads to wake up now.
     if ( blackhole_queue != END_TSO_QUEUE ) {
@@ -755,7 +760,6 @@ run_thread:
 
     case ThreadBlocked:
        scheduleHandleThreadBlocked(t);
-       threadPaused(t);
        break;
 
     case ThreadFinished:
@@ -895,6 +899,7 @@ scheduleDetectDeadlock(void)
        // they are unreachable and will therefore be sent an
        // exception.  Any threads thus released will be immediately
        // runnable.
+
        GarbageCollect(GetRoots,rtsTrue);
        recent_activity = ACTIVITY_DONE_GC;
        if ( !EMPTY_RUN_QUEUE() ) return;
@@ -1475,12 +1480,13 @@ scheduleHandleHeapOverflow( Capability *cap, StgTSO *t )
                 debugBelch("--<< thread %ld (%s) stopped: requesting a large block (size %ld)\n", 
                            (long)t->id, whatNext_strs[t->what_next], blocks));
        
-       // don't do this if it would push us over the
-       // alloc_blocks_lim limit; we'll GC first.
-       if (alloc_blocks + blocks < alloc_blocks_lim) {
+       // don't do this if the nursery is (nearly) full, we'll GC first.
+       if (cap->r.rCurrentNursery->link != NULL ||
+           cap->r.rNursery->n_blocks == 1) {  // paranoia to prevent infinite loop
+                                              // if the nursery has only one block.
            
-           alloc_blocks += blocks;
            bd = allocGroup( blocks );
+           cap->r.rNursery->n_blocks += blocks;
            
            // link the new group into the list
            bd->link = cap->r.rCurrentNursery;
@@ -1491,7 +1497,6 @@ scheduleHandleHeapOverflow( Capability *cap, StgTSO *t )
 #if !defined(SMP)
                ASSERT(g0s0->blocks == cap->r.rCurrentNursery &&
                       g0s0 == cap->r.rNursery);
-               g0s0->blocks = bd;
 #endif
                cap->r.rNursery->blocks = bd;
            }             
@@ -1507,20 +1512,15 @@ scheduleHandleHeapOverflow( Capability *cap, StgTSO *t )
            { 
                bdescr *x;
                for (x = bd; x < bd + blocks; x++) {
-                   x->step = g0s0;
+                   x->step = cap->r.rNursery;
                    x->gen_no = 0;
                    x->flags = 0;
                }
            }
            
-#if !defined(SMP)
-           // don't forget to update the block count in g0s0.
-           g0s0->n_blocks += blocks;
-
            // This assert can be a killer if the app is doing lots
            // of large block allocations.
-           ASSERT(countBlocks(g0s0->blocks) == g0s0->n_blocks);
-#endif
+           IF_DEBUG(sanity, checkNurserySanity(cap->r.rNursery));
            
            // now update the nursery to point to the new block
            cap->r.rCurrentNursery = bd;
@@ -1534,14 +1534,9 @@ scheduleHandleHeapOverflow( Capability *cap, StgTSO *t )
        }
     }
     
-    /* make all the running tasks block on a condition variable,
-     * maybe set context_switch and wait till they all pile in,
-     * then have them wait on a GC condition variable.
-     */
     IF_DEBUG(scheduler,
             debugBelch("--<< thread %ld (%s) stopped: HeapOverflow\n", 
                        (long)t->id, whatNext_strs[t->what_next]));
-    threadPaused(t);
 #if defined(GRAN)
     ASSERT(!is_on_queue(t,CurrentProc));
 #elif defined(PARALLEL_HASKELL)
@@ -1573,7 +1568,6 @@ scheduleHandleStackOverflow( StgTSO *t)
     /* just adjust the stack for this thread, then pop it back
      * on the run queue.
      */
-    threadPaused(t);
     { 
        /* enlarge the stack */
        StgTSO *new_t = threadStackOverflow(t);
@@ -1632,8 +1626,6 @@ scheduleHandleYield( StgTSO *t, nat prev_what_next )
        return rtsTrue;
     }
     
-    threadPaused(t);
-    
 #if defined(GRAN)
     ASSERT(!is_on_queue(t,CurrentProc));
       
@@ -1706,12 +1698,19 @@ scheduleHandleThreadBlocked( StgTSO *t
     emitSchedule = rtsTrue;
     
 #else /* !GRAN */
-      /* don't need to do anything.  Either the thread is blocked on
-       * I/O, in which case we'll have called addToBlockedQueue
-       * previously, or it's blocked on an MVar or Blackhole, in which
-       * case it'll be on the relevant queue already.
-       */
+
+      // We don't need to do anything.  The thread is blocked, and it
+      // has tidied up its stack and placed itself on whatever queue
+      // it needs to be on.
+
+#if !defined(SMP)
     ASSERT(t->why_blocked != NotBlocked);
+            // This might not be true under SMP: we don't have
+            // exclusive access to this TSO, so someone might have
+            // woken it up by now.  This actually happens: try
+            // conc023 +RTS -N2.
+#endif
+
     IF_DEBUG(scheduler,
             debugBelch("--<< thread %d (%s) stopped: ", 
                        t->id, whatNext_strs[t->what_next]);
@@ -1945,6 +1944,8 @@ scheduleDoGC( Capability *cap STG_UNUSED )
     // so this happens periodically:
     scheduleCheckBlackHoles();
     
+    IF_DEBUG(scheduler, printAllThreads());
+
     /* everybody back, start the GC.
      * Could do it in this thread, or signal a condition var
      * to do it in another thread.  Either way, we need to
@@ -2093,8 +2094,12 @@ deleteAllThreads ( void )
   StgTSO* t, *next;
   IF_DEBUG(scheduler,sched_belch("deleting all threads"));
   for (t = all_threads; t != END_TSO_QUEUE; t = next) {
-      next = t->global_link;
-      deleteThread(t);
+      if (t->what_next == ThreadRelocated) {
+         next = t->link;
+      } else {
+         next = t->global_link;
+         deleteThread(t);
+      }
   }      
 
   // The run queue now contains a bunch of ThreadKilled threads.  We
@@ -2979,7 +2984,7 @@ unblockCount ( StgBlockingQueueElement *bqe, StgClosure *node )
 #endif
 
 #if defined(GRAN)
-static StgBlockingQueueElement *
+StgBlockingQueueElement *
 unblockOneLocked(StgBlockingQueueElement *bqe, StgClosure *node)
 {
     StgTSO *tso;
@@ -3019,7 +3024,7 @@ unblockOneLocked(StgBlockingQueueElement *bqe, StgClosure *node)
                             tso->id, tso));
 }
 #elif defined(PARALLEL_HASKELL)
-static StgBlockingQueueElement *
+StgBlockingQueueElement *
 unblockOneLocked(StgBlockingQueueElement *bqe, StgClosure *node)
 {
     StgBlockingQueueElement *next;
@@ -3065,7 +3070,7 @@ unblockOneLocked(StgBlockingQueueElement *bqe, StgClosure *node)
 }
 
 #else /* !GRAN && !PARALLEL_HASKELL */
-static StgTSO *
+StgTSO *
 unblockOneLocked(StgTSO *tso)
 {
   StgTSO *next;
@@ -4069,10 +4074,10 @@ printThreadBlockage(StgTSO *tso)
 {
   switch (tso->why_blocked) {
   case BlockedOnRead:
-    debugBelch("is blocked on read from fd %ld", tso->block_info.fd);
+    debugBelch("is blocked on read from fd %d", (int)(tso->block_info.fd));
     break;
   case BlockedOnWrite:
-    debugBelch("is blocked on write to fd %ld", tso->block_info.fd);
+    debugBelch("is blocked on write to fd %d", (int)(tso->block_info.fd));
     break;
 #if defined(mingw32_HOST_OS)
     case BlockedOnDoProc:
@@ -4080,7 +4085,7 @@ printThreadBlockage(StgTSO *tso)
     break;
 #endif
   case BlockedOnDelay:
-    debugBelch("is blocked until %ld", tso->block_info.target);
+    debugBelch("is blocked until %ld", (long)(tso->block_info.target));
     break;
   case BlockedOnMVar:
     debugBelch("is blocked on an MVar");
@@ -4156,7 +4161,7 @@ printAllThreads(void)
   debugBelch("all threads:\n");
 # endif
 
-  for (t = all_threads; t != END_TSO_QUEUE; t = t->global_link) {
+  for (t = all_threads; t != END_TSO_QUEUE; ) {
     debugBelch("\tthread %d @ %p ", t->id, (void *)t);
 #if defined(DEBUG)
     {
@@ -4164,8 +4169,14 @@ printAllThreads(void)
       if (label) debugBelch("[\"%s\"] ",(char *)label);
     }
 #endif
-    printThreadStatus(t);
-    debugBelch("\n");
+    if (t->what_next == ThreadRelocated) {
+       debugBelch("has been relocated...\n");
+       t = t->link;
+    } else {
+       printThreadStatus(t);
+       debugBelch("\n");
+       t = t->global_link;
+    }
   }
 }