Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does haskell's network library use non-blocking sockets?

Tags:

haskell

ghc

I'm trying to better understand a design decision made in the network library. Reputable sources mention in a github issue and a mailing list response that network uses non-blocking sockets. Instead of using the default blocking behavior, they use select to block until the socket is ready to be read. Why is this better? Either way, it ends up blocking, and network only exposes a blocking API to end users. My guess is that it's bad for an FFI call to block and that there is some kind of GHC magic around select, but I haven't been able to confirm that.

As a minor aside, I cannot find where select in called in network. Grepping the codebase did not turn up anything. I just discovered GHC.Event, which seems to provide functions that would be used instead of calling select directly, but grepping shows network doesn't use this either.

like image 481
Andrew Thaddeus Martin Avatar asked Jan 13 '17 19:01

Andrew Thaddeus Martin


People also ask

What is non-blocking in socket?

In blocking socket mode, a system call event halts the execution until an appropriate reply has been received. In non-blocking sockets, it continues to execute even if the system call has been invoked and deals with its reply appropriately later.

How can you tell if a socket is blocking or non-blocking?

From MSDN, the return value of connect(): On a blocking socket, the return value indicates success or failure of the connection attempt. With a nonblocking socket, the connection attempt cannot be completed immediately. In this case, connect will return SOCKET_ERROR , and WSAGetLastError() will return WSAEWOULDBLOCK.

What does it mean for a socket to be blocking?

A socket is in blocking mode when an I/O call waits for an event to complete. If the blocking mode is set for a socket, the calling program is suspended until the expected event completes.

How do I make a TCP socket non-blocking?

To mark a socket as non-blocking, we use the fcntl system call. Here's an example: int flags = guard(fcntl(socket_fd, F_GETFL), "could not get file flags"); guard(fcntl(socket_fd, F_SETFL, flags | O_NONBLOCK), "could not set file flags"); Here's a complete example.


1 Answers

The non-blocking IO event loop is part of GHC's runtime system (RTS). This interacts very nicely with GHC's green thread system: instead of writing asynchronous code, you can just use lightweight threads and the runtime will take care of waking up the correct one.

All IO in in Haskell is non-blocking by default, so if you've got two threads that are each blocked on a different socket, then the runtime system will internally do select (or some other platform-specific way to wait on multiple file descriptors like epoll or kqueue) to only wake the thread up when the file descriptor becomes ready. See https://ghc.haskell.org/trac/ghc/wiki/Commentary/Rts/IOManager for more details.

like image 82
bennofs Avatar answered Sep 27 '22 22:09

bennofs