@@ -7,21 +7,19 @@ The logic for setting up a ghcide session by tapping into hie-bios.
7
7
module Development.IDE.Session
8
8
(SessionLoadingOptions (.. )
9
9
,CacheDirs (.. )
10
- ,loadSession
11
10
,loadSessionWithOptions
12
11
,setInitialDynFlags
13
12
,getHieDbLoc
14
- ,runWithDb
15
13
,retryOnSqliteBusy
16
14
,retryOnException
17
15
,Log (.. )
16
+ ,runWithDb
18
17
) where
19
18
20
19
-- Unfortunately, we cannot use loadSession with ghc-lib since hie-bios uses
21
20
-- the real GHC library and the types are incompatible. Furthermore, when
22
21
-- building with ghc-lib we need to make this Haskell agnostic, so no hie-bios!
23
22
24
- import Control.Concurrent.Async
25
23
import Control.Concurrent.Strict
26
24
import Control.Exception.Safe as Safe
27
25
import Control.Monad
@@ -100,14 +98,19 @@ import Control.Concurrent.STM.TQueue
100
98
import Control.DeepSeq
101
99
import Control.Exception (evaluate )
102
100
import Control.Monad.IO.Unlift (MonadUnliftIO )
101
+ import Control.Monad.Trans.Cont (ContT (ContT , runContT ))
103
102
import Data.Foldable (for_ )
104
103
import Data.HashMap.Strict (HashMap )
105
104
import Data.HashSet (HashSet )
106
105
import qualified Data.HashSet as Set
107
106
import Database.SQLite.Simple
108
107
import Development.IDE.Core.Tracing (withTrace )
108
+ import Development.IDE.Core.WorkerThread (awaitRunInThread ,
109
+ withWorkerQueue )
109
110
import Development.IDE.Session.Diagnostics (renderCradleError )
110
- import Development.IDE.Types.Shake (WithHieDb , toNoFileKey )
111
+ import Development.IDE.Types.Shake (WithHieDb ,
112
+ WithHieDbShield (.. ),
113
+ toNoFileKey )
111
114
import HieDb.Create
112
115
import HieDb.Types
113
116
import HieDb.Utils
@@ -375,8 +378,10 @@ makeWithHieDbRetryable recorder rng hieDb f =
375
378
-- writing. Actions are picked off one by one from the `HieWriterChan` and executed in serial
376
379
-- by a worker thread using a dedicated database connection.
377
380
-- This is done in order to serialize writes to the database, or else SQLite becomes unhappy
378
- runWithDb :: Recorder (WithPriority Log ) -> FilePath -> (WithHieDb -> IndexQueue -> IO () ) -> IO ()
379
- runWithDb recorder fp k = do
381
+ --
382
+ -- Also see Note [Serializing runs in separate thread]
383
+ runWithDb :: Recorder (WithPriority Log ) -> FilePath -> ContT () IO (WithHieDbShield , IndexQueue )
384
+ runWithDb recorder fp = ContT $ \ k -> do
380
385
-- use non-deterministic seed because maybe multiple HLS start at same time
381
386
-- and send bursts of requests
382
387
rng <- Random. newStdGen
@@ -394,18 +399,15 @@ runWithDb recorder fp k = do
394
399
withWriteDbRetryable = makeWithHieDbRetryable recorder rng writedb
395
400
withWriteDbRetryable initConn
396
401
397
- chan <- newTQueueIO
398
402
399
- withAsync (writerThread withWriteDbRetryable chan) $ \ _ -> do
400
- withHieDb fp (\ readDb -> k (makeWithHieDbRetryable recorder rng readDb) chan)
403
+ -- Clear the index of any files that might have been deleted since the last run
404
+ _ <- withWriteDbRetryable deleteMissingRealFiles
405
+ _ <- withWriteDbRetryable garbageCollectTypeNames
406
+
407
+ runContT (withWorkerQueue (writer withWriteDbRetryable)) $ \ chan ->
408
+ withHieDb fp (\ readDb -> k (WithHieDbShield $ makeWithHieDbRetryable recorder rng readDb, chan))
401
409
where
402
- writerThread :: WithHieDb -> IndexQueue -> IO ()
403
- writerThread withHieDbRetryable chan = do
404
- -- Clear the index of any files that might have been deleted since the last run
405
- _ <- withHieDbRetryable deleteMissingRealFiles
406
- _ <- withHieDbRetryable garbageCollectTypeNames
407
- forever $ do
408
- l <- atomically $ readTQueue chan
410
+ writer withHieDbRetryable l = do
409
411
-- TODO: probably should let exceptions be caught/logged/handled by top level handler
410
412
l withHieDbRetryable
411
413
`Safe.catch` \ e@ SQLError {} -> do
@@ -435,11 +437,9 @@ getHieDbLoc dir = do
435
437
-- This is the key function which implements multi-component support. All
436
438
-- components mapping to the same hie.yaml file are mapped to the same
437
439
-- HscEnv which is updated as new components are discovered.
438
- loadSession :: Recorder (WithPriority Log ) -> FilePath -> IO (Action IdeGhcSession )
439
- loadSession recorder = loadSessionWithOptions recorder def
440
440
441
- loadSessionWithOptions :: Recorder (WithPriority Log ) -> SessionLoadingOptions -> FilePath -> IO (Action IdeGhcSession )
442
- loadSessionWithOptions recorder SessionLoadingOptions {.. } rootDir = do
441
+ loadSessionWithOptions :: Recorder (WithPriority Log ) -> SessionLoadingOptions -> FilePath -> TQueue ( IO () ) -> IO (Action IdeGhcSession )
442
+ loadSessionWithOptions recorder SessionLoadingOptions {.. } rootDir que = do
443
443
let toAbsolutePath = toAbsolute rootDir -- see Note [Root Directory]
444
444
cradle_files <- newIORef []
445
445
-- Mapping from hie.yaml file to HscEnv, one per hie.yaml file
@@ -464,9 +464,6 @@ loadSessionWithOptions recorder SessionLoadingOptions{..} rootDir = do
464
464
let res' = toAbsolutePath <$> res
465
465
return $ normalise <$> res'
466
466
467
- dummyAs <- async $ return (error " Uninitialised" )
468
- runningCradle <- newVar dummyAs :: IO (Var (Async (IdeResult HscEnvEq ,[FilePath ])))
469
-
470
467
return $ do
471
468
clientConfig <- getClientConfigAction
472
469
extras@ ShakeExtras {restartShakeSession, ideNc, knownTargetsVar, lspEnv
@@ -739,12 +736,8 @@ loadSessionWithOptions recorder SessionLoadingOptions{..} rootDir = do
739
736
return (([renderPackageSetupException file e], Nothing ), maybe [] pure hieYaml)
740
737
741
738
returnWithVersion $ \ file -> do
742
- opts <- join $ mask_ $ modifyVar runningCradle $ \ as -> do
743
- -- If the cradle is not finished, then wait for it to finish.
744
- void $ wait as
745
- asyncRes <- async $ getOptions file
746
- return (asyncRes, wait asyncRes)
747
- pure opts
739
+ -- see Note [Serializing runs in separate thread]
740
+ awaitRunInThread que $ getOptions file
748
741
749
742
-- | Run the specific cradle on a specific FilePath via hie-bios.
750
743
-- This then builds dependencies or whatever based on the cradle, gets the
0 commit comments