
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