Skip to content

Instantly share code, notes, and snippets.

@TerrorJack
Last active November 10, 2020 11:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save TerrorJack/7c25a507aba34706ac2f724903d31ae2 to your computer and use it in GitHub Desktop.
Save TerrorJack/7c25a507aba34706ac2f724903d31ae2 to your computer and use it in GitHub Desktop.
Thread-local storage in Haskell that doesn't leak memory.
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE UnboxedTuples #-}
{-# LANGUAGE UnliftedFFITypes #-}
{-# OPTIONS_GHC -Wall #-}
module TLS
( TLS,
newTLS,
freeTLS,
getTLS,
setTLS,
)
where
import Control.Exception
import Data.Foldable
import Data.IORef
import qualified Data.IntMap.Lazy as IM
import Data.Tuple
import GHC.Conc
import GHC.Exts
import GHC.Types
import GHC.Weak
newtype TLS a
= TLS (IORef (IM.IntMap (Weak a)))
newTLS :: IO (TLS a)
newTLS = do
r <- newIORef IM.empty
_ <- mkWeakIORef r $ freeTLS $ TLS r
pure $ TLS r
freeTLS :: TLS a -> IO ()
freeTLS (TLS r) = do
m <- atomicModifyIORef' r (IM.empty,)
traverse_ markDead $ IM.elems m
getTLS :: TLS a -> IO (Maybe a)
getTLS (TLS r) = do
ThreadId tid# <- myThreadId
k <- evaluate $ c_rts_getThreadId tid#
mw <- IM.lookup k <$> readIORef r
case mw of
Just w -> deRefWeak w
_ -> pure Nothing
setTLS :: TLS a -> a -> IO ()
setTLS (TLS r) a = do
ThreadId tid# <- myThreadId
k <- evaluate $ c_rts_getThreadId tid#
mw <- atomicModifyIORef' r (swap . IM.updateLookupWithKey (\_ _ -> Nothing) k)
case mw of
Just w -> markDead w
_ -> pure ()
w' <- IO $ \s0 ->
case mkWeak#
tid#
a
( case atomicModifyIORef' r $ \m -> (IM.delete k m, ()) of
IO fin -> fin
)
s0 of
(# s1, w# #) -> (# s1, Weak w# #)
atomicModifyIORef' r $ \m -> (IM.insert k w' m, ())
markDead :: Weak a -> IO ()
markDead (Weak w#) = IO $ \s0 -> case finalizeWeak# w# s0 of
(# s1, _, _ #) -> (# s1, () #)
foreign import ccall unsafe "rts_getThreadId"
c_rts_getThreadId ::
ThreadId# -> Int
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment