-{-# OPTIONS -fno-implicit-prelude -#include "HsBase.h" #-}
+{-# OPTIONS_GHC -fno-implicit-prelude -#include "HsBase.h" #-}
#undef DEBUG_DUMP
--
-----------------------------------------------------------------------------
+-- #hide
module GHC.IO (
hWaitForInput, hGetChar, hGetLine, hGetContents, hPutChar, hPutStr,
commitBuffer', -- hack, see below
memcpy_baoff_ptr,
) where
-#include "config.h"
-
import Foreign
import Foreign.C
import GHC.List
import GHC.Exception ( ioError, catch )
+#ifdef mingw32_HOST_OS
+import GHC.Conc
+#endif
+
-- ---------------------------------------------------------------------------
-- Simple input operations
-- or 'False' if no input is available within @t@ milliseconds.
--
-- If @t@ is less than zero, then @hWaitForInput@ waits indefinitely.
--- NOTE: in the current implementation, this is the only case that works
--- correctly (if @t@ is non-zero, then all other concurrent threads are
--- blocked until data is available).
--
-- This operation may fail with:
--
-- * 'isEOFError' if the end of file has been reached.
+--
+-- NOTE for GHC users: unless you use the @-threaded@ flag,
+-- @hWaitForInput t@ where @t >= 0@ will block all other Haskell
+-- threads for the duration of the call. It behaves like a
+-- @safe@ foreign call in this respect.
hWaitForInput :: Handle -> Int -> IO Bool
hWaitForInput h msecs = do
(fromIntegral msecs) (haIsStream handle_)
return (r /= 0)
-foreign import ccall unsafe "inputReady"
+foreign import ccall safe "inputReady"
inputReady :: CInt -> CInt -> Bool -> IO CInt
-- ---------------------------------------------------------------------------
-- * 'isPermissionError' if another system resource limit would be exceeded.
hPutChar :: Handle -> Char -> IO ()
-hPutChar handle c =
- c `seq` do -- must evaluate c before grabbing the handle lock
+hPutChar handle c = do
+ c `seq` return ()
wantWritableHandle "hPutChar" handle $ \ handle_ -> do
let fd = haFD handle_
case haBufferMode handle_ of
LineBuffering -> hPutcBuffered handle_ True c
BlockBuffering _ -> hPutcBuffered handle_ False c
NoBuffering ->
- withObject (castCharToCChar c) $ \buf -> do
+ with (castCharToCChar c) $ \buf -> do
writeRawBufferPtr "hPutChar" (fromIntegral fd) (haIsStream handle_) buf 0 1
return ()
commitBuffer hdl raw sz@(I# _) count@(I# _) flush release = do
wantWritableHandle "commitAndReleaseBuffer" hdl $
- commitBuffer' hdl raw sz count flush release
+ commitBuffer' raw sz count flush release
-- Explicitly lambda-lift this function to subvert GHC's full laziness
-- optimisations, which otherwise tends to float out subexpressions
--
-- This hack is a fairly big win for hPutStr performance. --SDM 18/9/2001
--
-commitBuffer' hdl raw sz@(I# _) count@(I# _) flush release
+commitBuffer' raw sz@(I# _) count@(I# _) flush release
handle_@Handle__{ haFD=fd, haBuffer=ref, haBuffers=spare_buf_ref } = do
#ifdef DEBUG_DUMP
loop :: Int -> Int -> IO Int
loop off bytes | bytes <= 0 = return off
loop off bytes = do
-#ifndef mingw32_TARGET_OS
+#ifndef mingw32_HOST_OS
ssize <- c_write (fromIntegral fd) (ptr `plusPtr` off) (fromIntegral bytes)
let r = fromIntegral ssize :: Int
if (r == -1)
else do mb_buf <- maybeFillReadBuffer fd True is_stream buf
case mb_buf of
Nothing -> return so_far -- got nothing, we're done
- Just new_buf -> do
- writeIORef ref new_buf
- bufRead fd ref is_stream ptr so_far count
+ Just buf' -> do
+ writeIORef ref buf'
+ bufRead fd ref is_stream ptr so_far count
else do
let avail = w - r
if (count == avail)
return (so_far + count)
else do
+ memcpy_ptr_baoff ptr raw r (fromIntegral avail)
+ writeIORef ref buf{ bufWPtr=0, bufRPtr=0 }
let remaining = count - avail
so_far' = so_far + avail
ptr' = ptr `plusPtr` avail
return (so_far + count)
else do
+ memcpy_ptr_baoff ptr raw r (fromIntegral avail)
+ writeIORef ref buf{ bufWPtr=0, bufRPtr=0 }
let remaining = count - avail
so_far' = so_far + avail
ptr' = ptr `plusPtr` avail
readChunkNonBlocking :: FD -> Bool -> Ptr a -> Int -> IO Int
readChunkNonBlocking fd is_stream ptr bytes = do
-#ifndef mingw32_TARGET_OS
+#ifndef mingw32_HOST_OS
ssize <- c_read (fromIntegral fd) (castPtr ptr) (fromIntegral bytes)
let r = fromIntegral ssize :: Int
if (r == -1)
else throwErrno "readChunk"
else return r
#else
- (ssize, rc) <- asyncRead fd (fromIntegral $ fromEnum is_stream)
- (fromIntegral bytes) ptr
- let r = fromIntegral ssize :: Int
- if r == (-1)
- then ioError (errnoToIOError "hGetBufNonBlocking" (Errno (fromIntegral rc)) Nothing Nothing)
- else return r
+ fromIntegral `liftM`
+ readRawBufferPtr "readChunkNonBlocking" (fromIntegral fd) is_stream
+ (castPtr ptr) 0 (fromIntegral bytes)
+
+ -- we don't have non-blocking read support on Windows, so just invoke
+ -- the ordinary low-level read which will block until data is available,
+ -- but won't wait for the whole buffer to fill.
#endif
slurpFile :: FilePath -> IO (Ptr (), Int)