[Git][ghc/ghc][master] Do not use O_NONBLOCK on regular files or block devices

Marge Bot (@marge-bot) gitlab at gitlab.haskell.org
Sun Oct 8 19:06:36 UTC 2023



Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC


Commits:
e206be64 by Andrew Lelechenko at 2023-10-08T15:06:14-04:00
Do not use O_NONBLOCK on regular files or block devices

CLC proposal https://github.com/haskell/core-libraries-committee/issues/166

- - - - -


2 changed files:

- libraries/base/GHC/IO/FD.hs
- libraries/base/changelog.md


Changes:

=====================================
libraries/base/GHC/IO/FD.hs
=====================================
@@ -82,13 +82,19 @@ clampReadSize  = min 0x7ffff000
 data FD = FD {
   fdFD :: {-# UNPACK #-} !CInt,
 #if defined(mingw32_HOST_OS)
-  -- On Windows, a socket file descriptor needs to be read and written
+  -- | On Windows, a socket file descriptor needs to be read and written
   -- using different functions (send/recv).
   fdIsSocket_ :: {-# UNPACK #-} !Int
 #else
-  -- On Unix we need to know whether this FD has O_NONBLOCK set.
-  -- If it has, then we can use more efficient routines to read/write to it.
-  -- It is always safe for this to be off.
+  -- | On Unix we need to know whether this 'FD' has @O_NONBLOCK@ set.
+  -- If it has, then we can use more efficient routines (namely, unsafe FFI)
+  -- to read/write to it. Otherwise safe FFI is used.
+  --
+  -- @O_NONBLOCK@ has no effect on regular files and block devices at the moment,
+  -- thus this flag should be off for them. While reading from a file cannot
+  -- block indefinitely (as opposed to reading from a socket or a pipe), it can block
+  -- the entire runtime for a "brief" moment of time: you cannot read a file from
+  -- a floppy drive or network share without delay.
   fdIsNonBlocking :: {-# UNPACK #-} !Int
 #endif
  }
@@ -197,6 +203,9 @@ openFileWith
   :: FilePath -- ^ file to open
   -> IOMode   -- ^ mode in which to open the file
   -> Bool     -- ^ open the file in non-blocking mode?
+              --   This has no effect on regular files and block devices:
+              --   they are always opened in blocking mode.
+              --   See 'fdIsNonBlocking' for more discussion.
   -> (FD -> IODeviceType -> IO r) -- ^ @act1@: An action to perform
                     -- on the file descriptor with the masking state
                     -- restored and an exception handler that closes
@@ -332,7 +341,11 @@ mkFD fd iomode mb_stat is_socket is_nonblock = do
 
     return (FD{ fdFD = fd,
 #if !defined(mingw32_HOST_OS)
-                fdIsNonBlocking = fromEnum is_nonblock
+                -- As https://man7.org/linux/man-pages/man2/open.2.html explains,
+                -- O_NONBLOCK has no effect on regular files and block devices;
+                -- utilities inspecting fdIsNonBlocking (such as readRawBufferPtr)
+                -- should not be tricked to think otherwise.
+                fdIsNonBlocking = fromEnum (is_nonblock && fd_type /= RegularFile && fd_type /= RawDevice)
 #else
                 fdIsSocket_ = fromEnum is_socket
 #endif
@@ -452,11 +465,19 @@ dup2 fd fdto = do
 
 setNonBlockingMode :: FD -> Bool -> IO FD
 setNonBlockingMode fd set = do
-  setNonBlockingFD (fdFD fd) set
+  -- This mirrors the behaviour of mkFD:
+  -- O_NONBLOCK has no effect on regular files and block devices;
+  -- utilities inspecting fdIsNonBlocking (such as readRawBufferPtr)
+  -- should not be tricked to think otherwise.
+  is_nonblock <- if set then do
+    (fd_type, _, _) <- fdStat (fdFD fd)
+    pure $ fd_type /= RegularFile && fd_type /= RawDevice
+    else pure False
+  setNonBlockingFD (fdFD fd) is_nonblock
 #if defined(mingw32_HOST_OS)
   return fd
 #else
-  return fd{ fdIsNonBlocking = fromEnum set }
+  return fd{ fdIsNonBlocking = fromEnum is_nonblock }
 #endif
 
 ready :: FD -> Bool -> Int -> IO Bool


=====================================
libraries/base/changelog.md
=====================================
@@ -5,6 +5,9 @@
   * Add a `RULE` to `Prelude.lookup`, allowing it to participate in list fusion ([CLC proposal #174](https://github.com/haskell/core-libraries-committee/issues/175))
   * The `Enum Int64` and `Enum Word64` instances now use native operations on 32-bit platforms, increasing performance by up to 1.5x on i386 and up to 5.6x with the JavaScript backend. ([CLC proposal #187](https://github.com/haskell/core-libraries-committee/issues/187))
   * Update to [Unicode 15.1.0](https://www.unicode.org/versions/Unicode15.1.0/).
+  * Fix `fdIsNonBlocking` to always be `0` for regular files and block devices on unix, regardless of `O_NONBLOCK`
+  * Always use `safe` call to `read` for regular files and block devices on unix if the RTS is multi-threaded, regardless of `O_NONBLOCK`.
+    ([CLC proposal #166](https://github.com/haskell/core-libraries-committee/issues/166))
 
 ## 4.19.0.0 *TBA*
   * Add `{-# WARNING in "x-partial" #-}` to `Data.List.{head,tail}`.



View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/e206be6470d6c1d4a5ed80615c8dc830efe011ea

-- 
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/e206be6470d6c1d4a5ed80615c8dc830efe011ea
You're receiving this email because of your account on gitlab.haskell.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/ghc-commits/attachments/20231008/caeeee89/attachment-0001.html>


More information about the ghc-commits mailing list