takeOneMVar?

Alexander Kjeldaas alexander.kjeldaas at gmail.com
Thu Feb 14 21:54:25 CET 2013


Hi,

I ended up staring at the PrimOps.cmm file today, and porting tryPutMVar to
C so it can be used from the RTS.

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.

My rough idea is like this:

-- wait for all MVars, return the value of one of them, and the
corresponding index
takeOneMVar :: [MVar a] -> IO (a, Int)

This is implemented by this change:

typedef struct StgMVarTSOQueue_ {
    StgHeader                header;
    struct StgMVarTSOQueue_ *link;
*    // The group_head and group_link are used when a TSO is waiting on*
*    // multiple MVars.  Multiple StgMVarTSOQueue objects*
*    // are created, one for each MVar, and they are linked using the*
*    // group_link pointer.  group_head always points to the first*
*    // element. The tso pointer will always be the same in this case.*
*    // The group head acts as a synchronization element for the whole
group.*
*    // When the    group head lock is acquired, the owner can invalidate
the group*
*    struct StgMVarTSOQueue  *group_head;*
*    struct StgMVarTSOQueue  *group_link;*
    struct StgTSO_          *tso;
} StgMVarTSOQueue;

Now, whenever a TSO should be woken up by the MVar code, if

... putMVar(...) {
 ...
 queue = mvar->queue...

loop:
 if (end_of_queue(queue) {
    return 0;
 }
* if (marked_as_invalid(queue) {  // invalid = (queue->group_head == NULL)
for example*
*    queue = queue->link;*
*    goto loop;*
* }*
* if (queue->group_head != queue) {*
*    // Try to win race to wake up the TSO with *our* MVar.
*
*    won = TryLock(queue->group_head);*
*    if (!won) {*
*        // ignore this queue element for now, we can't get the lock, *
*        // and it will be marked_as_invalid at some point in the future
anyways.*
*        queue = queue->link;*
*        goto loop;  // try next*
*    }*
*    if (won) {*
*        for all in group, mark them as "invalid"*
*        Unlock(queue->group_head);*
*        goto wake_up_tso;*
*    } else {
*
*        // Did not win*
*        goto loop;*
*    }*
 } else {
   ..what is currently done..

wake_up_tso:
  ... do wake up


Alexander
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.haskell.org/pipermail/ghc-devs/attachments/20130214/5b720791/attachment.htm>


More information about the ghc-devs mailing list