{-# LANGUAGE BangPatterns #-} -- | This implementation stores an unboxed counter and uses FFI -- operations to modify its contents. module Data.Atomics.Counter.Foreign where import Data.Bits.Atomic import Foreign.ForeignPtr import Foreign.Storable -- newtype AtomicCounter = AtomicCounter (ForeignPtr Int) type AtomicCounter = ForeignPtr Int type CTicket = Int -- | Create a new counter initialized to zero. newCounter :: IO AtomicCounter newCounter = do x <- mallocForeignPtr writeCounter x 0 return x -- | Try repeatedly until we successfully increment the counter. -- Returns the original value before the increment. incrCounter :: AtomicCounter -> IO Int incrCounter r = withForeignPtr r$ \r' -> fetchAndAdd r' 1 readCounterForCAS :: AtomicCounter -> IO CTicket readCounterForCAS = readCounter peekCTicket :: CTicket -> Int peekCTicket x = x readCounter :: AtomicCounter -> IO Int readCounter r = withForeignPtr r peek -- | Make a non-atomic write to the counter. No memory-barrier. writeCounter :: AtomicCounter -> Int -> IO () writeCounter r !new = withForeignPtr r $ \r' -> poke r' new casCounter :: AtomicCounter -> CTicket -> Int -> IO (Bool, CTicket) casCounter r !tick !new = withForeignPtr r $ \r' -> do b <- compareAndSwap r' tick new -- if b then return (True,new) -- else do x <- peek r' -- return (False,x) return (b==tick, b)