Question about indirectees of BLACKHOLE closures

Ömer Sinan Ağacan omeragacan at gmail.com
Sat Mar 24 19:27:04 UTC 2018


Hi Rahul,

I'm still confused. The code that walks the stack and updates UPDATE_FRAMEs
only makes indirections point to the "raise" closure, not to thunks or anything
else (I also don't understand why this is needed but I guess that's another
topic). I still don't see how can a BLACKHOLE point to a THUNK.

Ömer

2018-03-23 18:51 GMT+03:00 Rahul Muttineni <rahulmutt at gmail.com>:
> Hi Omer,
>
> As per my understanding, a BLACKHOLE can point to a THUNK when an exception
> is thrown. An exception walks up the stack and overwrites the blackholes
> pointed to by the update frames as it walks with an stg_raise closure. That
> way, if any concurrent thread happens to evaluate a thunk that was walked,
> it'll evaluate the thunk which will blow up as well thereby throwing the
> exception on the other thread(s) too.
>
> Definition of stg_raise:
> https://github.com/ghc/ghc/blob/ba5797937e575ce6119de6c07703e90dda2557e8/rts/Exception.cmm#L424-L427
>
> raiseExceptionHelper dealing with update frames:
> https://github.com/ghc/ghc/blob/d9d463289fe20316cff12a8f0dbf414db678fa72/rts/Schedule.c#L2864-L2875
>
> In general, yes, you can think that a BLACKHOLE will point to a non-THUNK
> object assuming that everything went right.
>
> Hope that helps,
> Rahul
>
> On Fri, Mar 23, 2018 at 5:48 PM, Ömer Sinan Ağacan <omeragacan at gmail.com>
> wrote:
>>
>> Thanks Simon, that's really helpful.
>>
>> A few more questions:
>>
>> As far as I understand the difference between
>>
>> - BLACKHOLE pointing to a TSO
>> - BLACKHOLE pointing to a BLOCKING_QUEUE
>>
>> is that in the former we don't yet have any threads blocked by the
>> BLACKHOLE
>> whereas in the latter we have and the blocking queue holds all those
>> blocked
>> threads. Did I get this right?
>>
>> Secondly, can a BLACKHOLE point to a THUNK? I'd expect no, because we
>> BLACKHOLE
>> a closure when we're done evaluating it (assuming no eager blackholing),
>> and
>> evaluation usually happens up to WHNF.
>>
>> Thanks,
>>
>> Ömer
>>
>> 2018-03-20 18:27 GMT+03:00 Simon Marlow <marlowsd at gmail.com>:
>> > Added comments: https://phabricator.haskell.org/D4517
>> >
>> > On 20 March 2018 at 14:58, Simon Marlow <marlowsd at gmail.com> wrote:
>> >>
>> >> Hi Omer,
>> >>
>> >> On 20 March 2018 at 13:05, Ömer Sinan Ağacan <omeragacan at gmail.com>
>> >> wrote:
>> >>>
>> >>> Hi,
>> >>>
>> >>> I've been looking at BLACKHOLE closures and how the indirectee field
>> >>> is
>> >>> used
>> >>> and I have a few questions:
>> >>>
>> >>> Looking at evacuate for BLACKHOLE closures:
>> >>>
>> >>>     case BLACKHOLE:
>> >>>     {
>> >>>         StgClosure *r;
>> >>>         const StgInfoTable *i;
>> >>>         r = ((StgInd*)q)->indirectee;
>> >>>         if (GET_CLOSURE_TAG(r) == 0) {
>> >>>             i = r->header.info;
>> >>>             if (IS_FORWARDING_PTR(i)) {
>> >>>                 r = (StgClosure *)UN_FORWARDING_PTR(i);
>> >>>                 i = r->header.info;
>> >>>             }
>> >>>             if (i == &stg_TSO_info
>> >>>                 || i == &stg_WHITEHOLE_info
>> >>>                 || i == &stg_BLOCKING_QUEUE_CLEAN_info
>> >>>                 || i == &stg_BLOCKING_QUEUE_DIRTY_info) {
>> >>>                 copy(p,info,q,sizeofW(StgInd),gen_no);
>> >>>                 return;
>> >>>             }
>> >>>             ASSERT(i != &stg_IND_info);
>> >>>         }
>> >>>         q = r;
>> >>>         *p = r;
>> >>>         goto loop;
>> >>>     }
>> >>>
>> >>> It seems like indirectee can be a TSO, WHITEHOLE,
>> >>> BLOCKING_QUEUE_CLEAN,
>> >>> BLOCKING_QUEUE_DIRTY, and it can't be IND. I'm wondering what does it
>> >>> mean for
>> >>> a BLACKHOLE to point to a
>> >>>
>> >>> - TSO
>> >>> - WHITEHOLE
>> >>> - BLOCKING_QUEUE_CLEAN
>> >>> - BLOCKING_QUEUE_DIRTY
>> >>
>> >>
>> >> That sounds right to me.
>> >>
>> >>>
>> >>> Is this documented somewhere or otherwise could someone give a few
>> >>> pointers on
>> >>> where to look in the code?
>> >>
>> >>
>> >> Unfortunately I don't think we have good documentation for this, but
>> >> you
>> >> should look at the comments around messageBlackHole in Messages.c.
>> >>
>> >>>
>> >>> Secondly, I also looked at the BLACKHOLE entry code, and it seems like
>> >>> it
>> >>> has a
>> >>> different assumption about what can indirectee field point to:
>> >>>
>> >>>     INFO_TABLE(stg_BLACKHOLE,1,0,BLACKHOLE,"BLACKHOLE","BLACKHOLE")
>> >>>         (P_ node)
>> >>>     {
>> >>>         W_ r, info, owner, bd;
>> >>>         P_ p, bq, msg;
>> >>>
>> >>>         TICK_ENT_DYN_IND(); /* tick */
>> >>>
>> >>>     retry:
>> >>>         p = StgInd_indirectee(node);
>> >>>         if (GETTAG(p) != 0) {
>> >>>             return (p);
>> >>>         }
>> >>>
>> >>>         info = StgHeader_info(p);
>> >>>         if (info == stg_IND_info) {
>> >>>             // This could happen, if e.g. we got a BLOCKING_QUEUE that
>> >>> has
>> >>>             // just been replaced with an IND by another thread in
>> >>>             // wakeBlockingQueue().
>> >>>             goto retry;
>> >>>         }
>> >>>
>> >>>         if (info == stg_TSO_info ||
>> >>>             info == stg_BLOCKING_QUEUE_CLEAN_info ||
>> >>>             info == stg_BLOCKING_QUEUE_DIRTY_info)
>> >>>         {
>> >>>             ("ptr" msg) = ccall allocate(MyCapability() "ptr",
>> >>>
>> >>> BYTES_TO_WDS(SIZEOF_MessageBlackHole));
>> >>>
>> >>>             SET_HDR(msg, stg_MSG_BLACKHOLE_info, CCS_SYSTEM);
>> >>>             MessageBlackHole_tso(msg) = CurrentTSO;
>> >>>             MessageBlackHole_bh(msg) = node;
>> >>>
>> >>>             (r) = ccall messageBlackHole(MyCapability() "ptr", msg
>> >>> "ptr");
>> >>>
>> >>>             if (r == 0) {
>> >>>                 goto retry;
>> >>>             } else {
>> >>>                 StgTSO_why_blocked(CurrentTSO) =
>> >>> BlockedOnBlackHole::I16;
>> >>>                 StgTSO_block_info(CurrentTSO) = msg;
>> >>>                 jump stg_block_blackhole(node);
>> >>>             }
>> >>>         }
>> >>>         else
>> >>>         {
>> >>>             ENTER(p);
>> >>>         }
>> >>>     }
>> >>>
>> >>> The difference is, when the tag of indirectee is 0, evacuate assumes
>> >>> that
>> >>> indirectee can't point to an IND, but BLACKHOLE entry code thinks it's
>> >>> possible
>> >>> and there's even a comment about why. (I don't understand the comment
>> >>> yet) I'm
>> >>> wondering if this code is correct, and why. Again any pointers would
>> >>> be
>> >>> appreciated.
>> >>
>> >>
>> >> Taking a quick look at the code, my guess is that:
>> >> - a BLOCKING_QUEUE gets overwritten by an IND in wakeBlockingQueue()
>> >> - but when this happens, the indirectee of the BLACKHOLE will also be
>> >> overwritten to point to the value
>> >>
>> >> At runtime a thread might see an intermediate state because these
>> >> mutations are happening in another thread, so we might follow the
>> >> indirectee
>> >> and see the IND. But this state can't be observed by the GC, because
>> >> all
>> >> mutator threads have stopped at a safe point.
>> >>
>> >> Cheers
>> >> Simon
>> >>
>> >>
>> >>>
>> >>> Thanks,
>> >>>
>> >>> Ömer
>> >>> _______________________________________________
>> >>> ghc-devs mailing list
>> >>> ghc-devs at haskell.org
>> >>> http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
>> >>
>> >>
>> >
>> _______________________________________________
>> ghc-devs mailing list
>> ghc-devs at haskell.org
>> http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs
>
>
>
>
> --
> Rahul Muttineni


More information about the ghc-devs mailing list