Skip to content

Add support for non-blocking network IO

Yorick Peterse requested to merge async-io into master

Details

This adds support for performing non-blocking network operations, such as reading and writing to/from a socket. The runtime API exposed is similar to Erlang, allowing one to write code that uses non-blocking APIs without having to resort to using callbacks. For example, in a typicall callback based language you may write the following to read from a socket:

socket.create do (socket) {
  socket.read do (data) {

  }
}

In Inko, you instead would (more or less) write the following:

import std::net::socket::TcpStream

let socket = try! TcpStream.new(ip: '192.0.2.0', port: 80)
let message = try! socket.read_string(size: 4)

The VM then takes care of using the appropriate non-blocking operations, and will reschedule processes whenever necessary.

This functionality is exposed through the following runtime modules:

  • std::net::ip: used for parsing IPv4 and IPv6 addresses.
  • std::net::socket: used for TCP and UDP sockets.
  • std::net::unix: used for Unix domain sockets.

The VM uses the system's native polling mechanism to determine when a file descriptor is available for a read or write. On Linux we use epoll, while using kqueue for the various BSDs and Mac OS. For Windows we use wepoll (https://github.com/piscisaureus/wepoll). Wepoll exposes an API that is compatible with the epoll API, but uses Windows IO completion ports under the hoods.

When a process attempts to perform a non-blocking operation, the process is registered (combined with the file descriptor to poll) in a global poller and suspended. When the file descriptor becomes available for a read or write, the corresponding process is rescheduled. The polling mechanism is set up in such a way that a process can not be rescheduled multiple times at once.

Corresponding issue

Fixes #112 (closed)

Checklist

  • Write a more detailed description
  • Explain why we're using epoll/kqueue/etc directly instead of MIO
  • Set up a crate for wepoll bindings
  • Add kqueue support
  • Add wepoll support
  • Write a proper MR description
  • Investigate why LocalAllocator needs more memory on nightly Rust (perhaps due to hash brown?)
  • Handle unused variables on Windows: https://ci.appveyor.com/project/YorickPeterse/inko/builds/24170241/job/mhyg6pqfi30olulm
  • Implement socket instructions
    • Creating a socket (UDP, TCP socket, TCP listener)
    • Obtaining the peer and local address
    • Setting and getting socket options
    • accept() for TCP listeners
    • send_to() for UDP sockets
    • recv_from for UDP sockets
    • read()
    • write()
    • connect() for UDP sockets
  • Write standard library
    • std::net::socket
      • Socket
      • UdpSocket
      • TcpStream
      • TcpListener
      • SocketAddress
    • std::net::ip
      • IpAddress
      • Ipv4Address
      • Ipv6Address
      • parse()
    • std::net::unix
      • UnixSocket
      • UnixDatagram
      • UnixListener
      • SocketAddress
  • Added tests
  • Added documentation
  • Inko source code follows the Inko style guide
Edited by Yorick Peterse

Merge request reports