+
+fillReadBufferWithoutBlocking :: FD -> Bool -> Buffer -> IO Buffer
+fillReadBufferWithoutBlocking fd is_stream
+ buf@Buffer{ bufBuf=b, bufRPtr=r, bufWPtr=w, bufSize=size } =
+ -- buffer better be empty:
+ assert (r == 0 && w == 0) $ do
+#ifdef DEBUG_DUMP
+ puts ("fillReadBufferLoopNoBlock: bytes = " ++ show size ++ "\n")
+#endif
+ res <- readRawBufferNoBlock "fillReadBuffer" fd is_stream b
+ 0 (fromIntegral size)
+ let res' = fromIntegral res
+#ifdef DEBUG_DUMP
+ puts ("fillReadBufferLoopNoBlock: res' = " ++ show res' ++ "\n")
+#endif
+ return buf{ bufRPtr=0, bufWPtr=res' }
+
+-- Low level routines for reading/writing to (raw)buffers:
+
+#ifndef mingw32_HOST_OS
+
+{-
+NOTE [nonblock]:
+
+Unix has broken semantics when it comes to non-blocking I/O: you can
+set the O_NONBLOCK flag on an FD, but it applies to the all other FDs
+attached to the same underlying file, pipe or TTY; there's no way to
+have private non-blocking behaviour for an FD. See bug #724.
+
+We fix this by only setting O_NONBLOCK on FDs that we create; FDs that
+come from external sources or are exposed externally are left in
+blocking mode. This solution has some problems though. We can't
+completely simulate a non-blocking read without O_NONBLOCK: several
+cases are wrong here. The cases that are wrong:
+
+ * reading/writing to a blocking FD in non-threaded mode.
+ In threaded mode, we just make a safe call to read().
+ In non-threaded mode we call select() before attempting to read,
+ but that leaves a small race window where the data can be read
+ from the file descriptor before we issue our blocking read().
+ * readRawBufferNoBlock for a blocking FD
+
+NOTE [2363]:
+
+In the threaded RTS we could just make safe calls to read()/write()
+for file descriptors in blocking mode without worrying about blocking
+other threads, but the problem with this is that the thread will be
+uninterruptible while it is blocked in the foreign call. See #2363.
+So now we always call fdReady() before reading, and if fdReady
+indicates that there's no data, we call threadWaitRead.
+
+-}
+
+readRawBuffer :: String -> FD -> Bool -> RawBuffer -> Int -> CInt -> IO CInt
+readRawBuffer loc fd is_nonblock buf off len
+ | is_nonblock = unsafe_read -- unsafe is ok, it can't block
+ | otherwise = do r <- throwErrnoIfMinus1 loc
+ (unsafe_fdReady (fromIntegral fd) 0 0 0)
+ if r /= 0
+ then read
+ else do threadWaitRead (fromIntegral fd); read
+ where
+ do_read call = throwErrnoIfMinus1RetryMayBlock loc call
+ (threadWaitRead (fromIntegral fd))
+ read = if threaded then safe_read else unsafe_read
+ unsafe_read = do_read (read_rawBuffer fd buf off len)
+ safe_read = do_read (safe_read_rawBuffer fd buf off len)
+
+readRawBufferPtr :: String -> FD -> Bool -> Ptr CChar -> Int -> CInt -> IO CInt
+readRawBufferPtr loc fd is_nonblock buf off len
+ | is_nonblock = unsafe_read -- unsafe is ok, it can't block
+ | otherwise = do r <- throwErrnoIfMinus1 loc
+ (unsafe_fdReady (fromIntegral fd) 0 0 0)
+ if r /= 0
+ then read
+ else do threadWaitRead (fromIntegral fd); read
+ where
+ do_read call = throwErrnoIfMinus1RetryMayBlock loc call
+ (threadWaitRead (fromIntegral fd))
+ read = if threaded then safe_read else unsafe_read
+ unsafe_read = do_read (read_off fd buf off len)
+ safe_read = do_read (safe_read_off fd buf off len)
+
+readRawBufferNoBlock :: String -> FD -> Bool -> RawBuffer -> Int -> CInt -> IO CInt
+readRawBufferNoBlock loc fd is_nonblock buf off len
+ | is_nonblock = unsafe_read -- unsafe is ok, it can't block
+ | otherwise = do r <- unsafe_fdReady (fromIntegral fd) 0 0 0
+ if r /= 0 then safe_read
+ else return 0
+ -- XXX see note [nonblock]
+ where
+ do_read call = throwErrnoIfMinus1RetryOnBlock loc call (return 0)
+ unsafe_read = do_read (read_rawBuffer fd buf off len)
+ safe_read = do_read (safe_read_rawBuffer fd buf off len)
+
+readRawBufferPtrNoBlock :: String -> FD -> Bool -> Ptr CChar -> Int -> CInt -> IO CInt
+readRawBufferPtrNoBlock loc fd is_nonblock buf off len
+ | is_nonblock = unsafe_read -- unsafe is ok, it can't block
+ | otherwise = do r <- unsafe_fdReady (fromIntegral fd) 0 0 0
+ if r /= 0 then safe_read
+ else return 0
+ -- XXX see note [nonblock]
+ where
+ do_read call = throwErrnoIfMinus1RetryOnBlock loc call (return 0)
+ unsafe_read = do_read (read_off fd buf off len)
+ safe_read = do_read (safe_read_off fd buf off len)
+
+writeRawBuffer :: String -> FD -> Bool -> RawBuffer -> Int -> CInt -> IO CInt
+writeRawBuffer loc fd is_nonblock buf off len
+ | is_nonblock = unsafe_write -- unsafe is ok, it can't block
+ | otherwise = do r <- unsafe_fdReady (fromIntegral fd) 1 0 0
+ if r /= 0
+ then write
+ else do threadWaitWrite (fromIntegral fd); write
+ where
+ do_write call = throwErrnoIfMinus1RetryMayBlock loc call
+ (threadWaitWrite (fromIntegral fd))
+ write = if threaded then safe_write else unsafe_write
+ unsafe_write = do_write (write_rawBuffer fd buf off len)
+ safe_write = do_write (safe_write_rawBuffer (fromIntegral fd) buf off len)
+
+writeRawBufferPtr :: String -> FD -> Bool -> Ptr CChar -> Int -> CInt -> IO CInt
+writeRawBufferPtr loc fd is_nonblock buf off len
+ | is_nonblock = unsafe_write -- unsafe is ok, it can't block
+ | otherwise = do r <- unsafe_fdReady (fromIntegral fd) 1 0 0
+ if r /= 0
+ then write
+ else do threadWaitWrite (fromIntegral fd); write
+ where
+ do_write call = throwErrnoIfMinus1RetryMayBlock loc call
+ (threadWaitWrite (fromIntegral fd))
+ write = if threaded then safe_write else unsafe_write
+ unsafe_write = do_write (write_off fd buf off len)
+ safe_write = do_write (safe_write_off (fromIntegral fd) buf off len)
+