{-# LANGUAGE BangPatterns #-} {-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE CPP #-} -- | This is the simplest implementation of thread-local storage using -- GHC's built-in ThreadId capabilities. -- -- While the interface below is designed to match the other -- implementations of TLS in this package, the GHC implementation can -- generaly be relied upon to keep a stable copy of the TLS variable -- for each `ThreadId` that calls `getTLS`. This may change in the -- future, however! module Data.TLS.GHC ( TLS , mkTLS , getTLS , allTLS , forEachTLS_ , freeAllTLS -- * Deprecated, backwards compatibility , freeTLS ) where import Control.Monad import Control.Concurrent import Data.Map.Strict as M import Data.IORef -- Module signature: -------------------------------------------------------------------------------- #include "TLS_Sig.hs" -------------------------------------------------------------------------------- -- | A thread-local variable of type `a`. data TLS a = TLS { mkNew :: !(IO a) , allCopies :: {-# UNPACK #-} !(IORef (Map ThreadId a)) } mkTLS new = do v <- newIORef $! M.empty return $! TLS new v getTLS TLS{mkNew,allCopies} = do tid <- myThreadId peek <- readIORef allCopies case M.lookup tid peek of Just a -> return a Nothing -> do a <- mkNew atomicModifyIORef' allCopies (\ mp -> (M.insert tid a mp, ())) return $! a allTLS TLS{allCopies} = do mp <- readIORef allCopies return $! M.elems mp forEachTLS_ tls fn = do ls <- allTLS tls forM_ ls fn -- Nothing to do here... we haven't pinned anything. Normal GC is fine. freeAllTLS _ = do return ()