+#if defined(THREADED_RTS)
+ // In threaded mode, we'll use WHITEHOLE to lock the selector
+ // thunk while we evaluate it.
+ {
+ do {
+ info_ptr = xchg((StgPtr)&p->header.info, (W_)&stg_WHITEHOLE_info);
+ } while (info_ptr == (W_)&stg_WHITEHOLE_info);
+
+ // make sure someone else didn't get here first...
+ if (IS_FORWARDING_PTR(p) ||
+ INFO_PTR_TO_STRUCT(info_ptr)->type != THUNK_SELECTOR) {
+ // v. tricky now. The THUNK_SELECTOR has been evacuated
+ // by another thread, and is now either a forwarding ptr or IND.
+ // We need to extract ourselves from the current situation
+ // as cleanly as possible.
+ // - unlock the closure
+ // - update *q, we may have done *some* evaluation
+ // - if evac, we need to call evacuate(), because we
+ // need the write-barrier stuff.
+ // - undo the chain we've built to point to p.
+ SET_INFO(p, (const StgInfoTable *)info_ptr);
+ *q = (StgClosure *)p;
+ if (evac) evacuate(q);
+ unchain_thunk_selectors(prev_thunk_selector, (StgClosure *)p);
+ return;
+ }
+ }
+#else
+ // Save the real info pointer (NOTE: not the same as get_itbl()).
+ info_ptr = (StgWord)p->header.info;