summaryrefslogtreecommitdiff
path: root/libraries/base/cbits
diff options
context:
space:
mode:
authorNiklas Hambüchen <mail@nh2.me>2017-09-19 15:12:56 -0400
committerBen Gamari <ben@smart-cactus.org>2017-09-19 15:58:46 -0400
commitba4dcc7cb77a37486368911fec854d112a1db93c (patch)
treeee3917b21670285881e7be7b4b865dba7d63bd43 /libraries/base/cbits
parentb7f2d1256949c016724577168106002c4b12169c (diff)
downloadhaskell-ba4dcc7cb77a37486368911fec854d112a1db93c.tar.gz
base: Make it less likely for fdReady() to fail on Windows sockets.
See the added comment for details. It's "less likely" because it can still fail if the socket happens to have an FD larger than 1023, which can happen if many files are opened. Until now, basic socket programs that use `hWaitForInput` were broken on Windows. That is because on Windows `FD_SETSIZE` defaults to 64, but pretty much all GHC programs seem to have > 64 FDs open, so you can't actually create a socket on which you can `select()`. It errors with `fdReady: fd is too big` even with an example as simple as the following (in this case, on my machine the `fd` is `284`): {-# LANGUAGE OverloadedStrings #-} import Control.Monad (forever) import Network.Socket import System.IO -- Simple echo server: Reads up to 10 chars from network, echoes them back. -- Uses the Handle API so that `hWaitForInput` can be used. main :: IO () main = do sock <- socket AF_INET Stream 0 setSocketOption sock ReuseAddr 1 bind sock (SockAddrInet 1234 0x0100007f) -- 0x0100007f == 127.0.0.1 localhost listen sock 2 forever $ do (connSock, _connAddr) <- accept sock putStrLn "Got connection" h <- socketToHandle connSock ReadWriteMode hSetBuffering h NoBuffering ready <- hWaitForInput h (5 * 1000) -- 5 seconds putStrLn $ "Ready: " ++ show ready line <- hGetLine h putStrLn "Got line" hPutStrLn h ("Got: " ++ line) hClose h I'm not sure how this was not discovered earlier; for #13525 (where `fdReady()` breaking completely was also discovered late) at least it failed only when the timeout was non-zero, which is not used in ghc beyond in `hWaitForInput`, but in this Windows socket case it breaks even on the 0-timeout. Maybe there is not actually anybody who uses sockets as handles on Windows? The workaround for now is to increase `FD_SETSIZE` on Windows; increasing it is possible on Windows and BSD, see https://stackoverflow.com/questions/7976388/increasing-limit-of-fd-setsi ze-and-select A real fix would be to move to IO Completion Ports on Windows, and thus get rid of the last uses of `select()` (the other platforms already use `poll()` but Windows doesn't have that). Reviewers: bgamari, austin, hvr, erikd, simonmar Reviewed By: bgamari Subscribers: rwbarton, thomie Differential Revision: https://phabricator.haskell.org/D3959
Diffstat (limited to 'libraries/base/cbits')
-rw-r--r--libraries/base/cbits/inputReady.c16
1 files changed, 16 insertions, 0 deletions
diff --git a/libraries/base/cbits/inputReady.c b/libraries/base/cbits/inputReady.c
index ddeee664d6..916633c9c0 100644
--- a/libraries/base/cbits/inputReady.c
+++ b/libraries/base/cbits/inputReady.c
@@ -4,6 +4,22 @@
* hWaitForInput Runtime Support
*/
+/* FD_SETSIZE defaults to 64 on Windows, which makes even the most basic
+ * programs break that use select() on a socket FD.
+ * Thus we raise it here (before any #include of network-related headers)
+ * to 1024 so that at least those programs would work that would work on
+ * Linux if that used select() (luckily it uses poll() by now).
+ * See https://ghc.haskell.org/trac/ghc/ticket/13497#comment:23
+ * The real solution would be to remove all uses of select()
+ * on Windows, too, and use IO Completion Ports instead.
+ * Note that on Windows, one can simply define FD_SETSIZE to the desired
+ * size before including Winsock2.h, as described here:
+ * https://msdn.microsoft.com/en-us/library/windows/desktop/ms740141(v=vs.85).aspx
+ */
+#if defined(_WIN32)
+#define FD_SETSIZE 1024
+#endif
+
/* select and supporting types is not Posix */
/* #include "PosixSource.h" */
#include "HsBase.h"