Add 'packageDbModules' function to GHC API.
[ghc-hetmet.git] / rts / Schedule.c
index e17c653..63e2e99 100644 (file)
@@ -399,6 +399,7 @@ schedule (Capability *initialCapability, Task *task)
     //     ASSERT_FULL_CAPABILITY_INVARIANTS(cap,task);
     }
 
+  yield:
     scheduleYield(&cap,task);
     if (emptyRunQueue(cap)) continue; // look for work again
 #endif
@@ -479,6 +480,7 @@ run_thread:
 
     ASSERT_FULL_CAPABILITY_INVARIANTS(cap,task);
     ASSERT(t->cap == cap);
+    ASSERT(t->bound ? t->bound->cap == cap : 1);
 
     prev_what_next = t->what_next;
 
@@ -564,7 +566,7 @@ run_thread:
        debugTrace(DEBUG_sched,
                   "--<< thread %lu (%s) stopped: blocked",
                   (unsigned long)t->id, whatNext_strs[t->what_next]);
-       continue;
+        goto yield;
     }
 #endif
 
@@ -652,15 +654,9 @@ scheduleFindWork (Capability *cap)
     scheduleCheckBlockedThreads(cap);
 
 #if defined(THREADED_RTS) || defined(PARALLEL_HASKELL)
-    // Try to activate one of our own sparks
     if (emptyRunQueue(cap)) { scheduleActivateSpark(cap); }
 #endif
 
-#if defined(THREADED_RTS)
-    // Try to steak work if we don't have any
-    if (emptyRunQueue(cap)) { stealWork(cap); }
-#endif
-    
 #if defined(PARALLEL_HASKELL)
     // if messages have been buffered...
     scheduleSendPendingMessages();
@@ -704,7 +700,9 @@ shouldYieldCapability (Capability *cap, Task *task)
 //    - we need to yield this Capability to someone else 
 //      (see shouldYieldCapability())
 //
-// The return value indicates whether 
+// Careful: the scheduler loop is quite delicate.  Make sure you run
+// the tests in testsuite/concurrent (all ways) after modifying this,
+// and also check the benchmarks in nofib/parallel for regressions.
 
 static void
 scheduleYield (Capability **pcap, Task *task)
@@ -712,7 +710,10 @@ scheduleYield (Capability **pcap, Task *task)
     Capability *cap = *pcap;
 
     // if we have work, and we don't need to give up the Capability, continue.
-    if (!emptyRunQueue(cap) && !shouldYieldCapability(cap,task))
+    if (!shouldYieldCapability(cap,task) && 
+        (!emptyRunQueue(cap) ||
+         blackholes_need_checking ||
+         sched_state >= SCHED_INTERRUPTING))
         return;
 
     // otherwise yield (sleep), and keep yielding if necessary.
@@ -932,8 +933,13 @@ scheduleCheckBlackHoles (Capability *cap)
     {
        ACQUIRE_LOCK(&sched_mutex);
        if ( blackholes_need_checking ) {
-           checkBlackHoles(cap);
            blackholes_need_checking = rtsFalse;
+            // important that we reset the flag *before* checking the
+            // blackhole queue, otherwise we could get deadlock.  This
+            // happens as follows: we wake up a thread that
+            // immediately runs on another Capability, blocks on a
+            // blackhole, and then we reset the blackholes_need_checking flag.
+           checkBlackHoles(cap);
        }
        RELEASE_LOCK(&sched_mutex);
     }
@@ -1061,30 +1067,10 @@ scheduleSendPendingMessages(void)
 static void
 scheduleActivateSpark(Capability *cap)
 {
-    StgClosure *spark;
-
-/* We only want to stay here if the run queue is empty and we want some
-   work. We try to turn a spark into a thread, and add it to the run
-   queue, from where it will be picked up in the next iteration of the
-   scheduler loop.  
-*/
-    if (!emptyRunQueue(cap)) 
-      /* In the threaded RTS, another task might have pushed a thread
-        on our run queue in the meantime ? But would need a lock.. */
-      return;
-
-    // Really we should be using reclaimSpark() here, but
-    // experimentally it doesn't seem to perform as well as just
-    // stealing from our own spark pool:
-    // spark = reclaimSpark(cap->sparks);
-    spark = tryStealSpark(cap->sparks); // defined in Sparks.c
-
-    if (spark != NULL) {
-      debugTrace(DEBUG_sched,
-                "turning spark of closure %p into a thread",
-                (StgClosure *)spark);
-      createSparkThread(cap,spark); // defined in Sparks.c
+    if (anySparks())
+    {
+        createSparkThread(cap);
+        debugTrace(DEBUG_sched, "creating a spark thread");
     }
 }
 #endif // PARALLEL_HASKELL || THREADED_RTS
@@ -2112,14 +2098,13 @@ exitScheduler(
        boundTaskExiting(task);
        stopTaskManager();
     }
-#else
-    freeCapability(&MainCapability);
 #endif
 }
 
 void
 freeScheduler( void )
 {
+    freeCapabilities();
     freeTaskManager();
     if (n_capabilities != 1) {
         stgFree(capabilities);