packages feed

chaselev-deque-0.5.0.3: RegressionTests/Issue5.hs

module RegressionTests.Issue5 (standalone_pushPop) where

import Control.Concurrent
import Data.IORef
import Data.Concurrent.Deque.Class 
import qualified Data.Concurrent.Deque.ChaseLev as CL

--------------------------------------------------------------------------------

standalone_pushPop :: IO ()
standalone_pushPop =
  triv =<< (newQ :: IO (DebugDeque CL.ChaseLevDeque a))           
 where   
   -- This is what's failing with the debug wrapper, WHY?
   triv :: PopL d => d [Char] -> IO ()
   triv q = do
     pushL q "hi" 
     x <- tryPopL q
     case x of
       Just "hi" -> putStrLn "Got expected value.  Test passed.\n"
       Just x'   -> error$ "A single push/pop got the WRONG value back: "++show x'
       Nothing   -> error "Even a single push/pop in isolation did not work!"


-- | Warning, this enforces the excessively STRONG invariant that if any end of the
-- deque is non-threadsafe then it may ever only be touched by one thread during its
-- entire lifetime.
--
-- This extreme form of monagamy is easier to verify, because we don't have enough
-- information to know if two operations on different threads are racing with one
-- another or are properly synchronized.
--
-- The wrapper data structure has two IORefs to track the last thread that touched
-- the left and right end of the deque, respectively.
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
    pushL q elt

  tryPopR (DebugDeque (_,ref) q) = do
    tryPopR q 

  newQ = do l <- newIORef Nothing
            r <- newIORef Nothing
            fmap (DebugDeque (l,r)) newQ

  -- FIXME: What are the threadsafe rules for nullQ?
  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
    tryPopL q