1 {-# OPTIONS_GHC -XNoImplicitPrelude -XBangPatterns #-}
2 {-# OPTIONS_HADDOCK hide #-}
3 -----------------------------------------------------------------------------
6 -- Copyright : (c) The University of Glasgow, 1994-2008
7 -- License : see libraries/base/LICENSE
9 -- Maintainer : libraries@haskell.org
10 -- Stability : internal
11 -- Portability : non-portable
13 -- Raw read/write operations on file descriptors
15 -----------------------------------------------------------------------------
19 openFile, mkFD, release,
21 readRawBufferPtr, readRawBufferPtrNoBlock, writeRawBufferPtr,
39 import GHC.IO.BufferedIO
40 import qualified GHC.IO.Device
41 import GHC.IO.Device (SeekMode(..), IODeviceType(..))
43 import GHC.IO.Exception
47 import qualified System.Posix.Internals
48 import System.Posix.Internals hiding (FD, setEcho, getEcho)
49 import System.Posix.Types
52 -- -----------------------------------------------------------------------------
53 -- The file-descriptor IO device
56 fdFD :: {-# UNPACK #-} !CInt,
57 #ifdef mingw32_HOST_OS
58 -- On Windows, a socket file descriptor needs to be read and written
59 -- using different functions (send/recv).
60 fdIsSocket_ :: {-# UNPACK #-} !Int
62 -- On Unix we need to know whether this FD has O_NONBLOCK set.
63 -- If it has, then we can use more efficient routines to read/write to it.
64 -- It is always safe for this to be off.
65 fdIsNonBlocking :: {-# UNPACK #-} !Int
70 #ifdef mingw32_HOST_OS
71 fdIsSocket :: FD -> Bool
72 fdIsSocket fd = fdIsSocket_ fd /= 0
75 instance Show FD where
76 show fd = show (fdFD fd)
78 instance GHC.IO.Device.RawIO FD where
80 readNonBlocking = fdReadNonBlocking
82 writeNonBlocking = fdWriteNonBlocking
84 instance GHC.IO.Device.IODevice FD where
87 isTerminal = isTerminal
88 isSeekable = isSeekable
100 instance BufferedIO FD where
101 newBuffer _dev state = newByteBuffer dEFAULT_BUFFER_SIZE state
102 fillReadBuffer fd buf = readBuf' fd buf
103 fillReadBuffer0 fd buf = readBufNonBlocking fd buf
104 flushWriteBuffer fd buf = writeBuf' fd buf
105 flushWriteBuffer0 fd buf = writeBufNonBlocking fd buf
107 readBuf' :: FD -> Buffer Word8 -> IO (Int, Buffer Word8)
110 puts ("readBuf fd=" ++ show fd ++ " " ++ summaryBuffer buf ++ "\n")
112 (r,buf') <- readBuf fd buf
114 puts ("after: " ++ summaryBuffer buf' ++ "\n")
118 writeBuf' :: FD -> Buffer Word8 -> IO ()
119 writeBuf' fd buf = do
121 puts ("writeBuf fd=" ++ show fd ++ " " ++ summaryBuffer buf ++ "\n")
125 -- -----------------------------------------------------------------------------
128 -- | Open a file and make an 'FD' for it. Truncates the file to zero
129 -- size when the `IOMode` is `WriteMode`. Puts the file descriptor
130 -- into non-blocking mode on Unix systems.
131 openFile :: FilePath -> IOMode -> IO (FD,IODeviceType)
132 openFile filepath iomode =
133 withFilePath filepath $ \ f ->
136 oflags1 = case iomode of
137 ReadMode -> read_flags
138 #ifdef mingw32_HOST_OS
139 WriteMode -> write_flags .|. o_TRUNC
141 WriteMode -> write_flags
143 ReadWriteMode -> rw_flags
144 AppendMode -> append_flags
146 #ifdef mingw32_HOST_OS
147 binary_flags = o_BINARY
152 oflags = oflags1 .|. binary_flags
155 -- the old implementation had a complicated series of three opens,
156 -- which is perhaps because we have to be careful not to open
157 -- directories. However, the man pages I've read say that open()
158 -- always returns EISDIR if the file is a directory and was opened
159 -- for writing, so I think we're ok with a single open() here...
160 fd <- throwErrnoIfMinus1Retry "openFile"
161 (c_open f (fromIntegral oflags) 0o666)
163 (fD,fd_type) <- mkFD fd iomode Nothing{-no stat-}
164 False{-not a socket-}
165 True{-is non-blocking-}
166 `catchAny` \e -> do c_close fd; throwIO e
168 #ifndef mingw32_HOST_OS
169 -- we want to truncate() if this is an open in WriteMode, but only
170 -- if the target is a RegularFile. ftruncate() fails on special files
172 if iomode == WriteMode && fd_type == RegularFile
179 std_flags, output_flags, read_flags, write_flags, rw_flags,
181 std_flags = o_NONBLOCK .|. o_NOCTTY
182 output_flags = std_flags .|. o_CREAT
183 read_flags = std_flags .|. o_RDONLY
184 write_flags = output_flags .|. o_WRONLY
185 rw_flags = output_flags .|. o_RDWR
186 append_flags = write_flags .|. o_APPEND
189 -- | Make a 'FD' from an existing file descriptor. Fails if the FD
190 -- refers to a directory. If the FD refers to a file, `mkFD` locks
191 -- the file according to the Haskell 98 single writer/multiple reader
192 -- locking semantics (this is why we need the `IOMode` argument too).
195 -> Maybe (IODeviceType, CDev, CIno)
196 -- the results of fdStat if we already know them, or we want
197 -- to prevent fdToHandle_stat from doing its own stat.
198 -- These are used for:
199 -- - we fail if the FD refers to a directory
200 -- - if the FD refers to a file, we lock it using (cdev,cino)
201 -> Bool -- ^ is a socket (on Windows)
202 -> Bool -- ^ is in non-blocking mode on Unix
203 -> IO (FD,IODeviceType)
205 mkFD fd iomode mb_stat is_socket is_nonblock = do
207 let _ = (is_socket, is_nonblock) -- warning suppression
212 Just stat -> return stat
214 let write = case iomode of
218 #ifdef mingw32_HOST_OS
219 setmode fd True -- unconditionally set binary mode
220 let _ = (dev,ino,write) -- warning suppression
225 ioException (IOError Nothing InappropriateType "openFile"
226 "is a directory" Nothing Nothing)
228 #ifndef mingw32_HOST_OS
229 -- regular files need to be locked
231 -- On Windows we use explicit exclusion via sopen() to implement
232 -- this locking (see __hscore_open()); on Unix we have to
233 -- implment it in the RTS.
234 r <- lockFile fd dev ino (fromBool write)
236 ioException (IOError Nothing ResourceBusy "openFile"
237 "file is locked" Nothing Nothing)
240 _other_type -> return ()
242 return (FD{ fdFD = fd,
243 #ifndef mingw32_HOST_OS
244 fdIsNonBlocking = fromEnum is_nonblock
246 fdIsSocket_ = fromEnum is_socket
251 #ifdef mingw32_HOST_OS
252 foreign import ccall unsafe "__hscore_setmode"
253 setmode :: CInt -> Bool -> IO CInt
256 -- -----------------------------------------------------------------------------
257 -- Standard file descriptors
260 stdFD fd = FD { fdFD = fd,
261 #ifdef mingw32_HOST_OS
265 -- We don't set non-blocking mode on standard handles, because it may
266 -- confuse other applications attached to the same TTY/pipe
267 -- see Note [nonblock]
271 stdin, stdout, stderr :: FD
276 -- -----------------------------------------------------------------------------
277 -- Operations on file descriptors
281 #ifndef mingw32_HOST_OS
282 (flip finally) (release fd) $ do
284 throwErrnoIfMinus1Retry_ "GHC.IO.FD.close" $
285 #ifdef mingw32_HOST_OS
286 if fdIsSocket fd then
287 c_closesocket (fdFD fd)
292 release :: FD -> IO ()
294 #ifndef mingw32_HOST_OS
297 let _ = fd -- warning suppression
300 #ifdef mingw32_HOST_OS
301 foreign import stdcall unsafe "HsBase.h closesocket"
302 c_closesocket :: CInt -> IO CInt
305 isSeekable :: FD -> IO Bool
308 return (t == RegularFile || t == RawDevice)
310 seek :: FD -> SeekMode -> Integer -> IO ()
311 seek fd mode off = do
312 throwErrnoIfMinus1Retry "seek" $
313 c_lseek (fdFD fd) (fromIntegral off) seektype
317 seektype = case mode of
318 AbsoluteSeek -> sEEK_SET
319 RelativeSeek -> sEEK_CUR
320 SeekFromEnd -> sEEK_END
322 tell :: FD -> IO Integer
325 (throwErrnoIfMinus1Retry "hGetPosn" $
326 c_lseek (fdFD fd) 0 sEEK_CUR)
328 getSize :: FD -> IO Integer
329 getSize fd = fdFileSize (fdFD fd)
331 setSize :: FD -> Integer -> IO ()
333 throwErrnoIf (/=0) "GHC.IO.FD.setSize" $
334 c_ftruncate (fdFD fd) (fromIntegral size)
337 devType :: FD -> IO IODeviceType
338 devType fd = do (ty,_,_) <- fdStat (fdFD fd); return ty
342 newfd <- throwErrnoIfMinus1 "GHC.IO.FD.dup" $ c_dup (fdFD fd)
343 return fd{ fdFD = newfd }
345 dup2 :: FD -> FD -> IO FD
347 -- Windows' dup2 does not return the new descriptor, unlike Unix
348 throwErrnoIfMinus1 "GHC.IO.FD.dup2" $
349 c_dup2 (fdFD fd) (fdFD fdto)
350 return fd{ fdFD = fdFD fdto } -- original FD, with the new fdFD
352 setNonBlockingMode :: FD -> Bool -> IO FD
353 setNonBlockingMode fd set = do
354 setNonBlockingFD (fdFD fd) set
355 #if defined(mingw32_HOST_OS)
358 return fd{ fdIsNonBlocking = fromEnum set }
361 ready :: FD -> Bool -> Int -> IO Bool
362 ready fd write msecs = do
363 r <- throwErrnoIfMinus1Retry "GHC.IO.FD.ready" $
364 fdReady (fdFD fd) (fromIntegral $ fromEnum $ write)
366 #if defined(mingw32_HOST_OS)
367 (fromIntegral $ fromEnum $ fdIsSocket fd)
371 return (toEnum (fromIntegral r))
373 foreign import ccall safe "fdReady"
374 fdReady :: CInt -> CInt -> CInt -> CInt -> IO CInt
376 -- ---------------------------------------------------------------------------
377 -- Terminal-related stuff
379 isTerminal :: FD -> IO Bool
380 isTerminal fd = c_isatty (fdFD fd) >>= return.toBool
382 setEcho :: FD -> Bool -> IO ()
383 setEcho fd on = System.Posix.Internals.setEcho (fdFD fd) on
385 getEcho :: FD -> IO Bool
386 getEcho fd = System.Posix.Internals.getEcho (fdFD fd)
388 setRaw :: FD -> Bool -> IO ()
389 setRaw fd raw = System.Posix.Internals.setCooked (fdFD fd) (not raw)
391 -- -----------------------------------------------------------------------------
392 -- Reading and Writing
394 fdRead :: FD -> Ptr Word8 -> Int -> IO Int
395 fdRead fd ptr bytes = do
396 r <- readRawBufferPtr "GHC.IO.FD.fdRead" fd ptr 0 (fromIntegral bytes)
397 return (fromIntegral r)
399 fdReadNonBlocking :: FD -> Ptr Word8 -> Int -> IO (Maybe Int)
400 fdReadNonBlocking fd ptr bytes = do
401 r <- readRawBufferPtrNoBlock "GHC.IO.FD.fdReadNonBlocking" fd ptr
402 0 (fromIntegral bytes)
404 (-1) -> return (Nothing)
405 n -> return (Just (fromIntegral n))
408 fdWrite :: FD -> Ptr Word8 -> Int -> IO ()
409 fdWrite fd ptr bytes = do
410 res <- writeRawBufferPtr "GHC.IO.FD.fdWrite" fd ptr 0 (fromIntegral bytes)
411 let res' = fromIntegral res
413 then fdWrite fd (ptr `plusPtr` res') (bytes - res')
416 -- XXX ToDo: this isn't non-blocking
417 fdWriteNonBlocking :: FD -> Ptr Word8 -> Int -> IO Int
418 fdWriteNonBlocking fd ptr bytes = do
419 res <- writeRawBufferPtrNoBlock "GHC.IO.FD.fdWriteNonBlocking" fd ptr 0
421 return (fromIntegral res)
423 -- -----------------------------------------------------------------------------
426 -- Low level routines for reading/writing to (raw)buffers:
428 #ifndef mingw32_HOST_OS
433 Unix has broken semantics when it comes to non-blocking I/O: you can
434 set the O_NONBLOCK flag on an FD, but it applies to the all other FDs
435 attached to the same underlying file, pipe or TTY; there's no way to
436 have private non-blocking behaviour for an FD. See bug #724.
438 We fix this by only setting O_NONBLOCK on FDs that we create; FDs that
439 come from external sources or are exposed externally are left in
440 blocking mode. This solution has some problems though. We can't
441 completely simulate a non-blocking read without O_NONBLOCK: several
442 cases are wrong here. The cases that are wrong:
444 * reading/writing to a blocking FD in non-threaded mode.
445 In threaded mode, we just make a safe call to read().
446 In non-threaded mode we call select() before attempting to read,
447 but that leaves a small race window where the data can be read
448 from the file descriptor before we issue our blocking read().
449 * readRawBufferNoBlock for a blocking FD
453 In the threaded RTS we could just make safe calls to read()/write()
454 for file descriptors in blocking mode without worrying about blocking
455 other threads, but the problem with this is that the thread will be
456 uninterruptible while it is blocked in the foreign call. See #2363.
457 So now we always call fdReady() before reading, and if fdReady
458 indicates that there's no data, we call threadWaitRead.
462 readRawBufferPtr :: String -> FD -> Ptr Word8 -> Int -> CSize -> IO Int
463 readRawBufferPtr loc !fd buf off len
464 | isNonBlocking fd = unsafe_read -- unsafe is ok, it can't block
465 | otherwise = do r <- throwErrnoIfMinus1 loc
466 (unsafe_fdReady (fdFD fd) 0 0 0)
469 else do threadWaitRead (fromIntegral (fdFD fd)); read
471 do_read call = fromIntegral `fmap`
472 throwErrnoIfMinus1RetryMayBlock loc call
473 (threadWaitRead (fromIntegral (fdFD fd)))
474 read = if threaded then safe_read else unsafe_read
475 unsafe_read = do_read (c_read (fdFD fd) (buf `plusPtr` off) len)
476 safe_read = do_read (c_safe_read (fdFD fd) (buf `plusPtr` off) len)
478 -- return: -1 indicates EOF, >=0 is bytes read
479 readRawBufferPtrNoBlock :: String -> FD -> Ptr Word8 -> Int -> CSize -> IO Int
480 readRawBufferPtrNoBlock loc !fd buf off len
481 | isNonBlocking fd = unsafe_read -- unsafe is ok, it can't block
482 | otherwise = do r <- unsafe_fdReady (fdFD fd) 0 0 0
483 if r /= 0 then safe_read
485 -- XXX see note [nonblock]
487 do_read call = do r <- throwErrnoIfMinus1RetryOnBlock loc call (return (-1))
491 n -> return (fromIntegral n)
492 unsafe_read = do_read (c_read (fdFD fd) (buf `plusPtr` off) len)
493 safe_read = do_read (c_safe_read (fdFD fd) (buf `plusPtr` off) len)
495 writeRawBufferPtr :: String -> FD -> Ptr Word8 -> Int -> CSize -> IO CInt
496 writeRawBufferPtr loc !fd buf off len
497 | isNonBlocking fd = unsafe_write -- unsafe is ok, it can't block
498 | otherwise = do r <- unsafe_fdReady (fdFD fd) 1 0 0
501 else do threadWaitWrite (fromIntegral (fdFD fd)); write
503 do_write call = fromIntegral `fmap`
504 throwErrnoIfMinus1RetryMayBlock loc call
505 (threadWaitWrite (fromIntegral (fdFD fd)))
506 write = if threaded then safe_write else unsafe_write
507 unsafe_write = do_write (c_write (fdFD fd) (buf `plusPtr` off) len)
508 safe_write = do_write (c_safe_write (fdFD fd) (buf `plusPtr` off) len)
510 writeRawBufferPtrNoBlock :: String -> FD -> Ptr Word8 -> Int -> CSize -> IO CInt
511 writeRawBufferPtrNoBlock loc !fd buf off len
512 | isNonBlocking fd = unsafe_write -- unsafe is ok, it can't block
513 | otherwise = do r <- unsafe_fdReady (fdFD fd) 1 0 0
517 do_write call = do r <- throwErrnoIfMinus1RetryOnBlock loc call (return (-1))
520 n -> return (fromIntegral n)
521 write = if threaded then safe_write else unsafe_write
522 unsafe_write = do_write (c_write (fdFD fd) (buf `plusPtr` off) len)
523 safe_write = do_write (c_safe_write (fdFD fd) (buf `plusPtr` off) len)
525 isNonBlocking :: FD -> Bool
526 isNonBlocking fd = fdIsNonBlocking fd /= 0
528 foreign import ccall unsafe "fdReady"
529 unsafe_fdReady :: CInt -> CInt -> CInt -> CInt -> IO CInt
531 #else /* mingw32_HOST_OS.... */
533 readRawBufferPtr :: String -> FD -> Ptr Word8 -> Int -> CSize -> IO CInt
534 readRawBufferPtr loc !fd buf off len
535 | threaded = blockingReadRawBufferPtr loc fd buf off len
536 | otherwise = asyncReadRawBufferPtr loc fd buf off len
538 writeRawBufferPtr :: String -> FD -> Ptr Word8 -> Int -> CSize -> IO CInt
539 writeRawBufferPtr loc !fd buf off len
540 | threaded = blockingWriteRawBufferPtr loc fd buf off len
541 | otherwise = asyncWriteRawBufferPtr loc fd buf off len
543 readRawBufferPtrNoBlock :: String -> FD -> Ptr Word8 -> Int -> CSize -> IO CInt
544 readRawBufferPtrNoBlock = readRawBufferPtr
546 writeRawBufferPtrNoBlock :: String -> FD -> Ptr Word8 -> Int -> CSize -> IO CInt
547 writeRawBufferPtrNoBlock = writeRawBufferPtr
549 -- Async versions of the read/write primitives, for the non-threaded RTS
551 asyncReadRawBufferPtr :: String -> FD -> Ptr Word8 -> Int -> CSize -> IO CInt
552 asyncReadRawBufferPtr loc !fd buf off len = do
553 (l, rc) <- asyncRead (fromIntegral (fdFD fd)) (fdIsSocket_ fd)
554 (fromIntegral len) (buf `plusPtr` off)
557 ioError (errnoToIOError loc (Errno (fromIntegral rc)) Nothing Nothing)
558 else return (fromIntegral l)
560 asyncWriteRawBufferPtr :: String -> FD -> Ptr Word8 -> Int -> CSize -> IO CInt
561 asyncWriteRawBufferPtr loc !fd buf off len = do
562 (l, rc) <- asyncWrite (fromIntegral (fdFD fd)) (fdIsSocket_ fd)
563 (fromIntegral len) (buf `plusPtr` off)
566 ioError (errnoToIOError loc (Errno (fromIntegral rc)) Nothing Nothing)
567 else return (fromIntegral l)
569 -- Blocking versions of the read/write primitives, for the threaded RTS
571 blockingReadRawBufferPtr :: String -> FD -> Ptr Word8 -> Int -> CSize -> IO CInt
572 blockingReadRawBufferPtr loc fd buf off len
573 = fmap fromIntegral $ throwErrnoIfMinus1Retry loc $
575 then c_safe_recv (fdFD fd) (buf `plusPtr` off) len 0
576 else c_safe_read (fdFD fd) (buf `plusPtr` off) len
578 blockingWriteRawBufferPtr :: String -> FD -> Ptr Word8-> Int -> CSize -> IO CInt
579 blockingWriteRawBufferPtr loc fd buf off len
580 = fmap fromIntegral $ throwErrnoIfMinus1Retry loc $
582 then c_safe_send (fdFD fd) (buf `plusPtr` off) len 0
583 else c_safe_write (fdFD fd) (buf `plusPtr` off) len
585 -- NOTE: "safe" versions of the read/write calls for use by the threaded RTS.
586 -- These calls may block, but that's ok.
588 foreign import stdcall safe "recv"
589 c_safe_recv :: CInt -> Ptr Word8 -> CSize -> CInt{-flags-} -> IO CSsize
591 foreign import stdcall safe "send"
592 c_safe_send :: CInt -> Ptr Word8 -> CSize -> CInt{-flags-} -> IO CSsize
596 foreign import ccall "rtsSupportsBoundThreads" threaded :: Bool
598 -- -----------------------------------------------------------------------------
601 #ifndef mingw32_HOST_OS
602 throwErrnoIfMinus1RetryOnBlock :: String -> IO CSsize -> IO CSsize -> IO CSsize
603 throwErrnoIfMinus1RetryOnBlock loc f on_block =
606 if (res :: CSsize) == -1
610 then throwErrnoIfMinus1RetryOnBlock loc f on_block
611 else if err == eWOULDBLOCK || err == eAGAIN
617 -- -----------------------------------------------------------------------------
620 #ifndef mingw32_HOST_OS
621 foreign import ccall unsafe "lockFile"
622 lockFile :: CInt -> CDev -> CIno -> CInt -> IO CInt
624 foreign import ccall unsafe "unlockFile"
625 unlockFile :: CInt -> IO CInt
628 #if defined(DEBUG_DUMP)
629 puts :: String -> IO ()
630 puts s = do withCStringLen s $ \(p,len) -> c_write 1 p (fromIntegral len)