[project @ 2003-12-15 16:45:23 by simonmar]
[ghc-hetmet.git] / ghc / rts / Capability.c
index a2910ad..6d2f43c 100644 (file)
@@ -69,6 +69,9 @@ Condition thread_ready_cond = INIT_COND_VAR;
  * Task.startTask() uses its current value.
  */
 nat rts_n_waiting_tasks = 0;
+
+static Condition *passTarget = NULL;
+static rtsBool passingCapability = rtsFalse;
 #endif
 
 /* -----------------------------------------------------------------------------
@@ -137,10 +140,8 @@ static Capability *returning_capabilities;
  */ 
 void grabCapability(Capability** cap)
 {
-#ifdef RTS_SUPPORTS_THREADS
-  ASSERT(rts_n_free_capabilities > 0);
-#endif
 #if !defined(SMP)
+  ASSERT(rts_n_free_capabilities == 1);
   rts_n_free_capabilities = 0;
   *cap = &MainCapability;
   handleSignalsInThisThread();
@@ -149,9 +150,7 @@ void grabCapability(Capability** cap)
   free_capabilities = (*cap)->link;
   rts_n_free_capabilities--;
 #endif
-    IF_DEBUG(scheduler,
-            fprintf(stderr,"worker thread (%p): got capability\n",
-               osThreadId()));
+  IF_DEBUG(scheduler, sched_belch("worker: got capability"));
 }
 
 /*
@@ -187,6 +186,7 @@ void releaseCapability(Capability* cap
 #endif
     rts_n_waiting_workers--;
     signalCondition(&returning_worker_cond);
+    IF_DEBUG(scheduler, sched_belch("worker: released capability to returning worker"));
   } else /*if ( !EMPTY_RUN_QUEUE() )*/ {
 #if defined(SMP)
     cap->link = free_capabilities;
@@ -197,12 +197,12 @@ void releaseCapability(Capability* cap
 #endif
     /* Signal that a capability is available */
     signalCondition(&thread_ready_cond);
+    startSchedulerTaskIfNecessary();  // if there is more work to be done,
+                                     // we'll need a new thread
+    IF_DEBUG(scheduler, sched_belch("worker: released capability"));
   }
 #endif
-    IF_DEBUG(scheduler,
-            fprintf(stderr,"worker thread (%p): released capability\n",
-               osThreadId()));
- return;
+  return;
 }
 
 #if defined(RTS_SUPPORTS_THREADS)
