REQ: add a non-closing version of handleToFd

Hello The function to extract a file descriptor from a handle, handleToFd, closes the handle as a side effect. This appears to be necessary in the general case, otherwise the implementers wouldn't have made it this way. But there are cases in which it isn't necessary to close the handle. For instance, this little function needs to extract the file descriptor, but there is no need to close, or change, the handle. isatty :: Handle -- ^ Handle to check -> IO Bool -- ^ Whether the handle is connected to a terminal isatty h = do fd <- handleToFd_noclose h isterm <- {# call isatty as hssh_c_isatty #} -- this is c2hs ((fromIntegral fd) :: CInt) return (isterm /= (0::CInt)) handleToFd_noclose :: Handle -> IO Fd -- to be implemented The isatty above can't be implemented with things the way they are. To me, this is a serious drawback. The cases, in which the handle needs to be closed, should be identified, and documented. Then, a version of handleToFd, which doesn't close the handle can be implemented. Cheers Volker

On 01/10/2011 12:31, Volker Wysk wrote:
Hello
The function to extract a file descriptor from a handle, handleToFd, closes the handle as a side effect. This appears to be necessary in the general case, otherwise the implementers wouldn't have made it this way.
But there are cases in which it isn't necessary to close the handle.
For instance, this little function needs to extract the file descriptor, but there is no need to close, or change, the handle.
isatty :: Handle -- ^ Handle to check -> IO Bool -- ^ Whether the handle is connected to a terminal isatty h = do fd<- handleToFd_noclose h isterm<- {# call isatty as hssh_c_isatty #} -- this is c2hs ((fromIntegral fd) :: CInt) return (isterm /= (0::CInt))
handleToFd_noclose :: Handle -> IO Fd -- to be implemented
The isatty above can't be implemented with things the way they are. To me, this is a serious drawback.
The cases, in which the handle needs to be closed, should be identified, and documented. Then, a version of handleToFd, which doesn't close the handle can be implemented.
There's another danger. A Handle has an associated finalizer that closes the file descriptor when the Handle is no longer needed by the program, so you can't make a handleToFd_noClose because the Handle might be closed anyway. What you can do is make a withHandleFD: withHandleFD :: Handle -> (FD -> IO a) -> IO a it's still quite dodgy, depending on what you do with the FD. Perhaps it should be called unsafeWithHandleFD. Anyway, patches gratefully accepted... Cheers, Simon

* Simon Marlow:
There's another danger. A Handle has an associated finalizer that closes the file descriptor when the Handle is no longer needed by the program, so you can't make a handleToFd_noClose because the Handle might be closed anyway.
Could you keep a reference to the Handle associated with the FD? Or can the auto-closing be moved to the FD, and the Handle could keep just a reference to it?
What you can do is make a withHandleFD:
withHandleFD :: Handle -> (FD -> IO a) -> IO a
it's still quite dodgy, depending on what you do with the FD. Perhaps it should be called unsafeWithHandleFD.
And you can't really fix that with monadic regions, either. Handles (whether called Handle or FD) are the more fundamental abstraction in the sense that it's more efficient to go from handles to other abstractions rather than back.

On 6 October 2011 14:58, Simon Marlow
... What you can do is make a withHandleFD:
withHandleFD :: Handle -> (FD -> IO a) -> IO a
it's still quite dodgy, depending on what you do with the FD. Perhaps it should be called unsafeWithHandleFD.
Anyway, patches gratefully accepted...
Maybe something like this together with a big warning message explaining the danger: {-# LANGUAGE NamedFieldPuns #-} module System.Posix.IO where import Control.Concurrent.MVar (MVar) unsafeWithHandleFd :: Handle -> (Fd -> IO a) -> IO a unsafeWithHandleFd h@(FileHandle _ m) f = unsafeWithHandleFd' h m f unsafeWithHandleFd h@(DuplexHandle _ _ w) f = unsafeWithHandleFd' h w f unsafeWithHandleFd' :: Handle -> MVar Handle__ -> (Fd -> IO a) -> IO a unsafeWithHandleFd' h m f = withHandle' "unsafeWithHandleFd" h m $ \h_@Handle__{haDevice} -> case cast haDevice of Nothing -> ioError (ioeSetErrorString (mkIOError IllegalOperation "unsafeWithHandleFd" (Just h) Nothing) "handle is not a file descriptor") Just fd -> do x <- f (Fd (FD.fdFD fd)) return (h_, x) I'm not sure about the DuplexHandle case. I mimicked handleToFd by only converting the write side but I have no idea why that is correct. Bas
participants (4)
-
Bas van Dijk
-
Florian Weimer
-
Simon Marlow
-
Volker Wysk