@@ -817,11 +817,11 @@ delayedAction a = do
817817 liftIO $ shakeEnqueue extras a
818818
819819data PendingRestart = PendingRestart
820- { pendingRestartVFS :: VFSModified
821- , pendingRestartActionBetweenSessions :: IO [Key ]
822- , pendingRestartReasons :: [T. Text ]
823- , pendingRestartActions :: [DelayedActionInternal ]
824- , pendingRestartDoneSignals :: [TMVar () ]
820+ { pendingRestartVFS :: ! VFSModified
821+ , pendingRestartActionBetweenSessions :: ! [ IO [Key ] ]
822+ , pendingRestartReasons :: ! [T. Text ]
823+ , pendingRestartActions :: ! [DelayedActionInternal ]
824+ , pendingRestartDoneSignals :: ! [TMVar () ]
825825 }
826826
827827newestVFSModified :: VFSModified -> VFSModified -> VFSModified
@@ -832,35 +832,46 @@ mergePendingRestart :: PendingRestart -> Maybe PendingRestart -> PendingRestart
832832mergePendingRestart new Nothing = new
833833mergePendingRestart new (Just old) = PendingRestart
834834 { pendingRestartVFS = newestVFSModified (pendingRestartVFS new) (pendingRestartVFS old)
835- , pendingRestartReasons = pendingRestartReasons new <> pendingRestartReasons old
836- -- TODO: Contains a quadratic list append on the number of accumulated shake restarts.
837- , pendingRestartActions = pendingRestartActions old <> pendingRestartActions new
838- , pendingRestartActionBetweenSessions = pendingRestartActionBetweenSessions old <> pendingRestartActionBetweenSessions new
839- , pendingRestartDoneSignals = pendingRestartDoneSignals new <> pendingRestartDoneSignals old }
835+ , pendingRestartReasons = pendingRestartReasons new ++ pendingRestartReasons old
836+ , pendingRestartActions = pendingRestartActions new ++ pendingRestartActions old
837+ , pendingRestartActionBetweenSessions = pendingRestartActionBetweenSessions new ++ pendingRestartActionBetweenSessions old
838+ , pendingRestartDoneSignals = pendingRestartDoneSignals new ++ pendingRestartDoneSignals old
839+ }
840840
841841data RestartSlot = RestartSlot
842- { queuedRestart :: IORef (Maybe (PendingRestart ))
843- , restartSignal :: MVar ()
842+ { queuedRestart :: IORef (Maybe PendingRestart )
843+ , restartSignal :: MVar ()
844+ , lastRestartBarrier :: TVar (TMVar () )
845+ -- ^ A barrier that is filled when the most recent shake restart completes.
846+ --
847+ -- Each call to 'shakeRestart' replaces this with a fresh empty TMVar. The
848+ -- restart worker fills it when the restart finishes. Dependents on the
849+ -- restart can then wait on this.
844850 }
845851
846852newRestartSlot :: IO RestartSlot
847- newRestartSlot = RestartSlot <$> newIORef Nothing <*> newEmptyMVar
853+ newRestartSlot = do
854+ initialBarrier <- newTMVarIO () -- starts filled (no pending restart)
855+ RestartSlot <$> newIORef Nothing <*> newEmptyMVar <*> newTVarIO initialBarrier
848856
849857-- | Restart the current 'ShakeSession' with the given system actions.
850- -- Any actions running in the current session will be aborted,
851- -- but actions added via 'shakeEnqueue' will be requeued.
858+ --
859+ -- Any actions running in the current session will be aborted, but actions added
860+ -- via 'shakeEnqueue' will be requeued.
852861shakeRestart :: IdeState -> VFSModified -> T. Text -> [DelayedAction () ] -> IO [Key ] -> IO ()
853862shakeRestart IdeState {.. } vfs reason acts ioActionBetweenShakeSession = do
854863 restartDone <- newEmptyTMVarIO
855- atomicModifyIORef'_ (queuedRestart (restartSlot shakeExtras)) $ Just . mergePendingRestart PendingRestart
864+ let slot = restartSlot shakeExtras
865+ -- Publish this restart's barrier, that dependents LSP requests can wait on.
866+ atomically $ writeTVar (lastRestartBarrier slot) restartDone
867+ atomicModifyIORef'_ (queuedRestart slot) $ Just . mergePendingRestart PendingRestart
856868 { pendingRestartVFS = vfs
857- , pendingRestartActionBetweenSessions = ioActionBetweenShakeSession
869+ , pendingRestartActionBetweenSessions = [ ioActionBetweenShakeSession]
858870 , pendingRestartReasons = [reason]
859871 , pendingRestartActions = acts
860872 , pendingRestartDoneSignals = [restartDone]
861873 }
862- void $ tryPutMVar (restartSignal (restartSlot shakeExtras)) ()
863- atomically $ readTMVar restartDone
874+ void $ tryPutMVar (restartSignal slot) ()
864875
865876-- | Run a worker that asynchronously processes shake restart requests. Will
866877-- only ever queue upto 1 additional restart, accumulating data while processing
@@ -878,10 +889,10 @@ processPendingRestart recorder IdeState{..} = do
878889 takeMVar (restartSignal (restartSlot shakeExtras))
879890 pendingRestart <- atomicModifyIORef' (queuedRestart (restartSlot shakeExtras)) (Nothing ,)
880891 void $ forM pendingRestart $ \ PendingRestart {.. } -> do
881- flip finally (atomically $ traverse (flip tryPutTMVar () ) pendingRestartDoneSignals) $ do
892+ flip finally (atomically $ traverse (flip tryPutTMVar () ) ( reverse pendingRestartDoneSignals) ) $ do
882893 let sessionAction runner = do
883894 (stopTime,() ) <- duration $ logErrorAfter 10 $ cancelShakeSession runner
884- keys <- pendingRestartActionBetweenSessions
895+ keys <- fmap concat ( sequence ( reverse pendingRestartActionBetweenSessions))
885896 -- it is every important to update the dirty keys after we enter the critical section
886897 -- see Note [Housekeeping rule cache and dirty key outside of hls-graph]
887898 atomically $ modifyTVar' (dirtyKeys shakeExtras) $ \ x -> foldl' (flip insertKeySet) x keys
@@ -890,13 +901,15 @@ processPendingRestart recorder IdeState{..} = do
890901 queue <- atomicallyNamed " actionQueue - peek" $ peekInProgress $ actionQueue shakeExtras
891902
892903 -- this log is required by tests
893- logWith recorder Debug $ LogBuildSessionRestart pendingRestartReasons queue backlog stopTime res
904+ logWith recorder Debug $ LogBuildSessionRestart ( reverse pendingRestartReasons) queue backlog stopTime res
894905
895906 withMVar' shakeSession sessionAction $ \ () ->
896907 -- It is crucial to be masked here, otherwise we can get killed
897908 -- between spawning the new thread and updating shakeSession.
898909 -- See https://github.com/haskell/ghcide/issues/79
899- (,() ) <$> newSession recorder shakeExtras pendingRestartVFS shakeDb pendingRestartActions pendingRestartReasons
910+ (,() ) <$> newSession recorder shakeExtras pendingRestartVFS shakeDb
911+ (reverse pendingRestartActions)
912+ (reverse pendingRestartReasons)
900913 pure ()
901914 where
902915 logErrorAfter :: Seconds -> IO () -> IO ()
0 commit comments