module Data.Concurrent.Deque.Debugger
(DebugDeque(DebugDeque))
where
import Data.IORef
import Control.Concurrent
import Data.Concurrent.Deque.Class
data DebugDeque d elt = DebugDeque (IORef (Maybe ThreadId), IORef (Maybe ThreadId)) (d elt)
instance DequeClass d => DequeClass (DebugDeque d) where
pushL (DebugDeque (ref,_) q) elt = do
markThread (leftThreadSafe q) ref
pushL q elt
tryPopR (DebugDeque (_,ref) q) = do
markThread (rightThreadSafe q) ref
tryPopR q
newQ = do l <- newIORef Nothing
r <- newIORef Nothing
fmap (DebugDeque (l,r)) newQ
nullQ (DebugDeque _ q) = nullQ q
leftThreadSafe (DebugDeque _ q) = leftThreadSafe q
rightThreadSafe (DebugDeque _ q) = rightThreadSafe q
instance PopL d => PopL (DebugDeque d) where
tryPopL (DebugDeque (ref,_) q) = do
markThread (leftThreadSafe q) ref
tryPopL q
markThread True _ = return ()
markThread False ref = do
last <- readIORef ref
tid <- myThreadId
atomicModifyIORef ref $ \ x ->
case x of
Nothing -> (Just tid, ())
Just tid2
| tid == tid2 -> (Just tid,())
| otherwise -> error$ "DebugDeque: invariant violated, thread safety not allowed but accessed by: "++show (tid,tid2)