Skip to content

Commit 61b1de9

Browse files
committed
An API for inter-process communication via Handles
This commit adds the System.Process.CommunicationHandle module, which provides the cross-platform CommunicationHandle abstraction which allows Handles to be passed to child processes for inter-process communication. A high-level API is provided by the function `readCreateProcessWithExitCodeCommunicationHandle`, which can be consulted for further details about how the functionality is meant to be used. To test this functionality, we created a new "cli-child" executable component to the process-tests package. To work around Cabal bug #9854, it was necessary to change the build-type of the package to `Custom`, in order to make the "cli-child" executable visible when running the test-suite. The custom Setup.hs script contains more details about the problem.
1 parent 6751549 commit 61b1de9

13 files changed

+666
-63
lines changed

Setup.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
module Main (main) where
22

3+
-- Cabal
34
import Distribution.Simple
45
( defaultMainWithHooks
56
, autoconfUserHooks

System/Process.hs

Lines changed: 5 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -89,11 +89,11 @@ import System.Process.Internals
8989

9090
import Control.Concurrent
9191
import Control.DeepSeq (rnf)
92-
import Control.Exception (SomeException, mask
92+
import Control.Exception (
9393
#if !defined(javascript_HOST_ARCH)
94-
, allowInterrupt
94+
allowInterrupt,
9595
#endif
96-
, bracket, try, throwIO)
96+
bracket)
9797
import qualified Control.Exception as C
9898
import Control.Monad
9999
import Data.Maybe
@@ -111,7 +111,8 @@ import System.Win32.Process (getProcessId, getCurrentProcessId, ProcessId)
111111
import System.Posix.Process (getProcessID)
112112
import System.Posix.Types (CPid (..))
113113
#endif
114-
import GHC.IO.Exception ( ioException, IOErrorType(..), IOException(..) )
114+
115+
import GHC.IO.Exception ( ioException, IOErrorType(..) )
115116

116117
#if defined(wasm32_HOST_ARCH)
117118
import GHC.IO.Exception ( unsupportedOperation )
@@ -615,28 +616,6 @@ readCreateProcessWithExitCode cp input = do
615616
(_,Nothing,_) -> error "readCreateProcessWithExitCode: Failed to get a stdout handle."
616617
(_,_,Nothing) -> error "readCreateProcessWithExitCode: Failed to get a stderr handle."
617618

618-
-- | Fork a thread while doing something else, but kill it if there's an
619-
-- exception.
620-
--
621-
-- This is important in the cases above because we want to kill the thread
622-
-- that is holding the Handle lock, because when we clean up the process we
623-
-- try to close that handle, which could otherwise deadlock.
624-
--
625-
withForkWait :: IO () -> (IO () -> IO a) -> IO a
626-
withForkWait async body = do
627-
waitVar <- newEmptyMVar :: IO (MVar (Either SomeException ()))
628-
mask $ \restore -> do
629-
tid <- forkIO $ try (restore async) >>= putMVar waitVar
630-
let wait = takeMVar waitVar >>= either throwIO return
631-
restore (body wait) `C.onException` killThread tid
632-
633-
ignoreSigPipe :: IO () -> IO ()
634-
ignoreSigPipe = C.handle $ \e -> case e of
635-
IOError { ioe_type = ResourceVanished
636-
, ioe_errno = Just ioe }
637-
| Errno ioe == ePIPE -> return ()
638-
_ -> throwIO e
639-
640619
-- ----------------------------------------------------------------------------
641620
-- showCommandForUser
642621

System/Process/Common.hs

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ module System.Process.Common
1919
, mbFd
2020
, mbPipe
2121
, pfdToHandle
22+
, rawFdToHandle
2223

2324
-- Avoid a warning on Windows
2425
#if defined(mingw32_HOST_OS)
@@ -32,14 +33,15 @@ module System.Process.Common
3233
, HANDLE
3334
, mbHANDLE
3435
, mbPipeHANDLE
36+
, rawHANDLEToHandle
3537
#endif
3638
) where
3739

3840
import Control.Concurrent
3941
import Control.Exception
40-
import Data.String
42+
import Data.String ( IsString(..) )
4143
import Foreign.Ptr
42-
import Foreign.Storable
44+
import Foreign.Storable ( Storable(peek) )
4345

4446
import System.Posix.Internals
4547
import GHC.IO.Exception
@@ -270,8 +272,11 @@ mbPipe CreatePipe pfd mode = fmap Just (pfdToHandle pfd mode)
270272
mbPipe _std _pfd _mode = return Nothing
271273

272274
pfdToHandle :: Ptr FD -> IOMode -> IO Handle
273-
pfdToHandle pfd mode = do
274-
fd <- peek pfd
275+
pfdToHandle pfd mode =
276+
rawFdToHandle mode =<< peek pfd
277+
278+
rawFdToHandle :: IOMode -> FD -> IO Handle
279+
rawFdToHandle mode fd = do
275280
let filepath = "fd:" ++ show fd
276281
(fD,fd_type) <- FD.mkFD (fromIntegral fd) mode
277282
(Just (Stream,0,0)) -- avoid calling fstat()
@@ -299,11 +304,14 @@ mbHANDLE _std NoStream = return $ intPtrToPtr (-2)
299304
mbHANDLE _std (UseHandle hdl) = handleToHANDLE hdl
300305

301306
mbPipeHANDLE :: StdStream -> Ptr HANDLE -> IOMode -> IO (Maybe Handle)
302-
mbPipeHANDLE CreatePipe pfd mode =
303-
do raw_handle <- peek pfd
304-
let hwnd = fromHANDLE raw_handle :: Io NativeHandle
305-
ident = "hwnd:" ++ show raw_handle
306-
enc <- fmap Just getLocaleEncoding
307-
Just <$> mkHandleFromHANDLE hwnd Stream ident mode enc
307+
mbPipeHANDLE CreatePipe pfd mode =
308+
Just <$> ( rawHANDLEToHandle mode =<< peek pfd )
308309
mbPipeHANDLE _std _pfd _mode = return Nothing
310+
311+
rawHANDLEToHandle :: IOMode -> HANDLE -> IO Handle
312+
rawHANDLEToHandle mode raw_handle = do
313+
let hwnd = fromHANDLE raw_handle :: Io NativeHandle
314+
ident = "hwnd:" ++ show raw_handle
315+
enc <- getLocaleEncoding
316+
mkHandleFromHANDLE hwnd Stream ident mode (Just enc)
309317
#endif

0 commit comments

Comments
 (0)