Andrea Vezzosi pushed to branch wip/romes/async-rpc at Glasgow Haskell Compiler / GHC
Commits:
-
05f68d0e
by Andrea Vezzosi at 2026-10-26T18:21:34+01:00
-
7e21b3f8
by Andrea Vezzosi at 2026-10-26T23:42:27+01:00
-
1c9fe4ea
by Andrea Vezzosi at 2026-10-27T08:54:09+01:00
-
8dbf2fd4
by Andrea Vezzosi at 2026-10-27T08:58:54+01:00
-
5be020df
by Andrea Vezzosi at 2026-10-27T09:05:16+01:00
6 changed files:
- compiler/GHC/Runtime/Interpreter.hs
- compiler/GHC/Runtime/Interpreter/Process.hs
- compiler/GHC/Tc/Gen/Splice.hs
- libraries/ghci/GHCi/Message.hs
- libraries/ghci/GHCi/Message/Async.hs
- libraries/ghci/GHCi/Server.hs
Changes:
| ... | ... | @@ -105,7 +105,7 @@ import GHCi.Run |
| 105 | 105 | import Control.Concurrent
|
| 106 | 106 | import Control.Monad
|
| 107 | 107 | import Control.Monad.IO.Class
|
| 108 | -import Control.Monad.Catch as MC (mask)
|
|
| 108 | +import Control.Monad.Catch as MC (mask, handle, MonadThrow (..))
|
|
| 109 | 109 | import Data.Binary
|
| 110 | 110 | import Data.ByteString (ByteString)
|
| 111 | 111 | import qualified Data.ByteString.Short as SBS
|
| ... | ... | @@ -196,14 +196,16 @@ interpCmd interp msg = case interpInstance interp of |
| 196 | 196 | #if defined(HAVE_INTERNAL_INTERPRETER)
|
| 197 | 197 | InternalInterp -> run msg -- Just run it directly
|
| 198 | 198 | #endif
|
| 199 | - ExternalInterp ext -> withExtInterp ext $ \inst ->
|
|
| 199 | + ExternalInterp ext -> withExtInterp interp ext $ \inst ->
|
|
| 200 | 200 | sendMessage inst msg
|
| 201 | 201 | |
| 202 | -withExtInterp :: ExceptionMonad m => ExtInterp -> (forall d. ExtInterpInstance d -> m a) -> m a
|
|
| 203 | -withExtInterp ext action = case ext of
|
|
| 202 | +withExtInterp :: ExceptionMonad m => Interp -> ExtInterp -> (forall d. ExtInterpInstance d -> m a) -> m a
|
|
| 203 | +withExtInterp interp ext action = stopInterpOnPipeClosed $ case ext of
|
|
| 204 | 204 | ExtJS i -> withJSInterp i action
|
| 205 | 205 | ExtWasm i -> withWasmInterp i action
|
| 206 | 206 | ExtIServ i -> withIServ i action
|
| 207 | + where
|
|
| 208 | + stopInterpOnPipeClosed = MC.handle $ \ (e :: PipeClosedException) -> liftIO (stopInterp interp) >> MC.throwM e
|
|
| 207 | 209 | |
| 208 | 210 | withExtInterpStatus :: ExtInterp -> (forall d. ExtInterpStatusVar d -> m a) -> m a
|
| 209 | 211 | withExtInterpStatus ext action = case ext of
|
| ... | ... | @@ -469,11 +471,9 @@ lookupSymbol interp str = withSymbolCache interp str $ |
| 469 | 471 | #endif
|
| 470 | 472 | ExternalInterp ext -> case ext of
|
| 471 | 473 | ExtIServ i -> withIServ i $ \inst -> do
|
| 472 | - uninterruptibleMask_ $
|
|
| 473 | 474 | sendMessage inst (LookupSymbol (fastStringToShortByteString (interpSymbolToCLabel str)))
|
| 474 | 475 | ExtJS {} -> pprPanic "lookupSymbol not supported by the JS interpreter" (ppr str)
|
| 475 | 476 | ExtWasm i -> withWasmInterp i $ \inst -> do
|
| 476 | - uninterruptibleMask_ $
|
|
| 477 | 477 | sendMessage inst (LookupSymbol (fastStringToShortByteString (interpSymbolToCLabel str)))
|
| 478 | 478 | |
| 479 | 479 | lookupSymbolInDLL :: Interp -> RemotePtr LoadedDLL -> InterpSymbol s -> IO (Maybe (RemotePtr ()))
|
| ... | ... | @@ -484,7 +484,6 @@ lookupSymbolInDLL interp dll str = withSymbolCache interp str $ |
| 484 | 484 | #endif
|
| 485 | 485 | ExternalInterp ext -> case ext of
|
| 486 | 486 | ExtIServ i -> withIServ i $ \inst -> do
|
| 487 | - uninterruptibleMask_ $
|
|
| 488 | 487 | sendMessage inst (LookupSymbolInDLL dll (fastStringToShortByteString (interpSymbolToCLabel str)))
|
| 489 | 488 | ExtJS {} -> pprPanic "lookupSymbol not supported by the JS interpreter" (ppr str)
|
| 490 | 489 | -- wasm dyld doesn't track which symbol comes from which .so
|
| ... | ... | @@ -645,6 +644,9 @@ stopInterp interp = case interpInstance interp of |
| 645 | 644 | else sendMessage i Shutdown
|
| 646 | 645 | -- We asked the server to shutdown, so we will also shutdown any communication.
|
| 647 | 646 | closePipe (interpPipe (instProcess i))
|
| 647 | + modifyMVar_ (loader_state (interpLoader interp)) (const $ pure Nothing)
|
|
| 648 | + purgeInterpSymbolCache (interpSymbolCache interp)
|
|
| 649 | + modifyMVar_ (interpStringCache interp) (const $ pure emptyFsEnv)
|
|
| 648 | 650 | pure InterpPending
|
| 649 | 651 | |
| 650 | 652 | -- -----------------------------------------------------------------------------
|
| ... | ... | @@ -12,13 +12,10 @@ import GHC.Prelude |
| 12 | 12 | import GHC.Runtime.Interpreter.Types
|
| 13 | 13 | import GHCi.Message
|
| 14 | 14 | |
| 15 | -import GHC.IO (catchException)
|
|
| 16 | 15 | import GHC.Utils.Panic
|
| 17 | 16 | import GHC.Utils.Exception as Ex
|
| 18 | 17 | |
| 19 | 18 | import Data.Binary
|
| 20 | -import System.Exit
|
|
| 21 | -import System.Process
|
|
| 22 | 19 | import Control.Concurrent
|
| 23 | 20 | import Data.IORef
|
| 24 | 21 | import Control.Concurrent.STM
|
| ... | ... | @@ -34,7 +31,6 @@ import Control.Concurrent.STM |
| 34 | 31 | sendMessage :: Binary a => ExtInterpInstance d -> Message a -> IO a
|
| 35 | 32 | sendMessage i msg =
|
| 36 | 33 | remoteCall (interpPipe proc) msg
|
| 37 | - `catchException` \(e :: SomeException) -> handleInterpProcessFailure proc e
|
|
| 38 | 34 | where
|
| 39 | 35 | proc = instProcess i
|
| 40 | 36 | |
| ... | ... | @@ -77,18 +73,6 @@ sendTHComputation i msg reqHandler = mask $ \restore -> do |
| 77 | 73 | else loop
|
| 78 | 74 | in loop
|
| 79 | 75 | |
| 80 | -handleInterpProcessFailure :: InterpProcess -> SomeException -> IO a
|
|
| 81 | -handleInterpProcessFailure i e = do
|
|
| 82 | - let hdl = interpHandle i
|
|
| 83 | - ex <- getProcessExitCode hdl
|
|
| 84 | - case ex of
|
|
| 85 | - Just (ExitFailure n) ->
|
|
| 86 | - throwIO (InstallationError ("External interpreter terminated (" ++ show n ++ ")"))
|
|
| 87 | - _ -> do
|
|
| 88 | - terminateProcess hdl
|
|
| 89 | - _ <- waitForProcess hdl
|
|
| 90 | - throw e
|
|
| 91 | - |
|
| 92 | 76 | data CancelTHHandler = CancelTHHandler deriving Show
|
| 93 | 77 | instance Exception CancelTHHandler where
|
| 94 | 78 | fromException = asyncExceptionFromException
|
| ... | ... | @@ -1160,7 +1160,7 @@ runRemoteModFinalizers (ThModFinalizers finRefs) = do |
| 1160 | 1160 | runQinTcM $ sequence_ qs
|
| 1161 | 1161 | #endif
|
| 1162 | 1162 | |
| 1163 | - ExternalInterp ext -> withExtInterp ext $ \inst -> do
|
|
| 1163 | + ExternalInterp ext -> withExtInterp interp ext $ \inst -> do
|
|
| 1164 | 1164 | tcg <- getGblEnv
|
| 1165 | 1165 | th_state <- readTcRef (tcg_th_remote_state tcg)
|
| 1166 | 1166 | case th_state of
|
| ... | ... | @@ -1817,7 +1817,7 @@ runTH ty fhv = do |
| 1817 | 1817 | return r
|
| 1818 | 1818 | #endif
|
| 1819 | 1819 | |
| 1820 | - ExternalInterp ext -> withExtInterp ext $ \inst -> do
|
|
| 1820 | + ExternalInterp ext -> withExtInterp interp ext $ \inst -> do
|
|
| 1821 | 1821 | -- Run it on the server. For an overview of how TH works with
|
| 1822 | 1822 | -- Remote GHCi, see Note [Remote Template Haskell] in
|
| 1823 | 1823 | -- libraries/ghci/GHCi/TH.hs.
|
| ... | ... | @@ -27,7 +27,7 @@ module GHCi.Message |
| 27 | 27 | , Pipe(..), mkPipeFromHandles, mkPipeFromContinuations, closePipe
|
| 28 | 28 | , remoteCall, remoteTHCall
|
| 29 | 29 | , handleRemoteCall, handleRemoteTHCall, writeReply
|
| 30 | - , RemoteProcessException(..), PipeReadClosedException(..)
|
|
| 30 | + , RemoteProcessException(..), PipeClosedException(..)
|
|
| 31 | 31 | |
| 32 | 32 | , InboxId(..)
|
| 33 | 33 | , newMailbox
|
| ... | ... | @@ -75,7 +75,6 @@ import GHC.Stack.CCS |
| 75 | 75 | import qualified GHC.Boot.TH.Syntax as TH
|
| 76 | 76 | import qualified GHC.Boot.TH.Monad as TH
|
| 77 | 77 | import GHCi.Message.Async
|
| 78 | -import Control.Monad.STM
|
|
| 79 | 78 | |
| 80 | 79 | -- -----------------------------------------------------------------------------
|
| 81 | 80 | -- The RPC protocol between GHC and the interactive server
|
| ... | ... | @@ -7,7 +7,7 @@ module GHCi.Message.Async |
| 7 | 7 | (
|
| 8 | 8 | -- * Pipes
|
| 9 | 9 | Pipe(..), mkPipeFromHandles, mkPipeFromContinuations
|
| 10 | - , closePipe, PipeReadClosedException(..)
|
|
| 10 | + , closePipe, PipeClosedException(..)
|
|
| 11 | 11 | |
| 12 | 12 | -- * Interface for async bidirectional RPC
|
| 13 | 13 | , remoteAsyncReq, handleAsyncReq
|
| ... | ... | @@ -145,13 +145,13 @@ closePipe p@Pipe{..} = do |
| 145 | 145 | unless writeAlreadyClosed
|
| 146 | 146 | (throwTo (asyncFillTid pipeAsyncMngr) PipeWriteClosedException)
|
| 147 | 147 | |
| 148 | --- | We've closed the pipe read end on this process
|
|
| 149 | -data PipeReadClosedException = PipeReadClosedException deriving Show
|
|
| 150 | -instance Exception PipeReadClosedException
|
|
| 148 | +data PipeClosedException
|
|
| 149 | + = PipeReadClosedException -- ^ We've closed the pipe read end on this process
|
|
| 150 | + |
|
| 151 | + | PipeWriteClosedException -- ^ We've closed the pipe write end on this process
|
|
| 152 | + deriving Show
|
|
| 153 | +instance Exception PipeClosedException
|
|
| 151 | 154 | |
| 152 | --- | We've closed the pipe write end on this process
|
|
| 153 | -data PipeWriteClosedException = PipeWriteClosedException deriving Show
|
|
| 154 | -instance Exception PipeWriteClosedException
|
|
| 155 | 155 | |
| 156 | 156 | --------------------------------------------------------------------------------
|
| 157 | 157 | -- ** Pipe thread-safe read/write
|
| ... | ... | @@ -539,7 +539,7 @@ fetchedRequest am uq = do |
| 539 | 539 | |
| 540 | 540 | {-
|
| 541 | 541 | Note [Exceptions during serialization]
|
| 542 | ------------------------------------------------------------------------------
|
|
| 542 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 543 | 543 | |
| 544 | 544 | For efficiency reasons, any `IddMsg` to be sent is forced only when already
|
| 545 | 545 | writing onto the Pipe, so we cannot discern whether any raised exception
|
| ... | ... | @@ -39,7 +39,6 @@ import System.Exit |
| 39 | 39 | import System.IO
|
| 40 | 40 | |
| 41 | 41 | import Control.Concurrent
|
| 42 | -import Control.Monad.STM
|
|
| 43 | 42 | import GHCi.Message.Async (runWriteReply, (%>>=))
|
| 44 | 43 | import GHCi.Server.Threads
|
| 45 | 44 |