Fix linker_unload now that we are running constructors in the linker (#8291)
[ghc.git] / rts / Messages.c
index ae5d5d1..c5988f8 100644 (file)
@@ -28,8 +28,7 @@ void sendMessage(Capability *from_cap, Capability *to_cap, Message *msg)
 #ifdef DEBUG    
     {
         const StgInfoTable *i = msg->header.info;
-        if (i != &stg_MSG_WAKEUP_info &&
-            i != &stg_MSG_THROWTO_info &&
+        if (i != &stg_MSG_THROWTO_info &&
             i != &stg_MSG_BLACKHOLE_info &&
             i != &stg_MSG_TRY_WAKEUP_info &&
             i != &stg_IND_info && // can happen if a MSG_BLACKHOLE is revoked
@@ -47,9 +46,9 @@ void sendMessage(Capability *from_cap, Capability *to_cap, Message *msg)
     if (to_cap->running_task == NULL) {
        to_cap->running_task = myTask(); 
             // precond for releaseCapability_()
-       releaseCapability_(to_cap,rtsFalse);
+        releaseCapability_(to_cap,rtsFalse);
     } else {
-        contextSwitchCapability(to_cap);
+        interruptCapability(to_cap);
     }
 
     RELEASE_LOCK(&to_cap->lock);
@@ -71,25 +70,11 @@ executeMessage (Capability *cap, Message *m)
 loop:
     write_barrier(); // allow m->header to be modified by another thread
     i = m->header.info;
-    if (i == &stg_MSG_WAKEUP_info)
-    {
-        // the plan is to eventually get rid of these and use
-        // TRY_WAKEUP instead.
-        MessageWakeup *w = (MessageWakeup *)m;
-        StgTSO *tso = w->tso;
-        debugTraceCap(DEBUG_sched, cap, "message: wakeup thread %ld", 
-                      (lnat)tso->id);
-        ASSERT(tso->cap == cap);
-        ASSERT(tso->why_blocked == BlockedOnMsgWakeup);
-        ASSERT(tso->block_info.closure == (StgClosure *)m);
-        tso->why_blocked = NotBlocked;
-        appendToRunQueue(cap, tso);
-    }
-    else if (i == &stg_MSG_TRY_WAKEUP_info)
+    if (i == &stg_MSG_TRY_WAKEUP_info)
     {
         StgTSO *tso = ((MessageWakeup *)m)->tso;
         debugTraceCap(DEBUG_sched, cap, "message: try wakeup thread %ld", 
-                      (lnat)tso->id);
+                      (W_)tso->id);
         tryWakeupThread(cap, tso);
     }
     else if (i == &stg_MSG_THROWTO_info)
@@ -105,7 +90,7 @@ loop:
         }
 
         debugTraceCap(DEBUG_sched, cap, "message: throwTo %ld -> %ld", 
-                      (lnat)t->source->id, (lnat)t->target->id);
+                      (W_)t->source->id, (W_)t->target->id);
 
         ASSERT(t->source->why_blocked == BlockedOnMsgThrowTo);
         ASSERT(t->source->block_info.closure == (StgClosure *)m);
@@ -113,11 +98,13 @@ loop:
         r = throwToMsg(cap, t);
 
         switch (r) {
-        case THROWTO_SUCCESS:
+        case THROWTO_SUCCESS: {
             // this message is done
-            unlockClosure((StgClosure*)m, &stg_MSG_NULL_info);
-            tryWakeupThread(cap, t->source);
+            StgTSO *source = t->source;
+            doneWithMsgThrowTo(t);
+            tryWakeupThread(cap, source);
             break;
+        }
         case THROWTO_BLOCKED:
             // unlock the message
             unlockClosure((StgClosure*)m, &stg_MSG_THROWTO_info);
@@ -176,11 +163,11 @@ nat messageBlackHole(Capability *cap, MessageBlackHole *msg)
     const StgInfoTable *info;
     StgClosure *p;
     StgBlockingQueue *bq;
-    StgClosure *bh = msg->bh;
+    StgClosure *bh = UNTAG_CLOSURE(msg->bh);
     StgTSO *owner;
 
     debugTraceCap(DEBUG_sched, cap, "message: thread %d blocking on blackhole %p", 
-                  (lnat)msg->tso->id, msg->bh);
+                  (W_)msg->tso->id, msg->bh);
 
     info = bh->header.info;
 
@@ -190,6 +177,7 @@ nat messageBlackHole(Capability *cap, MessageBlackHole *msg)
     // all.
     if (info != &stg_BLACKHOLE_info && 
         info != &stg_CAF_BLACKHOLE_info && 
+        info != &__stg_EAGER_BLACKHOLE_info &&
         info != &stg_WHITEHOLE_info) {
         // if it is a WHITEHOLE, then a thread is in the process of
         // trying to BLACKHOLE it.  But we know that it was once a
@@ -198,9 +186,12 @@ nat messageBlackHole(Capability *cap, MessageBlackHole *msg)
         return 0;
     }
 
-    // we know at this point that the closure 
+    // The blackhole must indirect to a TSO, a BLOCKING_QUEUE, an IND,
+    // or a value.
 loop:
-    p = ((StgInd*)bh)->indirectee;
+    // NB. VOLATILE_LOAD(), because otherwise gcc hoists the load
+    // and turns this into an infinite loop.
+    p = UNTAG_CLOSURE((StgClosure*)VOLATILE_LOAD(&((StgInd*)bh)->indirectee));
     info = p->header.info;
 
     if (info == &stg_IND_info)
@@ -214,7 +205,7 @@ loop:
 
     else if (info == &stg_TSO_info)
     {
-        owner = deRefTSO((StgTSO *)p);
+        owner = (StgTSO*)p;
 
 #ifdef THREADED_RTS
         if (owner->cap != cap) {
@@ -255,8 +246,7 @@ loop:
         // the current thread, since in that case it will not be on
         // the run queue.
         if (owner->why_blocked == NotBlocked && owner->id != msg->tso->id) {
-            removeFromRunQueue(cap, owner);
-            pushOnRunQueue(cap,owner);
+            promoteInRunQueue(cap, owner);
         }
 
         // point to the BLOCKING_QUEUE from the BLACKHOLE
@@ -265,7 +255,7 @@ loop:
         recordClosureMutated(cap,bh); // bh was mutated
 
         debugTraceCap(DEBUG_sched, cap, "thread %d blocked on thread %d", 
-                      (lnat)msg->tso->id, (lnat)owner->id);
+                      (W_)msg->tso->id, (W_)owner->id);
 
         return 1; // blocked
     }
@@ -276,7 +266,7 @@ loop:
 
         ASSERT(bq->bh == bh);
 
-        owner = deRefTSO(bq->owner);
+        owner = bq->owner;
 
         ASSERT(owner != END_TSO_QUEUE);
 
@@ -298,12 +288,11 @@ loop:
         }
 
         debugTraceCap(DEBUG_sched, cap, "thread %d blocked on thread %d", 
-                      (lnat)msg->tso->id, (lnat)owner->id);
+                      (W_)msg->tso->id, (W_)owner->id);
 
         // See above, #3838
         if (owner->why_blocked == NotBlocked && owner->id != msg->tso->id) {
-            removeFromRunQueue(cap, owner);
-            pushOnRunQueue(cap,owner);
+            promoteInRunQueue(cap, owner);
         }
 
         return 1; // blocked
