fix another theoretical deadlock bug in the Chan implementation (c.f. #6153)
authorSimon Marlow <marlowsd@gmail.com>
Mon, 11 Jun 2012 08:54:06 +0000 (09:54 +0100)
committerSimon Marlow <marlowsd@gmail.com>
Mon, 11 Jun 2012 12:42:27 +0000 (13:42 +0100)
Control/Concurrent/Chan.hs

index 2b84503..4bc72e3 100644 (file)
@@ -102,12 +102,21 @@ writeChan (Chan _ writeVar) val = do
 -- |Read the next value from the 'Chan'.
 readChan :: Chan a -> IO a
 readChan (Chan readVar _) = do
-  modifyMVar readVar $ \read_end -> do
+  modifyMVarMasked readVar $ \read_end -> do -- Note [modifyMVarMasked]
     (ChItem val new_read_end) <- readMVar read_end
         -- Use readMVar here, not takeMVar,
         -- else dupChan doesn't work
     return (new_read_end, val)
 
+-- Note [modifyMVarMasked]
+-- This prevents a theoretical deadlock if an asynchronous exception
+-- happens during the readMVar while the MVar is empty.  In that case
+-- the read_end MVar will be left empty, and subsequent readers will
+-- deadlock.  Using modifyMVarMasked prevents this.  The deadlock can
+-- be reproduced, but only by expanding readMVar and inserting an
+-- artificial yield between its takeMVar and putMVar operations.
+
+
 -- |Duplicate a 'Chan': the duplicate channel begins empty, but data written to
 -- either channel from then on will be available from both.  Hence this creates
 -- a kind of broadcast channel, where data written by anyone is seen by