@@ -1,61 +1,34 @@
1−{-# LANGUAGE TupleSections #-}
2module Control.Concurrent.ThreadLocal.Internal where
1module Control.Concurrent.ThreadLocal.Internal where
4−import Control.Concurrent (ThreadId, myThreadId, mkWeakThreadId)
3+import Control.Concurrent (ThreadId, myThreadId)
4+import Control.Concurrent.Async
5import Control.Concurrent.MVar
5import Control.Concurrent.MVar
6−import Control.Monad ((<=<), guard)
6+import Data.Map (Map)
7−import Data.Foldable (find, toList)
8−import Data.Maybe (isJust)
9−import Data.Vector (Vector)
10−import qualified Data.Vector as Vector
7+import qualified Data.Map.Strict as Map
11−import Data.Witherable
12−import System.Mem.Weak
14−data LocalValue a = LocalValue {-# UNPACK #-} !(Weak ThreadId) -- ^ ThreadId reference used as a key
9+type ThreadMap a = Map ThreadId a
15− String -- ^ String representation of ThreadId, for debugging
18−localThread :: LocalValue a -> IO (Maybe ThreadId)
19−localThread (LocalValue weak _ _) = deRefWeak weak
21−derefLocal :: LocalValue a -> IO (Maybe (ThreadId, a))
22−derefLocal (LocalValue weak _ a) = fmap (,a) <$> deRefWeak weak
24−makeLocal :: ThreadId -> a -> IO (LocalValue a)
25−makeLocal tid a = do weak <- mkWeakThreadId tid
26− pure (LocalValue weak (show tid) a)
28−newtype ThreadLocal a = ThreadLocal { values :: MVar (Vector (LocalValue a))
11+data ThreadLocal a = ThreadLocal { mvar :: MVar (ThreadMap a)
12+ , gcThread :: Maybe (Async ())
31-- | Create a new thread local storage of type 'a'
15-- | Create a new thread local storage of type 'a'
32newThreadLocal :: IO (ThreadLocal a)
16newThreadLocal :: IO (ThreadLocal a)
33−newThreadLocal = do var <- newMVar Vector.empty
17+newThreadLocal = do var <- newMVar Map.empty
34− return (ThreadLocal var)
18+ return (ThreadLocal var Nothing)
36-- | Insert a value for the current thread
20-- | Insert a value for the current thread
37insertThreadLocal :: a -> ThreadLocal a -> IO ()
21insertThreadLocal :: a -> ThreadLocal a -> IO ()
38−insertThreadLocal val (ThreadLocal var) = do tid <- myThreadId
22+insertThreadLocal val (ThreadLocal var _) = do tid <- myThreadId
39− loc <- makeLocal tid val
23+ modifyMVar_ var (pure . Map.insert tid val)
40− modifyMVar_ var $ \v ->
41− do ts <- filterA (\l -> do tid' <- localThread l
42− pure (isJust tid' && Just tid /= tid')
44− pure (Vector.fromList (loc:ts))
46-- | Fetch a value for the current thread. If none was inserted previously, return Nothing.
25-- | Fetch a value for the current thread. If none was inserted previously, return Nothing.
47fetchThreadLocal :: ThreadLocal a -> IO (Maybe a)
26fetchThreadLocal :: ThreadLocal a -> IO (Maybe a)
48−fetchThreadLocal (ThreadLocal var) = do tid <- myThreadId
27+fetchThreadLocal (ThreadLocal var _) = do tid <- myThreadId
49− v <- readMVar var
28+ m <- readMVar var
50− f tid <$> wither derefLocal v
29+ return (Map.lookup tid m)
51− where f tid vec = do (_,v) <- find ((== tid) . fst) vec
54−gcThreadLocal :: ThreadLocal a -> IO ()
55−gcThreadLocal (ThreadLocal var) = modifyMVar_ var (filterA (fmap isJust . localThread))
57−dumpThreadLocal :: ThreadLocal a -> IO [(Maybe ThreadId, String, a)]
31+deleteThreadLocal :: ThreadLocal a -> IO ()
58−dumpThreadLocal (ThreadLocal var) = traverse (\l@(LocalValue _ s v) -> (,s,v) <$> localThread l) . toList =<< readMVar var
32+deleteThreadLocal (ThreadLocal var _) = do tid <- myThreadId
33+ modifyMVar_ var (pure . Map.delete tid)
60−printThreadLocal :: Show a => ThreadLocal a -> IO ()
61−printThreadLocal = print <=< dumpThreadLocal