<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] -> 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->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->group_head == NULL) for example</b></div>
<div style><b> queue = queue->link;</b></div><div style><b> goto loop;</b></div><div style><b> }</b></div><div style><b> if (queue->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->group_head);</b></div><div style><b> if (!won) {</b></div><div style><b> // ignore this queue element for now, we can'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->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 "invalid"</b></div><div style><b> Unlock(queue->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>