MessageThrowTo * throwTo (Capability *cap, // the Capability we hold StgTSO *source, // the TSO sending the exception (or NULL) StgTSO *target, // the TSO receiving the exception StgClosure *exception) // the exception closure { MessageThrowTo *msg; msg = (MessageThrowTo *) allocate(cap, sizeofW(MessageThrowTo)); // the message starts locked; see below SET_HDR(msg, &stg_WHITEHOLE_info, CCS_SYSTEM); msg->source = source; msg->target = target; msg->exception = exception; switch (throwToMsg(cap, msg)) { case THROWTO_SUCCESS: // unlock the message now, otherwise we leave a WHITEHOLE in // the heap (#6103) SET_HDR(msg, &stg_MSG_THROWTO_info, CCS_SYSTEM); return NULL; case THROWTO_BLOCKED: default: // the caller will unlock the message when it is ready. We // cannot unlock it yet, because the calling thread will need // to tidy up its state first. return msg; } }
void executeMessage (Capability *cap, Message *m) { const StgInfoTable *i; loop: write_barrier(); // allow m->header to be modified by another thread i = m->header.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); tryWakeupThread(cap, tso); } else if (i == &stg_MSG_THROWTO_info) { MessageThrowTo *t = (MessageThrowTo *)m; nat r; const StgInfoTable *i; i = lockClosure((StgClosure*)m); if (i != &stg_MSG_THROWTO_info) { unlockClosure((StgClosure*)m, i); goto loop; } debugTraceCap(DEBUG_sched, cap, "message: throwTo %ld -> %ld", (lnat)t->source->id, (lnat)t->target->id); ASSERT(t->source->why_blocked == BlockedOnMsgThrowTo); ASSERT(t->source->block_info.closure == (StgClosure *)m); r = throwToMsg(cap, t); switch (r) { case THROWTO_SUCCESS: { // this message is done StgTSO *source = t->source; doneWithMsgThrowTo(t); tryWakeupThread(cap, source); break; } case THROWTO_BLOCKED: // unlock the message unlockClosure((StgClosure*)m, &stg_MSG_THROWTO_info); break; } } else if (i == &stg_MSG_BLACKHOLE_info) { nat r; MessageBlackHole *b = (MessageBlackHole*)m; r = messageBlackHole(cap, b); if (r == 0) { tryWakeupThread(cap, b->tso); } return; } else if (i == &stg_IND_info || i == &stg_MSG_NULL_info) { // message was revoked return; } else if (i == &stg_WHITEHOLE_info) { goto loop; } else { barf("executeMessage: %p", i); } }