ghc-debug-brick-0.8.0.0: src/GHC/Debug/Brick/Action/Async.hs
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE ScopedTypeVariables #-}
module GHC.Debug.Brick.Action.Async (
runWithAsyncSampleReporter,
) where
import Brick.BChan
import Brick.Types
import Control.Concurrent (threadDelay)
import Control.Concurrent.Async
import Control.Exception
import Control.Monad.IO.Class (liftIO)
import Data.Text (Text)
import qualified Data.Text as Text
import Lens.Micro
import GHC.Debug.Async
import GHC.Debug.Brick.Model
import GHC.Debug.Brick.UI.Async
import GHC.Debug.Client
-- | Run the action asynchronously sending update messages periodically
-- to the brick UI.
--
-- After the computation @action@ has finished, a final operation @andThen@ can be executed, for example to update
-- the UI footer, or to persist the results of the heap traversal to disk.
--
-- The update period is configurable via @'OperationalState'.'_asyncSamplingInterval'@.
--
-- @'runWithAsyncSampleReporter' dbg desc mkEvent action andThen@
runWithAsyncSampleReporter :: forall a n . Debuggee -> Text -> (a -> SampleEvent) -> IO (AsyncTrace a) -> (a -> EventM Name OperationalState ()) -> EventM n OperationalState ()
runWithAsyncSampleReporter dbg desc mkEvent action andThen = do
outside_os <- get
let
reportSampleResult :: a -> IO ()
reportSampleResult a = do
writeBChan (outside_os ^. event_chan) (NewSampleEvent $ mkEvent a)
runAsyncAction :: IO a
runAsyncAction = do
asyncTrace <- action
let
progressReporter = do
threadDelay (outside_os ^. asyncSamplingInterval)
asyncResult asyncTrace >>= \ case
Done a -> reportSampleResult a
Running a -> reportSampleResult a
NotStarted -> pure ()
progressReporter
mRes <- run dbg (waitForAsyncTraceResultM asyncTrace)
`race` progressReporter
case mRes of
Left finalRes -> pure finalRes
Right () -> throwIO $ ErrorCall $ Text.unpack desc <> ": progress reporter unexpectedly terminated"
asyncAction desc runAsyncAction $ \ finalRes -> do
-- write final result to the IOTree
liftIO $ reportSampleResult finalRes
andThen finalRes