module Haskell.Debug.Adapter.Thread where
import Control.Monad.IO.Class
import Control.Concurrent.Async
import Control.Concurrent
import qualified System.Log.Logger as L
import Data.Maybe
import qualified Data.List as L
import Control.Monad.State.Lazy
import Control.Lens
import Control.Monad.Except
import Haskell.Debug.Adapter.Type
import Haskell.Debug.Adapter.Utility
import Haskell.Debug.Adapter.Constant
start :: AppStores -> [IO ()] -> IO (Async ())
start dat acts = do
as <- mapM async acts
async $ run dat {_asyncsAppStores = as}
run :: AppStores -> IO ()
run appData = do
L.debugM _LOG_THREAD_MGR "satrt thread manager"
runApp appData app
L.debugM _LOG_THREAD_MGR "stop thread manager"
app :: AppContext ()
app = catchError go errHdl
where
errHdl msg = do
criticalEV _LOG_THREAD_MGR msg
criticalEV _LOG_THREAD_MGR "stopping all threads."
as <- view asyncsAppStores <$> get
liftIO $ mapM_ cancel as
go = isStop >>= \case
True -> return ()
False -> do
takeEvent >>= \case
Nothing -> return ()
Just ev -> runEvent ev
liftIO $ threadDelay _1_SEC
go
isStop :: AppContext Bool
isStop = do
as <- view asyncsAppStores <$> get
res <- liftIO $ mapM poll as
when (L.any isJust res) $
liftIO $ L.debugM _LOG_THREAD_MGR $ "thread status." ++ show res
return $ L.all isJust res
takeEvent :: AppContext (Maybe Event)
takeEvent = do
appDat <- get
let mvar = appDat^.eventStoreAppStores
liftIO $ goIO mvar
where
goIO mvar = isExists mvar >>= \case
False -> return Nothing
True -> take1 mvar
isExists mvar = readMVar mvar >>= \case
[] -> return False
_ -> return True
take1 mvar = takeMVar mvar >>= \case
[] -> do
putMVar mvar []
return Nothing
(x:xs) -> do
putMVar mvar xs
return $ Just x
runEvent :: Event -> AppContext ()
runEvent CriticalExitEvent = do
liftIO $ L.criticalM _LOG_THREAD_MGR "Critical exit started."
as <- view asyncsAppStores <$> get
liftIO $ mapM_ cancel as