{-# Language MagicHash, UnboxedTuples #-} -- | Note: extensive testing of atomic operations is performed in the -- "atomic-primops" library. Only extremely rudimentary tests appear -- here. import GHC.IO import GHC.IORef import GHC.ST import GHC.STRef import GHC.Prim import GHC.Base import Data.Primitive.Array import Data.IORef import Control.Monad ------------------------------------------------------------------------ casArrayST :: MutableArray s a -> Int -> a -> a -> ST s (Bool, a) casArrayST (MutableArray arr#) (I# i#) old new = ST$ \s1# -> case casArray# arr# i# old new s1# of (# s2#, x#, res #) -> (# s2#, (isTrue# (x# ==# 0#), res) #) casSTRef :: STRef s a -- ^ The 'STRef' containing a value 'current' -> a -- ^ The 'old' value to compare -> a -- ^ The 'new' value to replace 'current' if @old == current@ -> ST s (Bool, a) casSTRef (STRef var#) old new = ST $ \s1# -> -- The primop treats the boolean as a sort of error code. -- Zero means the CAS worked, one that it didn't. -- We flip that here: case casMutVar# var# old new s1# of (# s2#, x#, res #) -> (# s2#, (isTrue# (x# ==# 0#), res) #) -- | Performs a machine-level compare and swap operation on an -- 'IORef'. Returns a tuple containing a 'Bool' which is 'True' when a -- swap is performed, along with the 'current' value from the 'IORef'. -- -- Note \"compare\" here means pointer equality in the sense of -- 'GHC.Prim.reallyUnsafePtrEquality#'. casIORef :: IORef a -- ^ The 'IORef' containing a value 'current' -> a -- ^ The 'old' value to compare -> a -- ^ The 'new' value to replace 'current' if @old == current@ -> IO (Bool, a) casIORef (IORef var) old new = stToIO (casSTRef var old new) ------------------------------------------------------------------------ -- Make sure this Int corresponds to a single object in memory (NOINLINE): {-# NOINLINE mynum #-} mynum :: Int mynum = 33 main = do putStrLn "Perform a CAS within an IORef" ref <- newIORef mynum res <- casIORef ref mynum 44 res2 <- casIORef ref mynum 44 putStrLn$ " 1st try should succeed: "++show res putStrLn$ " 2nd should fail: "++show res2 ------------------------------------------------------------ putStrLn "Perform a CAS within a MutableArray#" arr <- newArray 5 mynum res <- stToIO$ casArrayST arr 3 mynum 44 res2 <- stToIO$ casArrayST arr 3 mynum 44 putStrLn$ " 1st try should succeed: "++show res putStrLn$ " 2nd should fail: "++show res2 putStrLn "Printing array:" forM_ [0..4] $ \ i -> do x <- readArray arr i putStr (" "++show x) putStrLn "" ------------------------------------------------------------ putStrLn "Done."