Ticket #4001: 0001-Implement-atomicReadMVar-fixing-4001.patch

File 0001-Implement-atomicReadMVar-fixing-4001.patch, 19.7 KB (added by ezyang, 2 years ago)

Improved patch with less fuzz

  • compiler/prelude/primops.txt.pp

    From b0c2b16d271274726b92083e8a4cc0466a18104d Mon Sep 17 00:00:00 2001
    From: "Edward Z. Yang" <[email protected]>
    Date: Fri, 14 Jun 2013 14:19:42 -0700
    Subject: [PATCH] Implement atomicReadMVar, fixing #4001.
    
    Adds an extra field to StgMVar, for the readers queue.
    
    Signed-off-by: Edward Z. Yang <[email protected]>
    ---
     compiler/prelude/primops.txt.pp          |    9 ++++
     includes/rts/Constants.h                 |   25 ++++-----
     includes/rts/storage/Closures.h          |    3 ++
     includes/stg/MiscClosures.h              |    3 ++
     rts/HeapStackCheck.cmm                   |   31 +++++++++++-
     rts/Linker.c                             |    2 +
     rts/PrimOps.cmm                          |   81 ++++++++++++++++++++++++++++++
     rts/RaiseAsync.c                         |   28 ++++++++++-
     rts/RaiseAsync.h                         |    1 +
     rts/RetainerProfile.c                    |    1 +
     rts/Schedule.c                           |    2 +
     rts/StgMiscClosures.cmm                  |    4 +-
     rts/Threads.c                            |    4 ++
     rts/Trace.c                              |    1 +
     rts/sm/Compact.c                         |    1 +
     rts/sm/Sanity.c                          |    1 +
     rts/sm/Scav.c                            |    1 +
     utils/deriveConstants/DeriveConstants.hs |    1 +
     18 files changed, 181 insertions(+), 18 deletions(-)
    
    diff --git a/compiler/prelude/primops.txt.pp b/compiler/prelude/primops.txt.pp
    index 4547281..1e7da58 100644
    a b primop TryPutMVarOp "tryPutMVar#" GenPrimOp 
    17171717   out_of_line      = True
    17181718   has_side_effects = True
    17191719
     1720primop  AtomicReadMVarOp "atomicReadMVar#" GenPrimOp
     1721   MVar# s a -> State# s -> (# State# s, a #)
     1722   {If {\tt MVar\#} is empty, block until it becomes full.
     1723   Then read its contents without modifying the MVar, without possibility
     1724   of intervention from other threads.}
     1725   with
     1726   out_of_line      = True
     1727   has_side_effects = True
     1728
    17201729primop  SameMVarOp "sameMVar#" GenPrimOp
    17211730   MVar# s a -> MVar# s a -> Bool
    17221731
  • includes/rts/Constants.h

    diff --git a/includes/rts/Constants.h b/includes/rts/Constants.h
    index 5ff4d4e..4739e3a 100644
    a b  
    202202 */
    203203#define NotBlocked          0
    204204#define BlockedOnMVar       1
    205 #define BlockedOnBlackHole  2
    206 #define BlockedOnRead       3
    207 #define BlockedOnWrite      4
    208 #define BlockedOnDelay      5
    209 #define BlockedOnSTM        6
     205#define BlockedOnMVarRead   2
     206#define BlockedOnBlackHole  3
     207#define BlockedOnRead       4
     208#define BlockedOnWrite      5
     209#define BlockedOnDelay      6
     210#define BlockedOnSTM        7
    210211
    211212/* Win32 only: */
    212 #define BlockedOnDoProc     7
     213#define BlockedOnDoProc     8
    213214
    214215/* Only relevant for PAR: */
    215216  /* blocked on a remote closure represented by a Global Address: */
    216 #define BlockedOnGA         8
     217#define BlockedOnGA         9
    217218  /* same as above but without sending a Fetch message */
    218 #define BlockedOnGA_NoSend  9
     219#define BlockedOnGA_NoSend  10
    219220/* Only relevant for THREADED_RTS: */
    220 #define BlockedOnCCall      10
    221 #define BlockedOnCCall_Interruptible 11
     221#define BlockedOnCCall      11
     222#define BlockedOnCCall_Interruptible 12
    222223   /* same as above but permit killing the worker thread */
    223224
    224225/* Involved in a message sent to tso->msg_cap */
    225 #define BlockedOnMsgThrowTo 12
     226#define BlockedOnMsgThrowTo 13
    226227
    227228/* The thread is not on any run queues, but can be woken up
    228229   by tryWakeupThread() */
    229 #define ThreadMigrating     13
     230#define ThreadMigrating     14
    230231
    231232/*
    232233 * These constants are returned to the scheduler by a thread that has
  • includes/rts/storage/Closures.h

    diff --git a/includes/rts/storage/Closures.h b/includes/rts/storage/Closures.h
    index 1eef182..f9f3012 100644
    a b typedef struct { 
    266266    StgHeader                header;
    267267    struct StgMVarTSOQueue_ *head;
    268268    struct StgMVarTSOQueue_ *tail;
     269    // Not actually a queue, since we don't maintain a head pointer;
     270    // FIFO behavior is not necessary since we wake everyone up.
     271    struct StgMVarTSOQueue_ *readers;
    269272    StgClosure*              value;
    270273} StgMVar;
    271274
  • includes/stg/MiscClosures.h

    diff --git a/includes/stg/MiscClosures.h b/includes/stg/MiscClosures.h
    index b9b4f23..037508b 100644
    a b RTS_FUN_DECL(stg_block_noregs); 
    292292RTS_FUN_DECL(stg_block_blackhole);
    293293RTS_FUN_DECL(stg_block_blackhole_finally);
    294294RTS_FUN_DECL(stg_block_takemvar);
     295RTS_FUN_DECL(stg_block_atomicreadmvar);
    295296RTS_RET(stg_block_takemvar);
     297RTS_RET(stg_block_atomicreadmvar);
    296298RTS_FUN_DECL(stg_block_putmvar);
    297299RTS_RET(stg_block_putmvar);
    298300#ifdef mingw32_HOST_OS
    RTS_FUN_DECL(stg_isEmptyMVarzh); 
    375377RTS_FUN_DECL(stg_newMVarzh);
    376378RTS_FUN_DECL(stg_takeMVarzh);
    377379RTS_FUN_DECL(stg_putMVarzh);
     380RTS_FUN_DECL(stg_atomicReadMVarzh);
    378381RTS_FUN_DECL(stg_tryTakeMVarzh);
    379382RTS_FUN_DECL(stg_tryPutMVarzh);
    380383
  • rts/HeapStackCheck.cmm

    diff --git a/rts/HeapStackCheck.cmm b/rts/HeapStackCheck.cmm
    index fbceb76..20cd9df 100644
    a b stg_block_noregs 
    487487/* -----------------------------------------------------------------------------
    488488 * takeMVar/putMVar-specific blocks
    489489 *
    490  * Stack layout for a thread blocked in takeMVar:
     490 * Stack layout for a thread blocked in takeMVar/atomicReadMVar:
    491491 *     
    492492 *       ret. addr
    493493 *       ptr to MVar   (R1)
    494  *       stg_block_takemvar_info
     494 *       stg_block_takemvar_info (or stg_block_readmvar_info)
    495495 *
    496496 * Stack layout for a thread blocked in putMVar:
    497497 *     
    stg_block_takemvar /* mvar passed in R1 */ 
    531531    BLOCK_BUT_FIRST(stg_block_takemvar_finally);
    532532}
    533533
     534INFO_TABLE_RET ( stg_block_atomicreadmvar, RET_SMALL, W_ info_ptr, P_ mvar )
     535    return ()
     536{
     537    jump stg_atomicReadMVarzh(mvar);
     538}
     539
     540// code fragment executed just before we return to the scheduler
     541stg_block_atomicreadmvar_finally
     542{
     543    W_ r1, r3;
     544    r1 = R1;
     545    r3 = R3;
     546    unlockClosure(R3, stg_MVAR_DIRTY_info);
     547    R1 = r1;
     548    R3 = r3;
     549    jump StgReturn [R1];
     550}
     551
     552stg_block_atomicreadmvar /* mvar passed in R1 */
     553{
     554    Sp_adj(-2);
     555    Sp(1) = R1;
     556    Sp(0) = stg_block_atomicreadmvar_info;
     557    R3 = R1; // mvar communicated to stg_block_atomicreadmvar_finally in R3
     558    BLOCK_BUT_FIRST(stg_block_atomicreadmvar_finally);
     559}
     560
    534561INFO_TABLE_RET( stg_block_putmvar, RET_SMALL, W_ info_ptr,
    535562                P_ mvar, P_ val )
    536563    return ()
  • rts/Linker.c

    diff --git a/rts/Linker.c b/rts/Linker.c
    index 47eb6b0..20978af 100644
    a b typedef struct _RtsSymbolVal { 
    10581058      SymI_HasProto(stg_yield_to_interpreter)                           \
    10591059      SymI_HasProto(stg_block_noregs)                                   \
    10601060      SymI_HasProto(stg_block_takemvar)                                 \
     1061      SymI_HasProto(stg_block_atomicreadmvar)                           \
    10611062      SymI_HasProto(stg_block_putmvar)                                  \
    10621063      MAIN_CAP_SYM                                                      \
    10631064      SymI_HasProto(MallocFailHook)                                     \
    typedef struct _RtsSymbolVal { 
    13141315      SymI_HasProto(stg_bh_upd_frame_info)                              \
    13151316      SymI_HasProto(suspendThread)                                      \
    13161317      SymI_HasProto(stg_takeMVarzh)                                     \
     1318      SymI_HasProto(stg_atomicReadMVarzh)                               \
    13171319      SymI_HasProto(stg_threadStatuszh)                                 \
    13181320      SymI_HasProto(stg_tryPutMVarzh)                                   \
    13191321      SymI_HasProto(stg_tryTakeMVarzh)                                  \
  • rts/PrimOps.cmm

    diff --git a/rts/PrimOps.cmm b/rts/PrimOps.cmm
    index 230b929..ce65d12 100644
    a b stg_newMVarzh () 
    11701170    StgMVar_head(mvar)  = stg_END_TSO_QUEUE_closure;
    11711171    StgMVar_tail(mvar)  = stg_END_TSO_QUEUE_closure;
    11721172    StgMVar_value(mvar) = stg_END_TSO_QUEUE_closure;
     1173    StgMVar_readers(mvar) = stg_END_TSO_QUEUE_closure;
    11731174    return (mvar);
    11741175}
    11751176
    loop: 
    13481349    return (1,val);
    13491350}
    13501351
     1352#define WakeupReaders(mvar, val)                                \
     1353    W_ q, tso, stack;                                           \
     1354    q = StgMVar_readers(mvar);                                  \
     1355rloop:                                                          \
     1356    if (q == stg_END_TSO_QUEUE_closure) {                       \
     1357        StgMVar_readers(mvar) = stg_END_TSO_QUEUE_closure;      \
     1358        goto rdone;                                             \
     1359    }                                                           \
     1360    if (StgHeader_info(q) == stg_IND_info) {                    \
     1361        q = StgInd_indirectee(q);                               \
     1362        goto rloop;                                             \
     1363    }                                                           \
     1364    tso = StgMVarTSOQueue_tso(q);                               \
     1365                                                                \
     1366    ASSERT(StgTSO_why_blocked(tso) == BlockedOnMVarRead::I16);  \
     1367    ASSERT(StgTSO_block_info(tso) == mvar);                     \
     1368                                                                \
     1369    stack = StgTSO_stackobj(tso);                               \
     1370    PerformTake(stack, val);                                    \
     1371    StgTSO__link(tso) = stg_END_TSO_QUEUE_closure;              \
     1372    if (TO_W_(StgStack_dirty(stack)) == 0) {                    \
     1373        ccall dirty_STACK(MyCapability() "ptr", stack "ptr");   \
     1374    }                                                           \
     1375                                                                \
     1376    ccall tryWakeupThread(MyCapability() "ptr", tso);           \
     1377                                                                \
     1378    q = StgMVarTSOQueue_link(q);                                \
     1379    goto rloop;                                                 \
     1380rdone:
     1381
    13511382stg_putMVarzh ( P_ mvar, /* :: MVar a */
    13521383                P_ val,  /* :: a */ )
    13531384{
    stg_putMVarzh ( P_ mvar, /* :: MVar a */ 
    13941425        jump stg_block_putmvar(mvar,val);
    13951426    }
    13961427
     1428    WakeupReaders(mvar, val);
     1429
    13971430    q = StgMVar_head(mvar);
    13981431loop:
    13991432    if (q == stg_END_TSO_QUEUE_closure) {
    stg_tryPutMVarzh ( P_ mvar, /* :: MVar a */ 
    14601493        ccall dirty_MVAR(BaseReg "ptr", mvar "ptr");
    14611494    }
    14621495
     1496    WakeupReaders(mvar, val);
     1497
    14631498    q = StgMVar_head(mvar);
    14641499loop:
    14651500    if (q == stg_END_TSO_QUEUE_closure) {
    loop: 
    15031538    return (1);
    15041539}
    15051540
     1541// see stg_takeMVarzh for more commentary
     1542stg_atomicReadMVarzh ( P_ mvar, /* :: MVar a */ )
     1543{
     1544    W_ val, info, tso, q;
     1545
     1546#if defined(THREADED_RTS)
     1547    ("ptr" info) = ccall lockClosure(mvar "ptr");
     1548#else
     1549    info = GET_INFO(mvar);
     1550#endif
     1551
     1552    if (info == stg_MVAR_CLEAN_info) {
     1553        ccall dirty_MVAR(BaseReg "ptr", mvar "ptr");
     1554    }
     1555
     1556    /* If the MVar is empty, put ourselves on the blocked readers
     1557     * list and wait until we're woken up.
     1558     */
     1559    if (StgMVar_value(mvar) == stg_END_TSO_QUEUE_closure) {
     1560
     1561        ALLOC_PRIM_WITH_CUSTOM_FAILURE
     1562            (SIZEOF_StgMVarTSOQueue,
     1563             unlockClosure(mvar, stg_MVAR_DIRTY_info);
     1564             GC_PRIM_P(stg_atomicReadMVarzh, mvar));
     1565
     1566        q = Hp - SIZEOF_StgMVarTSOQueue + WDS(1);
     1567
     1568        // not a queue, so we can just push it onto the front
     1569        SET_HDR(q, stg_MVAR_TSO_QUEUE_info, CCS_SYSTEM);
     1570        StgMVarTSOQueue_link(q) = StgMVar_readers(mvar);
     1571        StgMVarTSOQueue_tso(q)  = CurrentTSO;
     1572
     1573        StgTSO__link(CurrentTSO)       = q;
     1574        StgTSO_block_info(CurrentTSO)  = mvar;
     1575        StgTSO_why_blocked(CurrentTSO) = BlockedOnMVarRead::I16;
     1576        StgMVar_readers(mvar)          = q;
     1577
     1578        jump stg_block_atomicreadmvar(mvar);
     1579    }
     1580
     1581    val = StgMVar_value(mvar);
     1582
     1583    unlockClosure(mvar, stg_MVAR_DIRTY_info);
     1584    return (val);
     1585}
     1586
    15061587
    15071588/* -----------------------------------------------------------------------------
    15081589   Stable pointer primitives
  • rts/RaiseAsync.c

    diff --git a/rts/RaiseAsync.c b/rts/RaiseAsync.c
    index 11f518a..2b87b26 100644
    a b static StgTSO* raiseAsync (Capability *cap, 
    3232static void removeFromQueues(Capability *cap, StgTSO *tso);
    3333
    3434static void removeFromMVarBlockedQueue (StgTSO *tso);
     35static void removeFromMVarReadBlockedQueue (StgTSO *tso);
    3536
    3637static void blockedThrowTo (Capability *cap,
    3738                            StgTSO *target, MessageThrowTo *msg);
    check_target: 
    294295    }
    295296
    296297    case BlockedOnMVar:
     298    case BlockedOnMVarRead:
    297299    {
    298300        /*
    299301          To establish ownership of this TSO, we need to acquire a
    check_target: 
    318320
    319321        // we have the MVar, let's check whether the thread
    320322        // is still blocked on the same MVar.
    321         if (target->why_blocked != BlockedOnMVar
     323        if (target->why_blocked != status
    322324            || (StgMVar *)target->block_info.closure != mvar) {
    323325            unlockClosure((StgClosure *)mvar, info);
    324326            goto retry;
    check_target: 
    341343            return THROWTO_BLOCKED;
    342344        } else {
    343345            // revoke the MVar operation
    344             removeFromMVarBlockedQueue(target);
     346            if (status == BlockedOnMVar) {
     347                removeFromMVarBlockedQueue(target);
     348            } else {
     349                ASSERT(status == BlockedOnMVarRead);
     350                removeFromMVarReadBlockedQueue(target);
     351            }
    345352            raiseAsync(cap, target, msg->exception, rtsFalse, NULL);
    346353            unlockClosure((StgClosure *)mvar, info);
    347354            return THROWTO_SUCCESS;
    removeFromMVarBlockedQueue (StgTSO *tso) 
    619626}
    620627
    621628static void
     629removeFromMVarReadBlockedQueue (StgTSO *tso)
     630{
     631    StgMVarTSOQueue *q = (StgMVarTSOQueue*)tso->_link;
     632
     633    if (q == (StgMVarTSOQueue*)END_TSO_QUEUE) {
     634        return;
     635    }
     636
     637    OVERWRITE_INFO(q, &stg_IND_info);
     638    tso->_link = END_TSO_QUEUE;
     639}
     640
     641static void
    622642removeFromQueues(Capability *cap, StgTSO *tso)
    623643{
    624644  switch (tso->why_blocked) {
    removeFromQueues(Capability *cap, StgTSO *tso) 
    640660      removeFromMVarBlockedQueue(tso);
    641661      goto done;
    642662
     663  case BlockedOnMVarRead:
     664      removeFromMVarReadBlockedQueue(tso);
     665      goto done;
     666
    643667  case BlockedOnBlackHole:
    644668      // nothing to do
    645669      goto done;
  • rts/RaiseAsync.h

    diff --git a/rts/RaiseAsync.h b/rts/RaiseAsync.h
    index 336ab30..d804f6b 100644
    a b interruptible(StgTSO *t) 
    4949{
    5050  switch (t->why_blocked) {
    5151  case BlockedOnMVar:
     52  case BlockedOnMVarRead:
    5253  case BlockedOnMsgThrowTo:
    5354  case BlockedOnRead:
    5455  case BlockedOnWrite:
  • rts/RetainerProfile.c

    diff --git a/rts/RetainerProfile.c b/rts/RetainerProfile.c
    index 4e7ed3e..c25c4b4 100644
    a b inner_loop: 
    16721672        retainClosure(tso->bq,                 c, c_child_r);
    16731673        retainClosure(tso->trec,               c, c_child_r);
    16741674        if (   tso->why_blocked == BlockedOnMVar
     1675               || tso->why_blocked == BlockedOnMVarRead
    16751676               || tso->why_blocked == BlockedOnBlackHole
    16761677               || tso->why_blocked == BlockedOnMsgThrowTo
    16771678            ) {
  • rts/Schedule.c

    diff --git a/rts/Schedule.c b/rts/Schedule.c
    index abd317c..85bb89e 100644
    a b scheduleDetectDeadlock (Capability **pcap, Task *task) 
    947947            case BlockedOnBlackHole:
    948948            case BlockedOnMsgThrowTo:
    949949            case BlockedOnMVar:
     950            case BlockedOnMVarRead:
    950951                throwToSingleThreaded(cap, task->incall->tso,
    951952                                      (StgClosure *)nonTermination_closure);
    952953                return;
    resurrectThreads (StgTSO *threads) 
    28312832       
    28322833        switch (tso->why_blocked) {
    28332834        case BlockedOnMVar:
     2835        case BlockedOnMVarRead:
    28342836            /* Called by GC - sched_mutex lock is currently held. */
    28352837            throwToSingleThreaded(cap, tso,
    28362838                                  (StgClosure *)blockedIndefinitelyOnMVar_closure);
  • rts/StgMiscClosures.cmm

    diff --git a/rts/StgMiscClosures.cmm b/rts/StgMiscClosures.cmm
    index 28a41ad..63bc67f 100644
    a b INFO_TABLE(stg_STABLE_NAME,0,1,PRIM,"STABLE_NAME","STABLE_NAME") 
    464464   and entry code for each type.
    465465   ------------------------------------------------------------------------- */
    466466
    467 INFO_TABLE(stg_MVAR_CLEAN,3,0,MVAR_CLEAN,"MVAR","MVAR")
     467INFO_TABLE(stg_MVAR_CLEAN,4,0,MVAR_CLEAN,"MVAR","MVAR")
    468468{ foreign "C" barf("MVAR object entered!") never returns; }
    469469
    470 INFO_TABLE(stg_MVAR_DIRTY,3,0,MVAR_DIRTY,"MVAR","MVAR")
     470INFO_TABLE(stg_MVAR_DIRTY,4,0,MVAR_DIRTY,"MVAR","MVAR")
    471471{ foreign "C" barf("MVAR object entered!") never returns; }
    472472
    473473/* -----------------------------------------------------------------------------
  • rts/Threads.c

    diff --git a/rts/Threads.c b/rts/Threads.c
    index 4c990f1..f2b8005 100644
    a b tryWakeupThread (Capability *cap, StgTSO *tso) 
    255255    switch (tso->why_blocked)
    256256    {
    257257    case BlockedOnMVar:
     258    case BlockedOnMVarRead:
    258259    {
    259260        if (tso->_link == END_TSO_QUEUE) {
    260261            tso->block_info.closure = (StgClosure*)END_TSO_QUEUE;
    printThreadBlockage(StgTSO *tso) 
    734735  case BlockedOnMVar:
    735736    debugBelch("is blocked on an MVar @ %p", tso->block_info.closure);
    736737    break;
     738  case BlockedOnMVarRead:
     739    debugBelch("is blocked on atomic MVar read @ %p", tso->block_info.closure);
     740    break;
    737741  case BlockedOnBlackHole:
    738742      debugBelch("is blocked on a black hole %p",
    739743                 ((StgBlockingQueue*)tso->block_info.bh->bh));
  • rts/Trace.c

    diff --git a/rts/Trace.c b/rts/Trace.c
    index 78dfead..2190189 100644
    a b static char *thread_stop_reasons[] = { 
    179179    [ThreadFinished] = "finished",
    180180    [THREAD_SUSPENDED_FOREIGN_CALL] = "suspended while making a foreign call",
    181181    [6 + BlockedOnMVar]         = "blocked on an MVar",
     182    [6 + BlockedOnMVarRead]     = "blocked on an atomic MVar read",
    182183    [6 + BlockedOnBlackHole]    = "blocked on a black hole",
    183184    [6 + BlockedOnRead]         = "blocked on a read operation",
    184185    [6 + BlockedOnWrite]        = "blocked on a write operation",
  • rts/sm/Compact.c

    diff --git a/rts/sm/Compact.c b/rts/sm/Compact.c
    index 7c89418..fb40994 100644
    a b thread_TSO (StgTSO *tso) 
    442442    thread_(&tso->global_link);
    443443
    444444    if (   tso->why_blocked == BlockedOnMVar
     445        || tso->why_blocked == BlockedOnMVarRead
    445446        || tso->why_blocked == BlockedOnBlackHole
    446447        || tso->why_blocked == BlockedOnMsgThrowTo
    447448        || tso->why_blocked == NotBlocked
  • rts/sm/Sanity.c

    diff --git a/rts/sm/Sanity.c b/rts/sm/Sanity.c
    index f0e1659..9b579ab 100644
    a b checkTSO(StgTSO *tso) 
    519519           info == &stg_WHITEHOLE_info); // happens due to STM doing lockTSO()
    520520
    521521    if (   tso->why_blocked == BlockedOnMVar
     522        || tso->why_blocked == BlockedOnMVarRead
    522523        || tso->why_blocked == BlockedOnBlackHole
    523524        || tso->why_blocked == BlockedOnMsgThrowTo
    524525        || tso->why_blocked == NotBlocked
  • rts/sm/Scav.c

    diff --git a/rts/sm/Scav.c b/rts/sm/Scav.c
    index 6137f6d..e0cc688 100644
    a b scavengeTSO (StgTSO *tso) 
    7171
    7272    evacuate((StgClosure **)&tso->_link);
    7373    if (   tso->why_blocked == BlockedOnMVar
     74        || tso->why_blocked == BlockedOnMVarRead
    7475        || tso->why_blocked == BlockedOnBlackHole
    7576        || tso->why_blocked == BlockedOnMsgThrowTo
    7677        || tso->why_blocked == NotBlocked
  • utils/deriveConstants/DeriveConstants.hs

    diff --git a/utils/deriveConstants/DeriveConstants.hs b/utils/deriveConstants/DeriveConstants.hs
    index 78233a5..a57ceb3 100644
    a b wanteds = concat 
    477477          ,closureSize  C "StgMVar"
    478478          ,closureField C "StgMVar" "head"
    479479          ,closureField C "StgMVar" "tail"
     480          ,closureField C "StgMVar" "readers"
    480481          ,closureField C "StgMVar" "value"
    481482
    482483          ,closureSize  C "StgMVarTSOQueue"