never executed always true always false
1 {-# LANGUAGE RankNTypes #-}
2 {-# LANGUAGE DerivingVia #-}
3 module GHC.Driver.Pipeline.LogQueue ( LogQueue(..)
4 , newLogQueue
5 , finishLogQueue
6 , writeLogQueue
7 , parLogAction
8 , printLogs
9
10 , LogQueueQueue(..)
11 , initLogQueue
12 , allLogQueues
13 , newLogQueueQueue
14 , dequeueLogQueueQueue
15 ) where
16
17 import GHC.Prelude
18 import Control.Concurrent
19 import Data.IORef
20 import GHC.Types.Error
21 import GHC.Types.SrcLoc
22 import GHC.Utils.Logger
23 import qualified Data.IntMap as IM
24 import Control.Concurrent.STM
25
26 -- LogQueue Abstraction
27
28 -- | Each module is given a unique 'LogQueue' to redirect compilation messages
29 -- to. A 'Nothing' value contains the result of compilation, and denotes the
30 -- end of the message queue.
31 data LogQueue = LogQueue { logQueueId :: !Int
32 , logQueueMessages :: !(IORef [Maybe (MessageClass, SrcSpan, SDoc, LogFlags)])
33 , logQueueSemaphore :: !(MVar ())
34 }
35
36 newLogQueue :: Int -> IO LogQueue
37 newLogQueue n = do
38 mqueue <- newIORef []
39 sem <- newMVar ()
40 return (LogQueue n mqueue sem)
41
42 finishLogQueue :: LogQueue -> IO ()
43 finishLogQueue lq = do
44 writeLogQueueInternal lq Nothing
45
46
47 writeLogQueue :: LogQueue -> (MessageClass,SrcSpan,SDoc, LogFlags) -> IO ()
48 writeLogQueue lq msg = do
49 writeLogQueueInternal lq (Just msg)
50
51 -- | Internal helper for writing log messages
52 writeLogQueueInternal :: LogQueue -> Maybe (MessageClass,SrcSpan,SDoc, LogFlags) -> IO ()
53 writeLogQueueInternal (LogQueue _n ref sem) msg = do
54 atomicModifyIORef' ref $ \msgs -> (msg:msgs,())
55 _ <- tryPutMVar sem ()
56 return ()
57
58 -- The log_action callback that is used to synchronize messages from a
59 -- worker thread.
60 parLogAction :: LogQueue -> LogAction
61 parLogAction log_queue log_flags !msgClass !srcSpan !msg =
62 writeLogQueue log_queue (msgClass,srcSpan,msg, log_flags)
63
64 -- Print each message from the log_queue using the global logger
65 printLogs :: Logger -> LogQueue -> IO ()
66 printLogs !logger (LogQueue _n ref sem) = read_msgs
67 where read_msgs = do
68 takeMVar sem
69 msgs <- atomicModifyIORef' ref $ \xs -> ([], reverse xs)
70 print_loop msgs
71
72 print_loop [] = read_msgs
73 print_loop (x:xs) = case x of
74 Just (msgClass,srcSpan,msg,flags) -> do
75 logMsg (setLogFlags logger flags) msgClass srcSpan msg
76 print_loop xs
77 -- Exit the loop once we encounter the end marker.
78 Nothing -> return ()
79
80 -- The LogQueueQueue abstraction
81
82 data LogQueueQueue = LogQueueQueue Int (IM.IntMap LogQueue)
83
84 newLogQueueQueue :: LogQueueQueue
85 newLogQueueQueue = LogQueueQueue 1 IM.empty
86
87 addToQueueQueue :: LogQueue -> LogQueueQueue -> LogQueueQueue
88 addToQueueQueue lq (LogQueueQueue n im) = LogQueueQueue n (IM.insert (logQueueId lq) lq im)
89
90 initLogQueue :: TVar LogQueueQueue -> LogQueue -> STM ()
91 initLogQueue lqq lq = modifyTVar lqq (addToQueueQueue lq)
92
93 -- | Return all items in the queue in ascending order
94 allLogQueues :: LogQueueQueue -> [LogQueue]
95 allLogQueues (LogQueueQueue _n im) = IM.elems im
96
97 dequeueLogQueueQueue :: LogQueueQueue -> Maybe (LogQueue, LogQueueQueue)
98 dequeueLogQueueQueue (LogQueueQueue n lqq) = case IM.minViewWithKey lqq of
99 Just ((k, v), lqq') | k == n -> Just (v, LogQueueQueue (n + 1) lqq')
100 _ -> Nothing
101