[project @ 2001-07-06 14:11:38 by simonmar]
Fix a couple of nasty bugs in the take/putMVar implementation.
Now we keep the invariant that a full MVar only has blocked putMVars
on its queue, and an empty MVar only has blocked takeMVars on its
queue. It was the absence of this invariant that led to accidental
deadlock before.
The second bug is that there was a window between a blocked thread
being restarted and it actually retrying the takeMVar/putMVar
operation when it could receive an exception, which would also lead to
deadlock.
The solution to both these problems (as suggested by Simon P.J.) is to
atomically wake up and perform the next blocked putMVar when we do a
take, and vice versa. As a side effect, takeMVar & putMVar should be
much faster when blocking & restarting, because we now shortcut the
retrying of the blocked operation and we use a more specialised stack
layout for the blocked thread. Unfortunately, things got more
complicated too, but there are comments explaining what's going on.