@@ -241,12 +241,10 @@ void releaseCapability(Capability* cap
 void
 grabReturnCapability(Mutex* pMutex, Capability** pCap)
 {
-  IF_DEBUG(scheduler,
-          fprintf(stderr,"worker (%p): returning, waiting for lock.\n", osThreadId()));
-  IF_DEBUG(scheduler,
-          fprintf(stderr,"worker (%p): returning; workers waiting: %d\n",
-                  osThreadId(), rts_n_waiting_workers));
-  if ( noCapabilities() ) {
+  IF_DEBUG(scheduler, 
+          sched_belch("worker: returning; workers waiting: %d",
+                      rts_n_waiting_workers));
+  if ( noCapabilities() || passingCapability ) {
     rts_n_waiting_workers++;
     wakeBlockedWorkerThread();
     context_switch = 1;        // make sure it's our turn soon
@@ -290,14 +288,12 @@ void
 yieldToReturningWorker(Mutex* pMutex, Capability** pCap, Condition* pThreadCond)
 {
   if ( rts_n_waiting_workers > 0 ) {
-    IF_DEBUG(scheduler,
-            fprintf(stderr,"worker thread (%p): giving up RTS token\n", osThreadId()));
+    IF_DEBUG(scheduler, sched_belch("worker: giving up capability"));
     releaseCapability(*pCap);
         /* And wait for work */
     waitForWorkCapability(pMutex, pCap, pThreadCond);
     IF_DEBUG(scheduler,
-            fprintf(stderr,"worker thread (%p): got back RTS token (after yieldToReturningWorker)\n",
-               osThreadId()));
+            sched_belch("worker: got back capability (after yieldToReturningWorker)"));
   }
   return;
 }
@@ -319,37 +315,30 @@ yieldToReturningWorker(Mutex* pMutex, Capability** pCap, Condition* pThreadCond)
  * Post-condition: pMutex is held and *pCap is held by the current thread
  */
  
-static Condition *passTarget = NULL;
 void 
 waitForWorkCapability(Mutex* pMutex, Capability** pCap, Condition* pThreadCond)
 {
 #ifdef SMP
   #error SMP version not implemented
 #endif
-  IF_DEBUG(scheduler,
-          fprintf(stderr,"worker thread (%p): wait for cap (cond: %p)\n",
-             osThreadId(),pThreadCond));
-  while ( noCapabilities() || (pThreadCond && passTarget != pThreadCond)
-      || (!pThreadCond && passTarget)) {
+  while ( noCapabilities() || (passingCapability && passTarget != pThreadCond)) {
+    IF_DEBUG(scheduler,
+            sched_belch("worker: wait for capability (cond: %p)",
+                        pThreadCond));
     if(pThreadCond)
     {
       waitCondition(pThreadCond, pMutex);
-      IF_DEBUG(scheduler,
-              fprintf(stderr,"worker thread (%p): get passed capability\n",
-                 osThreadId()));
+      IF_DEBUG(scheduler, sched_belch("worker: get passed capability"));
     }
     else
     {
       rts_n_waiting_tasks++;
       waitCondition(&thread_ready_cond, pMutex);
       rts_n_waiting_tasks--;
-      IF_DEBUG(scheduler,
-              fprintf(stderr,"worker thread (%p): get normal capability\n",
-                 osThreadId()));
+      IF_DEBUG(scheduler, sched_belch("worker: get normal capability"));
     }
   }
-  passTarget = NULL;
+  passingCapability = rtsFalse;
   grabCapability(pCap);
   return;
 }
@@ -371,15 +360,41 @@ passCapability(Mutex* pMutex, Capability* cap, Condition *pTargetThreadCond)
 #ifdef SMP
   #error SMP version not implemented
 #endif
+    ASSERT(rts_n_free_capabilities == 0);
     rts_n_free_capabilities = 1;
     signalCondition(pTargetThreadCond);
     passTarget = pTargetThreadCond;
-    IF_DEBUG(scheduler,
-            fprintf(stderr,"worker thread (%p): passCapability\n",
-               osThreadId()));
+    passingCapability = rtsTrue;
+    IF_DEBUG(scheduler, sched_belch("worker: passCapability"));
+}
+
+/*
+ * Function: passCapabilityToWorker(Mutex*, Capability*)
+ *
+ * Purpose:  Let go of the capability and make sure that a
+ *          "plain" worker thread (not a bound thread) gets it next.
+ *
+ * Pre-condition: pMutex is held and cap is held by the current thread
+ * Post-condition: pMutex is held; cap will be grabbed by the "target"
+ *                thread when pMutex is released.
+ */
+
+void
+passCapabilityToWorker(Mutex* pMutex, Capability* cap)
+{
+#ifdef SMP
+  #error SMP version not implemented
+#endif
+    rts_n_free_capabilities = 1;
+    signalCondition(&thread_ready_cond);
+    startSchedulerTaskIfNecessary();
+    passTarget = NULL;
+    passingCapability = rtsTrue;
+    IF_DEBUG(scheduler, sched_belch("worker: passCapabilityToWorker"));
 }
 
 
+
 #endif /* RTS_SUPPORTS_THREADS */
 
 #if defined(SMP)
@@ -407,7 +422,8 @@ initCapabilities_(nat n)
   free_capabilities = cap;
   rts_n_free_capabilities = n;
   returning_capabilities = NULL;
-  IF_DEBUG(scheduler,fprintf(stderr,"scheduler: Allocated %d capabilities\n", n_free_capabilities););
+  IF_DEBUG(scheduler,
+          sched_belch("allocated %d capabilities", n_free_capabilities));
 }
 #endif /* SMP */