Skip to content

Data race in `readTVarIO#`?

Currently readTVarIO# is defined thusly (annotations are my own):

stg_readTVarIOzh ( P_ tvar /* :: TVar a */ )
{
    W_ result, resultinfo;

again:
    result = StgTVar_current_value(tvar);
                                                    // (1)
    resultinfo = %INFO_PTR(result);
    prim_read_barrier;                              // (2)
    if (resultinfo == stg_TREC_HEADER_info) {
        goto again;
    }
    return (result);
}

I'm skeptical that the barriers here are correct. In particular, it seems to me that there should be a read barrier between the load from tvar->current_value and the %INFO_PTR load (point (1)). Secondly, I don't believe that the barrier at (2) is necessary.

IMHO, this is all much easier to reason about with C11-style release acquire semantics. Under this worldview, the load from current_value should be an acquire-load, which will synchronize with the release-store in unlock_tvar. This will guarantee a happens-before relationship, which then allows us to conclude that the barrier at (2) is redundant since the construction of the closure necessarily happens-before the store in unlock_tvar.

To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information