@@ -5,6 +5,7 @@
5{-# LANGUAGE BangPatterns #-}
5{-# LANGUAGE BangPatterns #-}
6{-# LANGUAGE GeneralizedNewtypeDeriving #-}
6{-# LANGUAGE GeneralizedNewtypeDeriving #-}
7{-# LANGUAGE RecordWildCards #-}
7{-# LANGUAGE RecordWildCards #-}
8+{-# LANGUAGE MagicHash #-}
9-- | Local nodes
10-- | Local nodes
@@ -65,6 +66,8 @@ import Control.Exception
65 , Exception
66 , Exception
67 , uninterruptibleMask_
68 , uninterruptibleMask_
69import qualified Control.Exception as Exception
72import qualified Control.Exception as Exception
70 ( Handler(..)
73 ( Handler(..)
@@ -83,6 +86,12 @@ import Control.Distributed.Process.Internal.StrictMVar
84 , takeMVar
87 , takeMVar
89+import Control.Distributed.Process.Internal.ThreadPool
86import Control.Concurrent.Chan (newChan, writeChan, readChan)
95import Control.Concurrent.Chan (newChan, writeChan, readChan)
87import qualified Control.Concurrent.MVar as MVar (newEmptyMVar, takeMVar)
96import qualified Control.Concurrent.MVar as MVar (newEmptyMVar, takeMVar)
88import Control.Concurrent.STM
97import Control.Concurrent.STM
@@ -218,8 +227,18 @@ import qualified Control.Distributed.Process.Internal.StrictContainerAccessors a
218 ( mapMaybe
227 ( mapMaybe
219 , mapDefault
228 , mapDefault
230+import GHC.IO (IO(..), unsafeUnmask)
231+import GHC.Base ( maskAsyncExceptions# )
221import Unsafe.Coerce
233import Unsafe.Coerce
235+-- Remove these when this is fixed:
236+-- https://ghc.haskell.org/trac/ghc/ticket/10149
237+block :: IO a -> IO a
238+block (IO io) = IO $ maskAsyncExceptions# io
239+unblock :: IO a -> IO a
240+unblock = unsafeUnmask
223--------------------------------------------------------------------------------
242--------------------------------------------------------------------------------
224-- Initialization --
243-- Initialization --
225--------------------------------------------------------------------------------
244--------------------------------------------------------------------------------
@@ -249,12 +268,14 @@ createBareLocalNode endPoint rtable = do
249 , _localConnections = Map.empty
268 , _localConnections = Map.empty
251 ctrlChan <- newChan
270 ctrlChan <- newChan
271+ sendPool <- newThreadPool
252 let node = LocalNode { localNodeId = NodeId $ NT.address endPoint
272 let node = LocalNode { localNodeId = NodeId $ NT.address endPoint
253 , localEndPoint = endPoint
273 , localEndPoint = endPoint
254 , localState = state
274 , localState = state
255 , localCtrlChan = ctrlChan
275 , localCtrlChan = ctrlChan
256 , localEventBus = MxEventBusInitialising
276 , localEventBus = MxEventBusInitialising
257 , remoteTable = rtable
277 , remoteTable = rtable
278+ , localSendPool = sendPool
259 tracedNode <- startMxAgent node
280 tracedNode <- startMxAgent node
@@ -361,11 +382,14 @@ runProcess node proc = do
362-- | Spawn a new process on a local node
383-- | Spawn a new process on a local node
363forkProcess :: LocalNode -> Process () -> IO ProcessId
384forkProcess :: LocalNode -> Process () -> IO ProcessId
364−forkProcess node proc =
385+forkProcess node proc = do
386+ ms <- getMaskingState
365− modifyMVarMasked (localState node) startProcess
387+ modifyMVarMasked (localState node) (startProcess ms)
389+ startProcess :: MaskingState
367− startProcess :: LocalNodeState -> IO (LocalNodeState, ProcessId)
391+ -> IO (LocalNodeState, ProcessId)
368− startProcess (LocalNodeValid vst) = do
392+ startProcess ms (LocalNodeValid vst) = do
369 let lpid = LocalProcessId { lpidCounter = vst ^. localPidCounter
393 let lpid = LocalProcessId { lpidCounter = vst ^. localPidCounter
370 , lpidUnique = vst ^. localPidUnique
394 , lpidUnique = vst ^. localPidUnique
@@ -387,7 +411,13 @@ forkProcess node proc =
387 , processThread = tid
411 , processThread = tid
388 , processNode = node
412 , processNode = node
414+ -- Rewrite this code when this is fixed:
415+ -- https://ghc.haskell.org/trac/ghc/ticket/10149
416+ let unmask = case ms of
418+ MaskedInterruptible -> block
419+ MaskedUninterruptible -> id
390− tid' <- uninterruptibleMask_ $ forkIOWithUnmask $ \unmask -> do
420+ tid' <- uninterruptibleMask_ $ forkIO $ do
391 reason <- Exception.catches
421 reason <- Exception.catches
392 (unmask $ runLocalProcess lproc proc >> return DiedNormal)
422 (unmask $ runLocalProcess lproc proc >> return DiedNormal)
393 [ (Exception.Handler (\ex@(ProcessExitException from msg) -> do
423 [ (Exception.Handler (\ex@(ProcessExitException from msg) -> do
@@ -433,7 +463,7 @@ forkProcess node proc =
436− startProcess LocalNodeClosed =
466+ startProcess _ LocalNodeClosed =
437 throwIO $ NodeClosedException $ localNodeId node
467 throwIO $ NodeClosedException $ localNodeId node
439 cleanupProcess :: ProcessId
469 cleanupProcess :: ProcessId
@@ -580,6 +610,8 @@ handleIncomingMessages node = go initConnectionState
580 , ctrlMsgSignal = Died nid DiedDisconnect
610 , ctrlMsgSignal = Died nid DiedDisconnect
582 let notLost k = not (k `Set.member` (st ^. incomingFrom theirAddr))
612 let notLost k = not (k `Set.member` (st ^. incomingFrom theirAddr))
613+ liftIO $ lookupWorker (localSendPool node) (NodeId theirAddr)
614+ >>= maybe (return ()) killThread
583 closeImplicitReconnections node nid
615 closeImplicitReconnections node nid
584 go ( (incomingFrom theirAddr ^= Set.empty)
616 go ( (incomingFrom theirAddr ^= Set.empty)
585 . (incoming ^: Map.filterWithKey (const . notLost))
617 . (incoming ^: Map.filterWithKey (const . notLost))
@@ -634,6 +666,12 @@ data NCState = NCState
634 , _registeredOnNodes :: !(Map ProcessId [(NodeId,Int)])
666 , _registeredOnNodes :: !(Map ProcessId [(NodeId,Int)])
669+submitSendPool :: LocalNode -> NodeId -> IO () -> IO ()
670+submitSendPool node nid task = submitTask (localSendPool node) fork nid task
673+ forkIO $ io `Exception.catch` \(NodeClosedException _) -> return ()
637newtype NC a = NC { unNC :: StateT NCState (ReaderT LocalNode IO) a }
675newtype NC a = NC { unNC :: StateT NCState (ReaderT LocalNode IO) a }
638 deriving ( Applicative
676 deriving ( Applicative
639 , Functor
677 , Functor
@@ -644,11 +682,12 @@ newtype NC a = NC { unNC :: StateT NCState (ReaderT LocalNode IO) a }
646initNCState :: NCState
684initNCState :: NCState
647−initNCState = NCState { _links = Map.empty
685+initNCState = NCState
686+ { _links = Map.empty
648− , _monitors = Map.empty
687+ , _monitors = Map.empty
649− , _registeredHere = Map.empty
688+ , _registeredHere = Map.empty
650− , _registeredOnNodes = Map.empty
689+ , _registeredOnNodes = Map.empty
653-- | Thrown in response to the user invoking 'kill' (see Primitives.hs). This
692-- | Thrown in response to the user invoking 'kill' (see Primitives.hs). This
654-- type is deliberately not exported so it cannot be caught explicitly.
693-- type is deliberately not exported so it cannot be caught explicitly.
@@ -666,7 +705,7 @@ ncSendToProcess pid msg = do
666 node <- ask
705 node <- ask
667 if processNodeId pid == localNodeId node
706 if processNodeId pid == localNodeId node
668 then ncEffectLocalSend node pid msg
707 then ncEffectLocalSend node pid msg
669− else liftIO $ sendBinary node
708+ else liftIO $ submitSendPool node (processNodeId pid) $ sendBinary node
670 (NodeIdentifier $ localNodeId node)
709 (NodeIdentifier $ localNodeId node)
671 (NodeIdentifier $ processNodeId pid)
710 (NodeIdentifier $ processNodeId pid)
672 WithImplicitReconnect
711 WithImplicitReconnect
@@ -679,7 +718,7 @@ ncSendToNode to msg = do
679 node <- ask
718 node <- ask
680 liftIO $ if to == localNodeId node
719 liftIO $ if to == localNodeId node
681 then writeChan (localCtrlChan node) $! msg
720 then writeChan (localCtrlChan node) $! msg
682− else sendBinary node
721+ else submitSendPool node to $ sendBinary node
683 (NodeIdentifier $ localNodeId node)
722 (NodeIdentifier $ localNodeId node)
684 (NodeIdentifier to)
723 (NodeIdentifier to)
685 WithImplicitReconnect
724 WithImplicitReconnect