<div dir="ltr"><br><div style>Hi,</div><div style><br></div><div style>I ended up staring at the PrimOps.cmm file today, and porting tryPutMVar to C so it can be used from the RTS.</div><div style><br></div><div style>During my staring, it occurred to me that it should be possible to implement a wait-on-multiple MVars with mostly no overhead.  I am guessing that this would be desirable, but I am not sure.</div>

<div style><br></div><div style>My rough idea is like this:</div><div style><br></div><div style>-- wait for all MVars, return the value of one of them, and the corresponding index</div><div style>takeOneMVar :: [MVar a] -&gt; IO (a, Int)</div>

<div style><br></div><div style>This is implemented by this change:</div><div style><br></div><div style><div>typedef struct StgMVarTSOQueue_ {</div><div>    StgHeader                header;</div><div>    struct StgMVarTSOQueue_ *link;</div>

<div><b>    // The group_head and group_link are used when a TSO is waiting on</b></div><div><b>    // multiple MVars.  Multiple StgMVarTSOQueue objects</b></div><div><b>    // are created, one for each MVar, and they are linked using the</b></div>

<div><b>    // group_link pointer.  group_head always points to the first</b></div><div><b>    // element. The tso pointer will always be the same in this case.</b></div><div style><b>    // The group head acts as a synchronization element for the whole group.</b></div>

<div style><b>    // When the    group head lock is acquired, the owner can invalidate the group</b></div><div style><b>    struct StgMVarTSOQueue  *group_head;</b><br></div><div><b>    struct StgMVarTSOQueue  *group_link;</b></div>

<div>    struct StgTSO_          *tso;</div><div>} StgMVarTSOQueue;</div><div><br></div><div style>Now, whenever a TSO should be woken up by the MVar code, if </div><div style><br></div><div style>... putMVar(...) {</div>

<div style> ...</div><div style> queue = mvar-&gt;queue...</div><div style><br></div><div style>loop:</div><div style> if (end_of_queue(queue) {</div><div style>    return 0;</div><div style> }</div><div style><b> if (marked_as_invalid(queue) {  // invalid = (queue-&gt;group_head == NULL) for example</b></div>

<div style><b>    queue = queue-&gt;link;</b></div><div style><b>    goto loop;</b></div><div style><b> }</b></div><div style><b> if (queue-&gt;group_head != queue) {</b></div><div style><b>    // Try to win race to wake up the TSO with *our* MVar.<br>

</b></div><div style><b>    won = TryLock(queue-&gt;group_head);</b></div><div style><b>    if (!won) {</b></div><div style><b>        // ignore this queue element for now, we can&#39;t get the lock, </b></div><div style>

<b>        // and it will be marked_as_invalid at some point in the future anyways.</b></div><div style><b>        queue = queue-&gt;link;</b></div><div style><b>        goto loop;  // try next</b></div><div style><b>    }</b></div>

<div style><b>    if (won) {</b></div><div style><b>        for all in group, mark them as &quot;invalid&quot;</b></div><div style><b>        Unlock(queue-&gt;group_head);</b></div><div style><b>        goto wake_up_tso;</b></div>

<div style><b>    } else {<br></b></div><div style><b>        // Did not win</b></div><div style><b>        goto loop;</b></div><div style><b>    }</b></div><div style> } else {</div><div style>   ..what is currently done..</div>

<div style><br></div><div style>wake_up_tso:</div><div style>  ... do wake up</div><div style><br></div><div style><br></div><div style>Alexander</div></div></div>