Skip to content

Commit db0e67c

Browse files
jasagredobolt12
authored andcommitted
Make takeMVar exception safe
1 parent ad7096d commit db0e67c

File tree

2 files changed

+20
-1
lines changed

2 files changed

+20
-1
lines changed

io-sim/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
- Implement `MonadLabelledMVar` instance for `(IOSim s)`
1111
- `TVarId` is now a sum type with one constructor per `TVar` role, e.g. `TVar`,
1212
`TMVar`, `MVar` and a few others - except for `TChan`.
13+
- A blocked `takeTVar` is now safe in the presence of exceptions. It will relay
14+
the value to other waiting threads.
1315

1416
## 1.6.0.0
1517

io-sim/src/Control/Monad/IOSim/STM.hs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,24 @@ takeMVarDefault (MVar tv) = mask_ $ do
398398
-- takevar; we need to remove it from 'takeq', otherwise we
399399
-- will have a space leak.
400400
let takeq' = Deque.filter (/= takevar) takeq
401-
writeTVar tv (MVarEmpty takeq' readq)
401+
takevalue <- readTVar takevar
402+
case takevalue of
403+
Nothing ->
404+
writeTVar tv (MVarEmpty takeq' readq)
405+
-- we were given a value before we could read it. Relay it to any
406+
-- new reading threads and possible the next take thread.
407+
Just x -> do
408+
-- notify readers
409+
mapM_ (\readvar -> writeTVar readvar (Just x)) readq
410+
411+
-- notify first `takeMVar` thread
412+
case Deque.uncons takeq' of
413+
Nothing ->
414+
writeTVar tv (MVarFull x mempty)
415+
416+
Just (takevar', takeq'') -> do
417+
writeTVar takevar' (Just x)
418+
writeTVar tv (MVarEmpty takeq'' mempty)
402419

403420
-- This case is unlikely but possible if another thread ran
404421
-- first and modified the mvar. This situation is fine as far as

0 commit comments

Comments
 (0)