diff options
Diffstat (limited to 'src/Control/Concurrent')
-rw-r--r-- | src/Control/Concurrent/Lifted/Instrument.hs | 29 |
1 files changed, 24 insertions, 5 deletions
diff --git a/src/Control/Concurrent/Lifted/Instrument.hs b/src/Control/Concurrent/Lifted/Instrument.hs index 9a409569..7e4a7356 100644 --- a/src/Control/Concurrent/Lifted/Instrument.hs +++ b/src/Control/Concurrent/Lifted/Instrument.hs | |||
@@ -10,6 +10,7 @@ module Control.Concurrent.Lifted.Instrument | |||
10 | 10 | ||
11 | import qualified Control.Concurrent.Lifted as Raw | 11 | import qualified Control.Concurrent.Lifted as Raw |
12 | import Control.Concurrent.Lifted hiding (fork) | 12 | import Control.Concurrent.Lifted hiding (fork) |
13 | import Control.Exception (fromException) | ||
13 | import Control.Monad.Trans.Control | 14 | import Control.Monad.Trans.Control |
14 | import System.IO.Unsafe | 15 | import System.IO.Unsafe |
15 | import qualified Data.Map.Strict as Map | 16 | import qualified Data.Map.Strict as Map |
@@ -18,6 +19,9 @@ import Control.Monad.Base | |||
18 | import qualified GHC.Conc as GHC | 19 | import qualified GHC.Conc as GHC |
19 | import Data.Time() | 20 | import Data.Time() |
20 | import Data.Time.Clock | 21 | import Data.Time.Clock |
22 | import System.IO | ||
23 | import Control.Monad.IO.Class | ||
24 | |||
21 | 25 | ||
22 | data PerThread = PerThread | 26 | data PerThread = PerThread |
23 | { lbl :: String | 27 | { lbl :: String |
@@ -25,13 +29,15 @@ data PerThread = PerThread | |||
25 | } | 29 | } |
26 | deriving (Eq,Ord,Show) | 30 | deriving (Eq,Ord,Show) |
27 | 31 | ||
28 | newtype GlobalState = GlobalState | 32 | data GlobalState = GlobalState |
29 | { threads :: Map.Map ThreadId PerThread | 33 | { threads :: !(Map.Map ThreadId PerThread) |
34 | , reportException :: String -> IO () | ||
30 | } | 35 | } |
31 | 36 | ||
32 | globals :: MVar GlobalState | 37 | globals :: MVar GlobalState |
33 | globals = unsafePerformIO $ newMVar $ GlobalState | 38 | globals = unsafePerformIO $ newMVar $ GlobalState |
34 | { threads = Map.empty | 39 | { threads = Map.empty |
40 | , reportException = hPutStrLn stderr | ||
35 | } | 41 | } |
36 | {-# NOINLINE globals #-} | 42 | {-# NOINLINE globals #-} |
37 | 43 | ||
@@ -40,14 +46,27 @@ forkIO :: IO () -> IO ThreadId | |||
40 | forkIO = fork | 46 | forkIO = fork |
41 | {-# INLINE forkIO #-} | 47 | {-# INLINE forkIO #-} |
42 | 48 | ||
43 | fork :: MonadBaseControl IO m => m () -> m ThreadId | 49 | fork :: (MonadBaseControl IO m, MonadIO m) => m () -> m ThreadId |
44 | fork action = do | 50 | fork action = do |
45 | t <- Raw.fork $ do | 51 | t <- Raw.fork $ do |
46 | tid <- myThreadId | 52 | tid <- myThreadId |
47 | tm <- liftBase getCurrentTime | 53 | tm <- liftBase getCurrentTime |
48 | bracket_ (modifyThreads $! Map.insert tid (PerThread "" tm)) | 54 | bracket_ (modifyThreads $! Map.insert tid (PerThread "" tm)) |
49 | (modifyThreads $! Map.delete tid) | 55 | (return ()) |
50 | action | 56 | $ do catch action $ \e -> case fromException e of |
57 | Just ThreadKilled -> return () | ||
58 | Nothing -> liftIO $ do | ||
59 | g <- takeMVar globals | ||
60 | let l = concat [ show e | ||
61 | , " (" | ||
62 | , maybe "" lbl $ Map.lookup tid (threads g) | ||
63 | , ")" | ||
64 | ] | ||
65 | reportException g l | ||
66 | putMVar globals $! g { threads = Map.insert tid (PerThread l tm) $ threads g } | ||
67 | throwIO e | ||
68 | -- Remove the thread only if it terminated normally or was killed. | ||
69 | modifyThreads $! Map.delete tid | ||
51 | return t | 70 | return t |
52 | 71 | ||
53 | labelThread :: ThreadId -> String -> IO () | 72 | labelThread :: ThreadId -> String -> IO () |