@@ -10,6 +10,7 @@ module Control.Distributed.Process.Internal.CQueue
10 , enqueueSTM
10 , enqueueSTM
12 , mkWeakCQueue
12 , mkWeakCQueue
15import Prelude hiding (length, reverse)
16import Prelude hiding (length, reverse)
@@ -17,10 +18,14 @@ import Control.Concurrent.STM
17 ( atomically
18 ( atomically
20 , tryReadTChan
23 , tryReadTChan
21 , newTChan
24 , newTChan
22 , writeTChan
26 , writeTChan
23 , readTChan
27 , readTChan
@@ -46,19 +51,22 @@ import GHC.Weak (Weak(Weak))
46-- We use a TCHan rather than a Chan so that we have a non-blocking read
51-- We use a TCHan rather than a Chan so that we have a non-blocking read
47data CQueue a = CQueue (StrictMVar (StrictList a)) -- Arrived
52data CQueue a = CQueue (StrictMVar (StrictList a)) -- Arrived
48 (TChan a) -- Incoming
53 (TChan a) -- Incoming
54+ (TVar Int) -- Queue size
50newCQueue :: IO (CQueue a)
56newCQueue :: IO (CQueue a)
51−newCQueue = CQueue <$> newMVar Nil <*> atomically newTChan
57+newCQueue = CQueue <$> newMVar Nil <*> atomically newTChan <*> newTVarIO 0
53-- | Enqueue an element
59-- | Enqueue an element
55-- Enqueue is strict.
61-- Enqueue is strict.
56enqueue :: CQueue a -> a -> IO ()
62enqueue :: CQueue a -> a -> IO ()
57−enqueue (CQueue _arrived incoming) !a = atomically $ writeTChan incoming a
63+enqueue c !a = atomically (enqueueSTM c a)
59-- | Variant of enqueue for use in the STM monad.
65-- | Variant of enqueue for use in the STM monad.
60enqueueSTM :: CQueue a -> a -> STM ()
66enqueueSTM :: CQueue a -> a -> STM ()
61−enqueueSTM (CQueue _arrived incoming) !a = writeTChan incoming a
67+enqueueSTM (CQueue _arrived incoming size) !a = do
68+ writeTChan incoming a
69+ modifyTVar' size succ
63data BlockSpec =
71data BlockSpec =
64 NonBlocking
72 NonBlocking
@@ -101,7 +109,7 @@ dequeue :: forall m a.
101 -> BlockSpec -- ^ Blocking behaviour
109 -> BlockSpec -- ^ Blocking behaviour
102 -> [MatchOn m a] -- ^ List of matches
110 -> [MatchOn m a] -- ^ List of matches
103 -> IO (Maybe a) -- ^ 'Nothing' only on timeout
111 -> IO (Maybe a) -- ^ 'Nothing' only on timeout
104−dequeue (CQueue arrived incoming) blockSpec matchons = mask_ $
112+dequeue (CQueue arrived incoming size) blockSpec matchons = mask_ $ decrementJust $
105 case blockSpec of
113 case blockSpec of
106 Timeout n -> timeout n $ fmap fromJust run
114 Timeout n -> timeout n $ fmap fromJust run
107 _other ->
115 _other ->
@@ -113,6 +121,16 @@ dequeue (CQueue arrived incoming) blockSpec matchons = mask_ $
113 -- no onException needed
121 -- no onException needed
114 _other -> run
122 _other -> run
124+ -- Decrement counter is smth is returned from the queue,
125+ -- this is safe to use as method is called under a mask
126+ -- and there is no 'unmasked' operation inside
127+ decrementJust f = do
130+ Just{} -> atomically $ modifyTVar' size pred
131+ Nothing -> return ()
116 chunks = chunkMatches matchons
134 chunks = chunkMatches matchons
@@ -245,5 +263,8 @@ dequeue (CQueue arrived incoming) blockSpec matchons = mask_ $
246-- | Weak reference to a CQueue
264-- | Weak reference to a CQueue
247mkWeakCQueue :: CQueue a -> IO () -> IO (Weak (CQueue a))
265mkWeakCQueue :: CQueue a -> IO () -> IO (Weak (CQueue a))
248−mkWeakCQueue m@(CQueue (StrictMVar (MVar m#)) _) f = IO $ \s ->
266+mkWeakCQueue m@(CQueue (StrictMVar (MVar m#)) _ _) f = IO $ \s ->
249 case mkWeak# m# m f s of (# s1, w #) -> (# s1, Weak w #)
267 case mkWeak# m# m f s of (# s1, w #) -> (# s1, Weak w #)
269+queueSize :: CQueue a -> IO Int
270+queueSize (CQueue _ _ size) = readTVarIO size