Rodrigo Mesquita pushed to branch wip/romes/async-rpc at Glasgow Haskell Compiler / GHC

Commits:

5 changed files:

Changes:

  • compiler/GHC/Runtime/Interpreter/Process.hs
    ... ... @@ -48,7 +48,7 @@ sendMessage i msg =
    48 48
     sendTHComputation
    
    49 49
       :: Binary a
    
    50 50
       => ExtInterpInstance d
    
    51
    -  -> Message a
    
    51
    +  -> (InboxId -> Message a)
    
    52 52
       -> (forall b. Binary b => THMessage b -> IO (Bool, b))
    
    53 53
       -- ^ Handle one message. Return True to end the loop.
    
    54 54
       -- This handler must never uninterrutibly mask an expression which may get
    
    ... ... @@ -56,21 +56,22 @@ sendTHComputation
    56 56
       -> IO a
    
    57 57
     sendTHComputation i msg reqHandler = mask $ \restore -> do
    
    58 58
       -- inline "withAsync/wait"
    
    59
    -  var <- newEmptyTMVarIO
    
    60
    -  ht  <- forkFinally (restore handlerLoop) (atomically . putTMVar var)
    
    61
    -  restore (sendMessage i msg <* atomically (readTMVar var))
    
    59
    +  var  <- newEmptyTMVarIO
    
    60
    +  mbox <- newMailbox (pipeAsyncMngr (interpPipe proc))
    
    61
    +  ht   <- forkFinally (restore (handlerLoop mbox)) (atomically . putTMVar var)
    
    62
    +  restore (sendMessage i (msg mbox) <* atomically (readTMVar var))
    
    62 63
         `onException` uninterruptibleMask_ (throwTo ht CancelTHHandler)
    
    63 64
       where
    
    64 65
         proc = instProcess i
    
    65
    -    handleOne doneRef = do
    
    66
    -      handleRemoteTHCall (interpPipe proc) $ \req -> do
    
    66
    +    handleOne mbox doneRef = do
    
    67
    +      handleRemoteTHCall (interpPipe proc) mbox $ \req -> do
    
    67 68
             (stop, res) <- reqHandler req
    
    68 69
             writeIORef doneRef stop
    
    69 70
             return res
    
    70
    -    handlerLoop = do
    
    71
    +    handlerLoop mbox = do
    
    71 72
           doneRef <- newIORef False
    
    72 73
           let loop = do
    
    73
    -            handleOne doneRef
    
    74
    +            handleOne mbox doneRef
    
    74 75
                 isDone <- readIORef doneRef
    
    75 76
                 if isDone then return ()
    
    76 77
                           else loop
    

  • compiler/GHC/Tc/Gen/Splice.hs
    ... ... @@ -1170,7 +1170,7 @@ runRemoteModFinalizers (ThModFinalizers finRefs) = do
    1170 1170
                 recovers <- newIORef []
    
    1171 1171
                 withForeignRef fhv $ \st ->
    
    1172 1172
                   withForeignRefs finRefs $ \qrefs ->
    
    1173
    -                sendTHComputation inst (RunModFinalizers st qrefs) $ \msg ->
    
    1173
    +                sendTHComputation inst (\ii -> RunModFinalizers ii st qrefs) $ \msg ->
    
    1174 1174
                       runInIO (runRemoteTH recovers msg)
    
    1175 1175
               checkQResult qr
    
    1176 1176
     
    
    ... ... @@ -1830,7 +1830,7 @@ runTH ty fhv = do
    1830 1830
             recovers <- newIORef []
    
    1831 1831
             withForeignRef rstate $ \state_hv ->
    
    1832 1832
               withForeignRef fhv $ \q_hv ->
    
    1833
    -            sendTHComputation inst (RunTH state_hv q_hv ty (Just loc)) $ \msg ->
    
    1833
    +            sendTHComputation inst (\ii -> RunTH ii state_hv q_hv ty (Just loc)) $ \msg ->
    
    1834 1834
                   runInIO (runRemoteTH recovers msg)
    
    1835 1835
           bs <- checkQResult qr
    
    1836 1836
           return $! runGet get (LB.fromStrict bs)
    

  • libraries/ghci/GHCi/Message.hs
    ... ... @@ -29,6 +29,10 @@ module GHCi.Message
    29 29
       , handleRemoteCall, handleRemoteTHCall
    
    30 30
       , RemoteProcessException(..), PipeClosedException(..)
    
    31 31
     
    
    32
    +  , InboxId(..)
    
    33
    +  , newMailbox
    
    34
    +  , closeMailbox
    
    35
    +
    
    32 36
       , BreakModule
    
    33 37
       , BreakUnitId
    
    34 38
       , LoadedDLL
    
    ... ... @@ -237,14 +241,16 @@ data Message a where
    237 241
       -- they did, we have to serialize the value anyway, so we might
    
    238 242
       -- as well serialize it to force it.
    
    239 243
       RunTH
    
    240
    -   :: RemoteRef (IORef QState)
    
    244
    +   :: InboxId -- ^ announce mailbox for related 'remoteTHCall's
    
    245
    +   -> RemoteRef (IORef QState)
    
    241 246
        -> HValueRef {- e.g. TH.Q TH.Exp -}
    
    242 247
        -> THResultType
    
    243 248
        -> Maybe TH.Loc
    
    244 249
        -> Message (QResult ByteString)
    
    245 250
     
    
    246 251
       -- | Run the given mod finalizers.
    
    247
    -  RunModFinalizers :: RemoteRef (IORef QState)
    
    252
    +  RunModFinalizers :: InboxId -- ^ announce mailbox for related 'remoteTHCall's
    
    253
    +                   -> RemoteRef (IORef QState)
    
    248 254
                        -> [RemoteRef (TH.Q ())]
    
    249 255
                        -> Message (QResult ())
    
    250 256
     
    
    ... ... @@ -536,11 +542,13 @@ instance Binary THResultType
    536 542
     -- StartTH message.  A new one is created per module that GHC
    
    537 543
     -- typechecks.
    
    538 544
     data QState = QState
    
    539
    -  { qsMap        :: Map TypeRep Dynamic
    
    545
    +  { qsMap      :: Map TypeRep Dynamic
    
    540 546
            -- ^ persistent data between splices in a module
    
    541
    -  , qsLocation   :: Maybe TH.Loc
    
    547
    +  , qsLocation :: Maybe TH.Loc
    
    542 548
            -- ^ location for current splice, if any
    
    543
    -  , qsPipe :: Pipe
    
    549
    +  , qsInboxId  :: InboxId
    
    550
    +      -- ^ the mailbox expecting requests for each RunTH-like run
    
    551
    +  , qsPipe     :: Pipe
    
    544 552
            -- ^ pipe to communicate with GHC
    
    545 553
       }
    
    546 554
     instance Show QState where show _ = "<QState>"
    
    ... ... @@ -623,9 +631,9 @@ getMessage = do
    623 631
           29 -> Msg <$> (BreakpointStatus <$> get <*> get)
    
    624 632
           30 -> Msg <$> (GetBreakpointVar <$> get <*> get)
    
    625 633
           31 -> Msg <$> return StartTH
    
    626
    -      32 -> Msg <$> (RunModFinalizers <$> get <*> get)
    
    634
    +      32 -> Msg <$> (RunModFinalizers <$> get <*> get <*> get)
    
    627 635
           33 -> Msg <$> (AddSptEntry <$> get <*> get)
    
    628
    -      34 -> Msg <$> (RunTH <$> get <*> get <*> get <*> get)
    
    636
    +      34 -> Msg <$> (RunTH <$> get <*> get <*> get <*> get <*> get)
    
    629 637
           35 -> Msg <$> (GetClosure <$> get)
    
    630 638
           36 -> Msg <$> (Seq <$> get)
    
    631 639
           37 -> Msg <$> return RtsRevertCAFs
    
    ... ... @@ -671,9 +679,9 @@ putMessage m = case m of
    671 679
       BreakpointStatus arr ix     -> putWord8 29 >> put arr >> put ix
    
    672 680
       GetBreakpointVar a b        -> putWord8 30 >> put a >> put b
    
    673 681
       StartTH                     -> putWord8 31
    
    674
    -  RunModFinalizers a b        -> putWord8 32 >> put a >> put b
    
    682
    +  RunModFinalizers a b c      -> putWord8 32 >> put a >> put b >> put c
    
    675 683
       AddSptEntry a b             -> putWord8 33 >> put a >> put b
    
    676
    -  RunTH st q loc ty           -> putWord8 34 >> put st >> put q >> put loc >> put ty
    
    684
    +  RunTH ii st q loc ty        -> putWord8 34 >> put ii >> put st >> put q >> put loc >> put ty
    
    677 685
       GetClosure a                -> putWord8 35 >> put a
    
    678 686
       Seq a                       -> putWord8 36 >> put a
    
    679 687
       RtsRevertCAFs               -> putWord8 37
    
    ... ... @@ -774,7 +782,7 @@ closePipe Pipe{..} = do
    774 782
     -- (blocks on the calling side, doesn't necessarily block the interpreter)
    
    775 783
     remoteCall :: Binary a => Pipe -> Message a -> IO a
    
    776 784
     remoteCall pipe msg = either throwIO (pure . runGet get)
    
    777
    -                  =<< remoteAsyncReq pipe (putMessage msg)
    
    785
    +                  =<< remoteAsyncReq pipe (putMessage msg) Nothing
    
    778 786
     
    
    779 787
     -- | Handle a single 'Message' request on the interpreter and reply to the host
    
    780 788
     handleRemoteCall :: Pipe
    
    ... ... @@ -782,22 +790,28 @@ handleRemoteCall :: Pipe
    782 790
                      -> (forall a. (Show a, Binary a) => Message a -> IO a)
    
    783 791
                      -> IO ()
    
    784 792
     handleRemoteCall pipe hook k =
    
    785
    -  handleAsyncReq pipe getMessage \writer msg0 -> IO \s0 ->
    
    793
    +  handleAsyncReq pipe getMessage Nothing \writer msg0 -> IO \s0 ->
    
    786 794
         case hook msg0 |#> s0 of -- unIO for linearity checking
    
    787 795
           (# s1, Msg msg #) -> case k msg |#> s1 of
    
    788 796
             (# s2, a #) -> writeReply writer (put a) |#> s2
    
    789 797
     
    
    790 798
     -- | Send a 'THMessage' request to the host and wait for a reply from the host
    
    791
    --- to the interpreter
    
    792
    -remoteTHCall :: Binary a => Pipe -> THMessage a -> IO a
    
    793
    -remoteTHCall pipe msg = either throwIO (pure . runGet get)
    
    794
    -                    =<< remoteAsyncReq pipe (putTHMessage msg)
    
    799
    +-- to the interpreter.
    
    800
    +--
    
    801
    +-- A 'THMessage' request from the interpreter is always associated with a
    
    802
    +-- 'RunTH'-like run. Since the host may have many in-flight TH runs, we always
    
    803
    +-- want a specific host 'InboxId' (which is announced in the 'RunTH' request)
    
    804
    +remoteTHCall :: Binary a => Pipe -> InboxId -> THMessage a -> IO a
    
    805
    +remoteTHCall pipe ii msg = either throwIO (pure . runGet get)
    
    806
    +                       =<< remoteAsyncReq pipe (putTHMessage msg) (Just ii)
    
    795 807
     
    
    796 808
     -- | Handle a 'THMessage' request on the host and reply to the interpreter.
    
    809
    +-- Symmterically to 'remoteTHCall', we always want to specify the 'InboxId' for
    
    810
    +-- RunTH "reverse requests"
    
    797 811
     handleRemoteTHCall
    
    798
    -  :: Pipe -> (forall a. (Show a, Binary a) => THMessage a -> IO a) -> IO ()
    
    799
    -handleRemoteTHCall pipe k =
    
    800
    -  handleAsyncReq pipe getTHMessage \writer (THMsg msg) -> IO \s0 ->
    
    812
    +  :: Pipe -> InboxId -> (forall a. (Show a, Binary a) => THMessage a -> IO a) -> IO ()
    
    813
    +handleRemoteTHCall pipe ii k =
    
    814
    +  handleAsyncReq pipe getTHMessage (Just ii) \writer (THMsg msg) -> IO \s0 ->
    
    801 815
         case k msg |#> s0 of -- unIO for linearity checking
    
    802 816
           (# s1, a #) -> writeReply writer (put a) |#> s1
    
    803 817
     
    
    ... ... @@ -806,13 +820,13 @@ handleRemoteTHCall pipe k =
    806 820
     --------------------------------------------------------------------------------
    
    807 821
     
    
    808 822
     -- | Send an asynchronous request and block waiting for a matching reply
    
    809
    -remoteAsyncReq :: Pipe -> Put -> IO (Either SomeException LB.ByteString)
    
    810
    -remoteAsyncReq pipe msg = do
    
    823
    +remoteAsyncReq :: Pipe -> Put -> (Maybe InboxId) -> IO (Either SomeException LB.ByteString)
    
    824
    +remoteAsyncReq pipe msg ii = do
    
    811 825
     
    
    812 826
       let pendingReplies = pendingReply (pipeAsyncMngr pipe)
    
    813 827
     
    
    814 828
       -- Mark pending request
    
    815
    -  uq <- freshReqId (pipeAsyncMngr pipe)
    
    829
    +  uq <- freshId (pipeAsyncMngr pipe)
    
    816 830
       wv <- newEmptyTMVarIO
    
    817 831
     
    
    818 832
       isClosed <- atomically $ do
    
    ... ... @@ -827,7 +841,7 @@ remoteAsyncReq pipe msg = do
    827 841
         throwIO PipeClosedException
    
    828 842
     
    
    829 843
       -- Write request
    
    830
    -  writePipe pipe (Request uq (runPut msg))
    
    844
    +  writePipe pipe (Request uq ii (runPut msg))
    
    831 845
         `onException`
    
    832 846
           -- the req wasn't done, or no one will be reading the reply:
    
    833 847
           -- in either case, drop it from the pending map.
    
    ... ... @@ -845,18 +859,20 @@ remoteAsyncReq pipe msg = do
    845 859
     -- The handler receives as an argument the function to use to reply to the request.
    
    846 860
     -- It must be used exactly once (all requests expect a reply, and you can't
    
    847 861
     -- reply more than once). Linear types enforce the handler replies in every
    
    848
    --- branch, and if the handler otherwise throws, it is handled by 'withAsyncHandler'.
    
    849
    -handleAsyncReq :: Pipe -> Get a -> (WriteReply Put %1 -> a -> IO r) -> IO r
    
    850
    -handleAsyncReq pipe getit k = mask $ \restore -> do
    
    862
    +-- branch, and if the handler otherwise throws, it is handled by 'handleAsyncReq'.
    
    863
    +handleAsyncReq :: Pipe -> Get a -> (Maybe InboxId) -> (WriteReply Put %1 -> a -> IO r) -> IO r
    
    864
    +handleAsyncReq pipe getit mii k = mask $ \restore -> do
    
    865
    +  let am = pipeAsyncMngr pipe
    
    851 866
       ack <- newEmptyMVar
    
    852 867
     
    
    853 868
       -- Block waiting for request
    
    854 869
       mbreq <- atomically $ do
    
    855 870
         isClosed <- readTVar (pipeIsClosed pipe)
    
    856
    -    isEmpty  <- isEmptyTQueue (requestsQueue (pipeAsyncMngr pipe))
    
    857
    -    if isClosed && isEmpty
    
    871
    +    if isClosed
    
    858 872
           then return Nothing
    
    859
    -      else Just <$> readTQueue (requestsQueue (pipeAsyncMngr pipe))
    
    873
    +      else Just <$> case mii of
    
    874
    +        Nothing -> readTQueue  $  requestsQueue am
    
    875
    +        Just ii -> readTQueue =<< getMailbox am ii
    
    860 876
     
    
    861 877
       case mbreq of
    
    862 878
         Nothing -> throwIO PipeClosedException
    
    ... ... @@ -907,15 +923,40 @@ data AsyncManager = AsyncManager
    907 923
         -- TMVar is signaled when the reply arrives. The exception can originate
    
    908 924
         -- from the host process, or from the remote one (with 'RemoteProcessException').
    
    909 925
       , requestsQueue :: !(TQueue (CorrelationId, LB.ByteString))
    
    910
    -    -- ^ A queue of pending received requests. When a request is received,
    
    911
    -    -- queue it here. A request handler will pop the next request from it.
    
    912
    -    -- (Nothing except the 'drainPipe' thread should read from the pipe).
    
    926
    +    -- ^ A queue of pending received requests. When a request is received
    
    927
    +    -- /without/ a specific 'InboxId', queue it here. A request handler will
    
    928
    +    -- pop the next request from it. (Nothing except the 'drainPipe' thread
    
    929
    +    -- should read from the pipe). Read with @'handleAsyncReq' p get Nothing@.
    
    930
    +  , mailboxQueues :: !(TVar (IntMap (TQueue (CorrelationId, LB.ByteString))))
    
    931
    +    -- ^ Requests for a specific 'InboxId' that can be read using
    
    932
    +    -- @'handleAsyncReq' p get (Just <mailboxid>)@.
    
    913 933
       , asyncDrainTid :: !ThreadId
    
    914
    -  , asyncNextReq  :: !(IORef Int)
    
    934
    +  , asyncFreshId  :: !(IORef Int)
    
    915 935
       }
    
    916 936
     
    
    937
    +-- | Each 'Request' expects a 'Reply' with a matching 'CorrelationId'.
    
    917 938
     type CorrelationId = Int
    
    918 939
     
    
    940
    +-- | A 'Request' may optionally declare an 'InboxId'. If it does, it can only
    
    941
    +-- be read by a 'handleAsyncReq' for that specific 'InboxId'. That is,
    
    942
    +-- @'handleAsyncReq' p get Nothing@ will not receive messages meant for a
    
    943
    +-- specific inbox.
    
    944
    +--
    
    945
    +-- This is useful to prevent mixing up reverse requests, where we want to send
    
    946
    +-- many reverse requests but have the caller handle them without interleaving
    
    947
    +-- them.
    
    948
    +newtype InboxId = InboxId Int deriving (Show, Binary)
    
    949
    +
    
    950
    +-- | Create a new mailbox from where we can read all requests addressed to this 'InboxId'.
    
    951
    +newMailbox :: AsyncManager -> IO InboxId
    
    952
    +newMailbox am = InboxId <$> freshId am
    
    953
    +  -- `mailboxQueues` is written on demand, no need to do it here.
    
    954
    +
    
    955
    +-- | Clean up a created mailbox by 'InboxId'.
    
    956
    +closeMailbox :: AsyncManager -> InboxId -> IO ()
    
    957
    +closeMailbox AsyncManager{..} (InboxId ii) =
    
    958
    +  atomically (modifyTVar mailboxQueues (IntMap.delete ii))
    
    959
    +
    
    919 960
     -- | We have a single type for requests and replies because both the host and
    
    920 961
     -- interpreter may send requests *and* replies on the write end *and* on recv
    
    921 962
     -- both on the read end.
    
    ... ... @@ -925,28 +966,37 @@ type CorrelationId = Int
    925 966
     --  2. The interpreter sends a NewName TH request on its Interpreter Write End (IWE)
    
    926 967
     --  3. The host sends a reply to the TH request on its HWE
    
    927 968
     --  4. The interpreter sends the reply to the RunTH request on its IWE
    
    928
    -data IddMsg  = Request !CorrelationId LB.ByteString
    
    969
    +--
    
    970
    +-- Additionally, we want to keep concurrent TH requests for independent RunTH
    
    971
    +-- calls separated. Thus the interpreter requests additionally specify a
    
    972
    +-- mailbox announced by RunTH:
    
    973
    +--  1. To interpreter:   @Request _ Nothing (RunTH <mailid>)@
    
    974
    +--  2. From interpreter: @Request _ (Just <mailid>) NewName@
    
    975
    +-- And the host will relate the <mailid> reverse requests to that RunTH run
    
    976
    +-- exclusively.
    
    977
    +data IddMsg  = Request !CorrelationId !(Maybe InboxId) LB.ByteString
    
    929 978
                  | Reply   !CorrelationId (Either SerializableException LB.ByteString)
    
    930 979
     
    
    931 980
     instance Binary IddMsg where
    
    932
    -  put (Request i bs) = putWord8 0 >> put i >> put bs
    
    933
    -  put (Reply i bs)   = putWord8 1 >> put i >> put bs
    
    981
    +  put (Request i ii bs) = putWord8 0 >> put i >> put ii >> put bs
    
    982
    +  put (Reply i bs)      = putWord8 1 >> put i >> put bs
    
    934 983
       get = do
    
    935 984
         b <- getWord8
    
    936 985
         case b of
    
    937
    -      0 -> Request <$> get <*> get
    
    986
    +      0 -> Request <$> get <*> get <*> get
    
    938 987
           1 -> Reply   <$> get <*> get
    
    939 988
           _ -> fail $ "impossible: Binary IddMsg - " ++ show b
    
    940 989
     
    
    941 990
     newAsyncManager :: Pipe -> IO AsyncManager
    
    942 991
     newAsyncManager pipe = do
    
    943
    -  asyncNextReq <- newIORef 0
    
    992
    +  asyncFreshId  <- newIORef 0
    
    944 993
       pendingReply  <- newTVarIO IntMap.empty
    
    945
    -  requestsQueue  <- newTQueueIO
    
    994
    +  requestsQueue <- newTQueueIO
    
    995
    +  mailboxQueues <- newTVarIO IntMap.empty
    
    946 996
     
    
    947 997
       -- Fork thread to drain read end.
    
    948 998
       -- (cleaned up on 'closePipe')
    
    949
    -  asyncDrainTid  <- forkIOWithUnmask (drainPipe pipe)
    
    999
    +  asyncDrainTid <- forkIOWithUnmask (drainPipe pipe)
    
    950 1000
     
    
    951 1001
       let am = AsyncManager{..}
    
    952 1002
       pure am
    
    ... ... @@ -975,8 +1025,15 @@ drainPipe p unmask = catch (unmask loop) replyToPendings where
    975 1025
                   putTMVar wv (bimap (toException . RemoteProcessException) id bs)
    
    976 1026
             loop
    
    977 1027
           -- Receive a request and queue it
    
    978
    -      Just (Request uq bs) -> do
    
    979
    -        atomically $ writeTQueue (requestsQueue am) (uq,bs)
    
    1028
    +      Just (Request uq mbi bs) -> do
    
    1029
    +        atomically $ case mbi of
    
    1030
    +          Nothing ->
    
    1031
    +            -- "Global" request
    
    1032
    +            writeTQueue (requestsQueue am) (uq,bs)
    
    1033
    +          Just ii -> do
    
    1034
    +            -- "Specific mailbox" request
    
    1035
    +            q <- getMailbox am ii
    
    1036
    +            writeTQueue q (uq,bs)
    
    980 1037
             loop
    
    981 1038
           -- EOF on read handle
    
    982 1039
           Nothing -> do
    
    ... ... @@ -991,9 +1048,20 @@ drainPipe p unmask = catch (unmask loop) replyToPendings where
    991 1048
     
    
    992 1049
       am = pipeAsyncMngr p
    
    993 1050
     
    
    994
    -freshReqId :: AsyncManager -> IO CorrelationId
    
    995
    -freshReqId AsyncManager{asyncNextReq} =
    
    996
    -  atomicModifyIORef' asyncNextReq $ \i -> (i+1, i)
    
    1051
    +freshId :: AsyncManager -> IO Int
    
    1052
    +freshId AsyncManager{asyncFreshId} =
    
    1053
    +  atomicModifyIORef' asyncFreshId $ \i -> (i+1, i)
    
    1054
    +
    
    1055
    +getMailbox :: AsyncManager -> InboxId -> STM (TQueue (CorrelationId, LB.ByteString))
    
    1056
    +getMailbox am (InboxId ii) = do
    
    1057
    +  mboxes <- readTVar (mailboxQueues am)
    
    1058
    +  case IntMap.lookup ii mboxes of
    
    1059
    +    Nothing -> do
    
    1060
    +      q <- newTQueue
    
    1061
    +      writeTVar (mailboxQueues am) (IntMap.insert ii q mboxes)
    
    1062
    +      pure q
    
    1063
    +    Just q ->
    
    1064
    +      pure q
    
    997 1065
     
    
    998 1066
     --------------------------------------------------------------------------------
    
    999 1067
     -- * Pipe thread-safe read/write
    

  • libraries/ghci/GHCi/Server.hs
    ... ... @@ -74,8 +74,8 @@ servWithCustom verbose hook pipe restore customHandler = newIORef False >>= loop
    74 74
             CustomMessage tag payload -> handleCustom tag payload
    
    75 75
             Shutdown -> writeIORef doneRef True >> reply ()
    
    76 76
             -- TODO: These two should probably be done off the main thread
    
    77
    -        RunTH st q ty loc -> wrapRunTH $ runTH pipe st q ty loc
    
    78
    -        RunModFinalizers st qrefs -> wrapRunTH $ runModFinalizerRefs pipe st qrefs
    
    77
    +        RunTH ii st q ty loc -> wrapRunTH ii $ runTH pipe ii st q ty loc
    
    78
    +        RunModFinalizers ii st qrefs -> wrapRunTH ii $ runModFinalizerRefs pipe ii st qrefs
    
    79 79
             _other -> run msg >>= reply
    
    80 80
     
    
    81 81
         isDone <- readIORef doneRef
    
    ... ... @@ -98,13 +98,13 @@ servWithCustom verbose hook pipe restore customHandler = newIORef False >>= loop
    98 98
       -- THMessage requests, and then finally send RunTHDone followed by a
    
    99 99
       -- QResult.  For an overview of how TH works with Remote GHCi, see
    
    100 100
       -- Note [Remote Template Haskell] in libraries/ghci/GHCi/TH.hs.
    
    101
    -  wrapRunTH :: forall a. (Binary a, Show a) => IO a -> IO (QResult a)
    
    102
    -  wrapRunTH io = do
    
    101
    +  wrapRunTH :: forall a. (Binary a, Show a) => InboxId -> IO a -> IO (QResult a)
    
    102
    +  wrapRunTH ii io = do
    
    103 103
         when verbose $ trace "wrapRunTH..."
    
    104 104
         r <- try io
    
    105 105
         when verbose $ trace "wrapRunTH done."
    
    106 106
         when verbose $ trace "writing RunTHDone."
    
    107
    -    remoteTHCall pipe RunTHDone
    
    107
    +    remoteTHCall pipe ii RunTHDone
    
    108 108
         case r of
    
    109 109
           Left e
    
    110 110
             | Just (GHCiQException _ err) <- fromException e  -> do
    

  • libraries/ghci/GHCi/TH.hs
    ... ... @@ -115,8 +115,8 @@ import qualified GHC.Boot.TH.Monad as TH
    115 115
     import Unsafe.Coerce
    
    116 116
     
    
    117 117
     -- | Create a new instance of 'QState'
    
    118
    -initQState :: Pipe -> QState
    
    119
    -initQState p = QState M.empty Nothing p
    
    118
    +initQState :: Pipe -> InboxId -> QState
    
    119
    +initQState p ii = QState M.empty Nothing ii p
    
    120 120
     
    
    121 121
     -- | The monad in which we run TH computations on the server
    
    122 122
     newtype GHCiQ a = GHCiQ { runGHCiQ :: IORef QState -> IO a }
    
    ... ... @@ -156,7 +156,7 @@ noLoc = TH.Loc "<no file>" "<no package>" "<no module>" (0,0) (0,0)
    156 156
     ghcCmd :: Binary a => THMessage (THResult a) -> GHCiQ a
    
    157 157
     ghcCmd m = GHCiQ $ \sRef -> do
    
    158 158
       s <- readIORef sRef
    
    159
    -  r <- remoteTHCall (qsPipe s) m
    
    159
    +  r <- remoteTHCall (qsPipe s) (qsInboxId s) m
    
    160 160
       case r of
    
    161 161
         THException str -> throwIO (GHCiQException s str)
    
    162 162
         THComplete res -> return res
    
    ... ... @@ -189,9 +189,9 @@ metaHandlersGHCiQ runInIO = TH.MetaHandlers {
    189 189
       -- See Note [TH recover with -fexternal-interpreter] in GHC.Tc.Gen.Splice
    
    190 190
       , mRecover = \h a -> runInIO $ GHCiQ $ \sRef -> mask $ \unmask -> do
    
    191 191
           s <- readIORef sRef
    
    192
    -      remoteTHCall (qsPipe s) StartRecover
    
    192
    +      remoteTHCall (qsPipe s) (qsInboxId s) StartRecover
    
    193 193
           e <- try $ unmask $ runGHCiQ (runQinGHCiQ a <* ghcCmd FailIfErrs) sRef
    
    194
    -      remoteTHCall (qsPipe s) (EndRecover (isLeft e))
    
    194
    +      remoteTHCall (qsPipe s) (qsInboxId s) (EndRecover (isLeft e))
    
    195 195
           case e of
    
    196 196
             Left GHCiQException{} ->
    
    197 197
               runGHCiQ (runQinGHCiQ h) sRef
    
    ... ... @@ -233,26 +233,28 @@ metaHandlersGHCiQ runInIO = TH.MetaHandlers {
    233 233
     -- a new IORef QState, and return a RemoteRef to it.
    
    234 234
     startTH :: IO (RemoteRef (IORef QState))
    
    235 235
     startTH = do
    
    236
    -  r <- newIORef (initQState (error "startTH: no pipe"))
    
    236
    +  r <- newIORef (initQState (error "startTH: no pipe") (error "startTH: no inbox id"))
    
    237 237
       mkRemoteRef r
    
    238 238
     
    
    239 239
     -- | Runs the mod finalizers.
    
    240 240
     --
    
    241 241
     -- The references must be created on the caller process.
    
    242
    -runModFinalizerRefs :: Pipe -> RemoteRef (IORef QState)
    
    242
    +runModFinalizerRefs :: Pipe -> InboxId
    
    243
    +                    -> RemoteRef (IORef QState)
    
    243 244
                         -> [RemoteRef (TH.Q ())]
    
    244 245
                         -> IO ()
    
    245
    -runModFinalizerRefs pipe rstate qrefs = do
    
    246
    +runModFinalizerRefs pipe ii rstate qrefs = do
    
    246 247
       qs <- mapM localRef qrefs
    
    247 248
       qstateref <- localRef rstate
    
    248 249
       qstate <- readIORef qstateref
    
    249
    -  qstate' <- newIORef $ qstate { qsPipe = pipe }
    
    250
    +  qstate' <- newIORef $ qstate { qsInboxId = ii, qsPipe = pipe }
    
    250 251
       _ <- runGHCiQ (runQinGHCiQ $ sequence_ qs) qstate'
    
    251 252
       return ()
    
    252 253
     
    
    253 254
     -- | The implementation of the 'RunTH' message
    
    254 255
     runTH
    
    255 256
       :: Pipe
    
    257
    +  -> InboxId
    
    256 258
       -> RemoteRef (IORef QState)
    
    257 259
           -- ^ The TH state, created by 'startTH'
    
    258 260
       -> HValueRef
    
    ... ... @@ -264,13 +266,13 @@ runTH
    264 266
       -> IO ByteString
    
    265 267
           -- ^ Returns an (encoded) result that depends on the THResultType
    
    266 268
     
    
    267
    -runTH pipe rstate rhv ty mb_loc = do
    
    269
    +runTH pipe ii rstate rhv ty mb_loc = do
    
    268 270
       hv <- localRef rhv
    
    269 271
       case ty of
    
    270
    -    THExp -> runTHQ pipe rstate mb_loc (unsafeCoerce hv :: TH.Q TH.Exp)
    
    271
    -    THPat -> runTHQ pipe rstate mb_loc (unsafeCoerce hv :: TH.Q TH.Pat)
    
    272
    -    THType -> runTHQ pipe rstate mb_loc (unsafeCoerce hv :: TH.Q TH.Type)
    
    273
    -    THDec -> runTHQ pipe rstate mb_loc (unsafeCoerce hv :: TH.Q [TH.Dec])
    
    272
    +    THExp -> runTHQ pipe ii rstate mb_loc (unsafeCoerce hv :: TH.Q TH.Exp)
    
    273
    +    THPat -> runTHQ pipe ii rstate mb_loc (unsafeCoerce hv :: TH.Q TH.Pat)
    
    274
    +    THType -> runTHQ pipe ii rstate mb_loc (unsafeCoerce hv :: TH.Q TH.Type)
    
    275
    +    THDec -> runTHQ pipe ii rstate mb_loc (unsafeCoerce hv :: TH.Q [TH.Dec])
    
    274 276
         THAnnWrapper -> do
    
    275 277
           hv <- unsafeCoerce <$> localRef rhv
    
    276 278
           case hv :: AnnotationWrapper of
    
    ... ... @@ -279,10 +281,10 @@ runTH pipe rstate rhv ty mb_loc = do
    279 281
     
    
    280 282
     -- | Run a Q computation.
    
    281 283
     runTHQ
    
    282
    -  :: Binary a => Pipe -> RemoteRef (IORef QState) -> Maybe TH.Loc -> TH.Q a
    
    284
    +  :: Binary a => Pipe -> InboxId -> RemoteRef (IORef QState) -> Maybe TH.Loc -> TH.Q a
    
    283 285
       -> IO ByteString
    
    284
    -runTHQ pipe rstate mb_loc ghciq = do
    
    286
    +runTHQ pipe ii rstate mb_loc ghciq = do
    
    285 287
       qstateref <- localRef rstate
    
    286
    -  modifyIORef' qstateref (\qstate -> qstate { qsLocation = mb_loc, qsPipe = pipe })
    
    288
    +  modifyIORef' qstateref (\qstate -> qstate { qsLocation = mb_loc, qsInboxId = ii, qsPipe = pipe })
    
    287 289
       r <- runGHCiQ (runQinGHCiQ ghciq) qstateref
    
    288 290
       return $! LB.toStrict (runPut (put r))