@@ -19,7 +19,8 @@ import Data.Text.Lazy.Encoding (encodeUtf8)
19import qualified Data.ByteString.Lazy.Char8 as L8
19import qualified Data.ByteString.Lazy.Char8 as L8
20import Control.Exception (Exception, SomeException, toException, fromException, finally, mask)
20import Control.Exception (Exception, SomeException, toException, fromException, finally, mask)
21import qualified Control.Exception as E
21import qualified Control.Exception as E
22−import Control.Concurrent (forkIO, threadDelay, killThread)
22+import Control.Concurrent (ThreadId, myThreadId, threadDelay, killThread)
23+import qualified Control.Concurrent as Concurrent
24import Data.Maybe
25import Data.Maybe
25import Control.Monad
26import Control.Monad
@@ -46,6 +47,20 @@ runQuit :: Int -> ModuleName -> FunctionName -> (FilePath -> IO [FilePath])
47runQuit port modu func extras = runQuitWithReloadActions port modu func extras []
48runQuit port modu func extras = runQuitWithReloadActions port modu func extras []
51+-- A version of `Concurrent.forkIO` that re-throws any uncaught
52+-- `E.UserInterrupt` from the child thread in the parent thread.
54+-- We need this because using hint (or the GHC API) causes @UserInterrupt@ to
55+-- occur in the thread that runs `runInterpreter` instead of the main thread.
56+forkIO :: IO () -> IO ThreadId
58+ threadId <- myThreadId
59+ Concurrent.forkIO (action `E.catch` \e -> case e of
60+ E.UserInterrupt -> E.throwTo threadId e
49runQuitWithReloadActions :: Int -> ModuleName -> FunctionName -> (FilePath -> IO [FilePath])
64runQuitWithReloadActions :: Int -> ModuleName -> FunctionName -> (FilePath -> IO [FilePath])
50 -> [IO (IO ())] -> IO ()
65 -> [IO (IO ())] -> IO ()
51runQuitWithReloadActions port modu func extras actions = do
66runQuitWithReloadActions port modu func extras actions = do