@@ -312,3 +301,46 @@ loop:
     return 0; // not blocked
 }
 
+// A shorter version of messageBlackHole(), that just returns the
+// owner (or NULL if the owner cannot be found, because the blackhole
+// has been updated in the meantime).
+
+StgTSO * blackHoleOwner (StgClosure *bh)
+{
+    const StgInfoTable *info;
+    StgClosure *p;
+
+    info = bh->header.info;
+
+    if (info != &stg_BLACKHOLE_info &&
+        info != &stg_CAF_BLACKHOLE_info && 
+        info != &__stg_EAGER_BLACKHOLE_info &&
+        info != &stg_WHITEHOLE_info) {
+        return NULL;
+    }
+
+    // The blackhole must indirect to a TSO, a BLOCKING_QUEUE, an IND,
+    // or a value.
+loop:
+    // NB. VOLATILE_LOAD(), because otherwise gcc hoists the load
+    // and turns this into an infinite loop.
+    p = UNTAG_CLOSURE((StgClosure*)VOLATILE_LOAD(&((StgInd*)bh)->indirectee));
+    info = p->header.info;
+
+    if (info == &stg_IND_info) goto loop;
+
+    else if (info == &stg_TSO_info)
+    {
+        return (StgTSO*)p;
+    }
+    else if (info == &stg_BLOCKING_QUEUE_CLEAN_info || 
+             info == &stg_BLOCKING_QUEUE_DIRTY_info)
+    {
+        StgBlockingQueue *bq = (StgBlockingQueue *)p;
+        return bq->owner;
+    }
+    
+    return NULL; // not blocked
+}
+
+