@@ -154,7 +154,8 @@ import Development.IDE.Graph.Database (ShakeDatabase,
154
154
import Development.IDE.Graph.Internal.Action (runActionInDbCb )
155
155
import Development.IDE.Graph.Internal.Database (AsyncParentKill (AsyncParentKill ))
156
156
import Development.IDE.Graph.Internal.Types (DBQue , Step (.. ),
157
- getShakeStep )
157
+ getShakeStep ,
158
+ withLockInShakeDatabase )
158
159
import Development.IDE.Graph.Rule
159
160
import Development.IDE.Types.Action
160
161
import Development.IDE.Types.Diagnostics
@@ -615,7 +616,6 @@ data IdeState = IdeState
615
616
}
616
617
617
618
618
-
619
619
-- This is debugging code that generates a series of profiles, if the Boolean is true
620
620
shakeDatabaseProfileIO :: Maybe FilePath -> IO (ShakeDatabase -> IO (Maybe FilePath ))
621
621
shakeDatabaseProfileIO mbProfileDir = do
@@ -754,7 +754,6 @@ shakeOpen recorder lspEnv defaultConfig idePlugins debouncer
754
754
pure ShakeExtras {shakeRecorder = recorder, .. }
755
755
shakeDb <-
756
756
shakeNewDatabase
757
- shakeControlQueue
758
757
opts { shakeExtra = newShakeExtra shakeExtras }
759
758
rules
760
759
shakeSession <- newEmptyMVar
@@ -912,43 +911,44 @@ runRestartTaskDyn recorder ideStateVar dy = runRestartTask recorder ideStateVar
912
911
runRestartTask :: Recorder (WithPriority Log ) -> MVar IdeState -> ShakeRestartArgs -> IO ()
913
912
runRestartTask recorder ideStateVar shakeRestartArgs = do
914
913
IdeState {shakeDb, shakeSession, shakeExtras, shakeDatabaseProfile} <- readMVar ideStateVar
915
- let prepareRestart sra@ ShakeRestartArgs {.. } = do
916
- keys <- sraBetweenSessions
917
- -- it is every important to update the dirty keys after we enter the critical section
918
- -- see Note [Housekeeping rule cache and dirty key outside of hls-graph]
919
- atomically $ modifyTVar' (dirtyKeys shakeExtras) $ \ x -> foldl' (flip insertKeySet) x keys
920
- -- Check if there is another restart request pending, if so, we run that one too
921
- readAndGo sra sraShakeControlQueue
922
- readAndGo sra sraShakeControlQueue = do
923
- nextRestartArg <- atomically $ tryReadTaskQueue sraShakeControlQueue
924
- case nextRestartArg of
925
- Nothing -> return sra
926
- Just (Left dy) -> do
927
- res <- prepareRestart $ dynShakeRestart dy
928
- return $ sra <> res
929
- Just (Right _) -> readAndGo sra sraShakeControlQueue
930
- withMVar'
931
- shakeSession
932
- ( \ runner -> do
933
- -- takeShakeLock shakeDb
934
- (stopTime, () ) <- duration $ logErrorAfter 10 $ cancelShakeSession runner
935
- restartArgs <- prepareRestart shakeRestartArgs
936
- queue <- atomicallyNamed " actionQueue - peek" $ peekInProgress $ actionQueue shakeExtras
937
- res <- shakeDatabaseProfile shakeDb
938
- backlog <- readTVarIO $ dirtyKeys shakeExtras
939
- -- this log is required by tests
940
- step <- shakeGetBuildStep shakeDb
941
- logWith recorder Info $ LogBuildSessionRestart restartArgs queue backlog stopTime res step
942
- return restartArgs
943
- )
944
- -- It is crucial to be masked here, otherwise we can get killed
945
- -- between spawning the new thread and updating shakeSession.
946
- -- See https://github.com/haskell/ghcide/issues/79
947
- ( \ (ShakeRestartArgs {.. }) ->
948
- do
949
- (,() ) <$> newSession recorder shakeExtras sraVfs shakeDb sraActions sraReason
950
- `finally` for_ sraWaitMVars (`putMVar` () )
951
- )
914
+ withLockInShakeDatabase shakeDb $ do
915
+ let prepareRestart sra@ ShakeRestartArgs {.. } = do
916
+ keys <- sraBetweenSessions
917
+ -- it is every important to update the dirty keys after we enter the critical section
918
+ -- see Note [Housekeeping rule cache and dirty key outside of hls-graph]
919
+ atomically $ modifyTVar' (dirtyKeys shakeExtras) $ \ x -> foldl' (flip insertKeySet) x keys
920
+ -- Check if there is another restart request pending, if so, we run that one too
921
+ readAndGo sra sraShakeControlQueue
922
+ readAndGo sra sraShakeControlQueue = do
923
+ nextRestartArg <- atomically $ tryReadTaskQueue sraShakeControlQueue
924
+ case nextRestartArg of
925
+ Nothing -> return sra
926
+ Just (Left dy) -> do
927
+ res <- prepareRestart $ dynShakeRestart dy
928
+ return $ sra <> res
929
+ Just (Right _) -> readAndGo sra sraShakeControlQueue
930
+ withMVar'
931
+ shakeSession
932
+ ( \ runner -> do
933
+ -- takeShakeLock shakeDb
934
+ (stopTime, () ) <- duration $ logErrorAfter 10 $ cancelShakeSession runner
935
+ restartArgs <- prepareRestart shakeRestartArgs
936
+ queue <- atomicallyNamed " actionQueue - peek" $ peekInProgress $ actionQueue shakeExtras
937
+ res <- shakeDatabaseProfile shakeDb
938
+ backlog <- readTVarIO $ dirtyKeys shakeExtras
939
+ -- this log is required by tests
940
+ step <- shakeGetBuildStep shakeDb
941
+ logWith recorder Info $ LogBuildSessionRestart restartArgs queue backlog stopTime res step
942
+ return restartArgs
943
+ )
944
+ -- It is crucial to be masked here, otherwise we can get killed
945
+ -- between spawning the new thread and updating shakeSession.
946
+ -- See https://github.com/haskell/ghcide/issues/79
947
+ ( \ (ShakeRestartArgs {.. }) ->
948
+ do
949
+ (,() ) <$> newSession recorder shakeExtras sraVfs shakeDb sraActions sraReason
950
+ `finally` for_ sraWaitMVars (`putMVar` () )
951
+ )
952
952
where
953
953
logErrorAfter :: Seconds -> IO () -> IO ()
954
954
logErrorAfter seconds action = flip withAsync (const action) $ do
0 commit comments