Skip to content

Commit 9ed29db

Browse files
committed
Make takeMVar exception safe
1 parent b14daa3 commit 9ed29db

File tree

2 files changed

+19
-1
lines changed

2 files changed

+19
-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: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,23 @@ 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+
case Deque.uncons takeq' of
412+
Nothing ->
413+
writeTVar tv (MVarFull x mempty)
414+
415+
Just (takevar', takeq'') -> do
416+
writeTVar takevar' (Just x)
417+
writeTVar tv (MVarEmpty takeq'' mempty)
402418

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

0 commit comments

Comments
 (0)