{-# LINE 1 "libraries\\process\\System\\Process\\CommunicationHandle\\Internal.hsc" #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE RankNTypes #-}
module System.Process.CommunicationHandle.Internal
(
CommunicationHandle(..)
, closeCommunicationHandle
, useCommunicationHandle
, createCommunicationPipe
)
where
import Control.Arrow ( first )
import GHC.IO.Handle (Handle, hClose)
{-# LINE 18 "libraries\\process\\System\\Process\\CommunicationHandle\\Internal.hsc" #-}
import Foreign.C (CInt(..), throwErrnoIf_)
import Foreign.Marshal (alloca)
import Foreign.Ptr (ptrToWordPtr, wordPtrToPtr)
import Foreign.Storable (Storable(peek))
import GHC.IO.Handle.FD (fdToHandle)
import GHC.IO.IOMode (IOMode(ReadMode, WriteMode))
import System.Process.Windows (HANDLE, mkNamedPipe)
# if defined(__IO_MANAGER_WINIO__)
import Control.Exception (catch, throwIO)
import GHC.IO (onException)
import GHC.IO.Device as IODevice (close, devType)
import GHC.IO.Encoding (getLocaleEncoding)
import GHC.IO.Exception (IOException(..), IOErrorType(InvalidArgument))
import GHC.IO.IOMode (IOMode(ReadWriteMode))
import GHC.IO.Handle.Windows (mkHandleFromHANDLE)
import GHC.IO.SubSystem ((<!>))
import GHC.IO.Windows.Handle (Io, NativeHandle, fromHANDLE)
import GHC.Event.Windows (associateHandle')
import System.Process.Common (rawHANDLEToHandle)
# else
import System.Process.Common (rawFdToHandle)
# endif
{-# LINE 68 "libraries\\process\\System\\Process\\CommunicationHandle\\Internal.hsc" #-}
newtype CommunicationHandle =
CommunicationHandle
#if defined(mingw32_HOST_OS)
HANDLE
#else
Fd
#endif
deriving ( Eq, Ord )
{-# LINE 106 "libraries\\process\\System\\Process\\CommunicationHandle\\Internal.hsc" #-}
type Fd = CInt
{-# LINE 108 "libraries\\process\\System\\Process\\CommunicationHandle\\Internal.hsc" #-}
instance Show CommunicationHandle where
showsPrec p (CommunicationHandle h) =
showsPrec p
#if defined(mingw32_HOST_OS)
$ ptrToWordPtr
#endif
h
instance Read CommunicationHandle where
readsPrec p str =
fmap
( first $ CommunicationHandle
#if defined(mingw32_HOST_OS)
. wordPtrToPtr
#endif
) $
readsPrec p str
useCommunicationHandle :: Bool -> CommunicationHandle -> IO Handle
useCommunicationHandle _wantToRead (CommunicationHandle ch) = do
#if defined(__IO_MANAGER_WINIO__)
return ()
<!> associateHandleWithFallback _wantToRead ch
#endif
getGhcHandle ch
closeCommunicationHandle :: CommunicationHandle -> IO ()
closeCommunicationHandle (CommunicationHandle ch) =
hClose =<< getGhcHandle ch
#if defined(__IO_MANAGER_WINIO__)
associateHandleWithFallback :: Bool -> HANDLE -> IO ()
associateHandleWithFallback _wantToRead h =
associateHandle' h `catch` handler
where
handler :: IOError -> IO ()
handler ioErr@(IOError { ioe_handle = _mbErrHandle, ioe_type = errTy, ioe_errno = mbErrNo })
| InvalidArgument <- errTy
, Just 22 <- mbErrNo
= return ()
| otherwise
= throwIO ioErr
#endif
{-# LINE 183 "libraries\\process\\System\\Process\\CommunicationHandle\\Internal.hsc" #-}
getGhcHandle :: HANDLE -> IO Handle
getGhcHandle =
getGhcHandlePOSIX
# if defined(__IO_MANAGER_WINIO__)
<!> getGhcHandleNative
# endif
getGhcHandlePOSIX :: HANDLE -> IO Handle
getGhcHandlePOSIX handle = openHANDLE handle >>= fdToHandle
openHANDLE :: HANDLE -> IO Fd
openHANDLE handle = _open_osfhandle handle (32768)
{-# LINE 195 "libraries\\process\\System\\Process\\CommunicationHandle\\Internal.hsc" #-}
foreign import ccall "io.h _open_osfhandle"
_open_osfhandle :: HANDLE -> CInt -> IO Fd
# if defined(__IO_MANAGER_WINIO__)
getGhcHandleNative :: HANDLE -> IO Handle
getGhcHandleNative hwnd =
do mb_codec <- fmap Just getLocaleEncoding
let iomode = ReadWriteMode
native_handle = fromHANDLE hwnd :: Io NativeHandle
hw_type <- IODevice.devType $ native_handle
mkHandleFromHANDLE native_handle hw_type (show hwnd) iomode mb_codec
`onException` IODevice.close native_handle
# endif
{-# LINE 232 "libraries\\process\\System\\Process\\CommunicationHandle\\Internal.hsc" #-}
createCommunicationPipe
:: ( forall a. (a, a) -> (a, a) )
-> Bool
-> IO (Handle, CommunicationHandle)
createCommunicationPipe swapIfTheyReadWeWrite _passAsyncHandleToChild = do
#if !defined(mingw32_HOST_OS)
(ourFd, theirFd) <- swapIfTheyReadWeWrite <$> createPipeFd
setFdOption (Fd ourFd) CloseOnExec True
ourHandle <- getGhcHandle (Fd ourFd)
return (ourHandle, CommunicationHandle $ Fd theirFd)
#else
trueForWinIO <-
return False
# if defined (__IO_MANAGER_WINIO__)
<!> return True
# endif
alloca $ \ pfdStdInput ->
alloca $ \ pfdStdOutput -> do
let (inheritRead, inheritWrite) = swapIfTheyReadWeWrite (False, True)
overlappedRead = trueForWinIO && ( _passAsyncHandleToChild || not inheritRead )
overlappedWrite = trueForWinIO && ( _passAsyncHandleToChild || not inheritWrite )
throwErrnoIf_ (==False) "mkNamedPipe" $
mkNamedPipe
pfdStdInput inheritRead overlappedRead
pfdStdOutput inheritWrite overlappedWrite
let ((ourPtr, ourMode), (theirPtr, _theirMode)) =
swapIfTheyReadWeWrite ((pfdStdInput, ReadMode), (pfdStdOutput, WriteMode))
ourHANDLE <- peek ourPtr
theirHANDLE <- peek theirPtr
return ()
# if defined (__IO_MANAGER_WINIO__)
<!> associateHandle' ourHANDLE
# endif
ourHandle <-
# if !defined (__IO_MANAGER_WINIO__)
( \ fd -> rawFdToHandle fd ourMode ) =<< openHANDLE ourHANDLE
# else
rawHANDLEToHandle ourHANDLE ourMode
# endif
return $ (ourHandle, CommunicationHandle theirHANDLE)
#endif