@@ -7,7 +7,6 @@ module Control.Distributed.Process.Internal.CQueue
10−import Control.Monad (join)
11import Control.Concurrent.MVar (MVar, newMVar, takeMVar, putMVar)
10import Control.Concurrent.MVar (MVar, newMVar, takeMVar, putMVar)
12import Control.Concurrent.STM
11import Control.Concurrent.STM
13 ( atomically
12 ( atomically
@@ -21,8 +20,7 @@ import Control.Applicative ((<$>), (<*>))
21import Control.Exception (mask, onException)
20import Control.Exception (mask, onException)
22import System.Timeout (timeout)
21import System.Timeout (timeout)
24−-- TODO: The only reason for TChan rather than Chan here is to that we have
25−-- a non-blocking read
23+-- We use a TCHan rather than a Chan so that we have a non-blocking read
26data CQueue a = CQueue (MVar [a]) -- Arrived
24data CQueue a = CQueue (MVar [a]) -- Arrived
27 (TChan a) -- Incoming
25 (TChan a) -- Incoming
@@ -37,23 +35,22 @@ data BlockSpec =
37 | Blocking
35 | Blocking
38 | Timeout Int
36 | Timeout Int
38+-- | Dequeue an element
40−-- TODO: Timeout only on checking incoming messages, not arrived
40+-- The timeout (if any) is applied only to waiting for incoming messages, not
41−-- (otherwise we might easily get into an infinite loop)
41+-- to checking messages that have already arrived
42dequeue :: forall a b.
42dequeue :: forall a b.
43 CQueue a -- ^ Queue
43 CQueue a -- ^ Queue
44 -> BlockSpec -- ^ Blocking behaviour
44 -> BlockSpec -- ^ Blocking behaviour
45 -> [a -> Maybe b] -- ^ List of matches
45 -> [a -> Maybe b] -- ^ List of matches
46 -> IO (Maybe b) -- ^ 'Nothing' only on timeout
46 -> IO (Maybe b) -- ^ 'Nothing' only on timeout
47−dequeue (CQueue arrived incoming) blockSpec matches =
47+dequeue (CQueue arrived incoming) blockSpec matches = go
49− Timeout t -> join <$> timeout t go
52 go :: IO (Maybe b)
49 go :: IO (Maybe b)
53 go = mask $ \restore -> do
50 go = mask $ \restore -> do
54 arr <- takeMVar arrived
51 arr <- takeMVar arrived
55− -- We first check the arrived messages. If we timeout during this search,
52+ -- We first check the arrived messages. If we get interrupted during this
56− -- we just put the MVar back (since we haven't touched the Chan yet)
53+ -- search, we just put the MVar back (we haven't read from the Chan yet)
57 (arr', mb) <- onException (restore (checkArrived [] arr))
54 (arr', mb) <- onException (restore (checkArrived [] arr))
58 (putMVar arrived arr)
55 (putMVar arrived arr)
59 case (mb, blockSpec) of
56 case (mb, blockSpec) of
@@ -62,8 +59,10 @@ dequeue (CQueue arrived incoming) blockSpec matches =
62 return (Just b)
59 return (Just b)
63 (Nothing, NonBlocking) ->
60 (Nothing, NonBlocking) ->
64 checkNonBlocking arr'
61 checkNonBlocking arr'
65− (Nothing, _) ->
62+ (Nothing, Blocking) ->
66 Just <$> checkBlocking arr'
63 Just <$> checkBlocking arr'
64+ (Nothing, Timeout n) ->
65+ timeout n $ checkBlocking arr'
68 -- We reverse the accumulator on return only if we find a match
67 -- We reverse the accumulator on return only if we find a match
69 checkArrived :: [a] -> [a] -> IO ([a], Maybe b)
68 checkArrived :: [a] -> [a] -> IO ([a], Maybe b)