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);
else if (info == &stg_TSO_info)
{
- owner = deRefTSO((StgTSO *)p);
+ owner = (StgTSO*)p;
#ifdef THREADED_RTS
if (owner->cap != cap) {
ASSERT(bq->bh == bh);
- owner = deRefTSO(bq->owner);
+ owner = bq->owner;
ASSERT(owner != END_TSO_QUEUE);
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
+}
+
+