packages feed

unagi-chan-0.1.0.0: src/Data/Atomics/Counter/Fat.hs

module Data.Atomics.Counter.Fat (
      AtomicCounter()
    , newCounter
    , incrCounter
    , readCounter
    ) where

-- An atomic counter padded with 64-bytes (an x86 cache line) on either side to
-- try to avoid false sharing.

import Data.Primitive.MachDeps(sIZEOF_INT)
import Control.Monad.Primitive(RealWorld)
import Data.Primitive.ByteArray
import Data.Atomics(fetchAddByteArrayInt)

newtype AtomicCounter = AtomicCounter (MutableByteArray RealWorld)

sIZEOF_CACHELINE , cACHELINE_PADDED_INT_IX  :: Int
sIZEOF_CACHELINE   = 64
cACHELINE_PADDED_INT_IX = (sIZEOF_CACHELINE `quot` 2) `quot` sIZEOF_INT

newCounter :: Int -> IO AtomicCounter
{-# INLINE newCounter #-}
newCounter n = do
    arr <- newAlignedPinnedByteArray 
                sIZEOF_CACHELINE
                sIZEOF_CACHELINE
    writeByteArray arr cACHELINE_PADDED_INT_IX n
    return (AtomicCounter arr)

incrCounter :: Int -> AtomicCounter -> IO Int
{-# INLINE incrCounter #-}
incrCounter incr (AtomicCounter arr) =
    fetchAddByteArrayInt arr cACHELINE_PADDED_INT_IX incr

readCounter :: AtomicCounter -> IO Int
{-# INLINE readCounter #-}
readCounter (AtomicCounter arr) = 
    readByteArray arr cACHELINE_PADDED_INT_IX