Update on Eio (effects-based direct-style IO for OCaml 5)

Eio provides an effects-based direct-style IO stack for OCaml 5.0. It aims to be easy to use, secure, well documented, and fast. It consists of a generic cross-platform API, plus optimised backends for different platforms. It can be used instead of (or alongside) Lwt and Async.

Recent changes

There have been several releases since the last announcement here. The bigger changes include:

  • Fiber-local storage (thanks to Jonathan Coates). This allows e.g. a web-server to attach a request ID to the fiber that is handling it, and then display this in all log messages generated by that request.
  • Eio.Mutex and Eio.Condition (@Lortex). These are similar to the ones in the standard library, but they allow other fibers to run while waiting instead of blocking the whole domain.
  • Eio.Buf_write is a port of Faraday to Eio, allowing efficient output buffering.
  • Fiber.fork_daemon allows spawning a fiber that will be cancelled automatically when the non-daemon fibers have finished. This is useful for e.g. running a thread to collect entropy for a random number generator while a program is running, without it preventing the program from finishing.
  • Fiber.{iter,map,filter,fiter_map} provide concurrent versions of the corresponding operations in List.
  • Eio.Path provides file-system access. New operations include read_dir (@patricoferris), unlink, rmdir and rename.
  • The networking APIs now include UDP (@patricoferris) and DNS (@bikalgurung), and IPv6 now works (@haesbaert).
  • Eio_mock provides a framework for creating mocks for testing, along with pre-defined ones for flows and networks. Eio_mock.Backend is a special backend for tests. It does no real IO, but can report if your tests deadlock.
  • The much-requested Eio_unix.sleep is now available as a direct replacement for Lwt_unix.sleep.

See the release notes for full details, and the tutorial for an introduction.

Integration with Lwt and Async

Lwt_eio allows running Lwt and Eio code together in a single domain. The 0.2 release adds support for integrating Lwt and Eio cancellation. The porting guide shows how to update an Lwt application to Eio incrementally.

Async_eio allows running Async and Eio code together in a single domain. This is experimental and requires some changes to Async itself.

async-eio-lwt-chimera shows how Async, Eio and Lwt code can all be used together in a single event loop. It runs an Async server that handles connections using an Lwt handler that reads a line from the request and then handles it by using Eio to read the named file from its data directory.

Porting

It’s useful for people to try porting applications and libraries to Eio so we can get feedback on the APIs and prioritise missing features. The Lwt and Async porting guides linked above may be helpful. Some examples so far include:

Backends

The recent uring releases have brought improved performance and several new features to the eio_linux backend.

We are still hoping to persuade a Windows user to try using Eio. The Luv backend should mostly work, but there are likely some problems with paths, etc. Even better would be if someone writes a dedicated eio_windows backend.

To add a backend for a new platform, it is best to start by studying Eio_mock.Backend, which is very simple as it does no IO. To add IO, you can copy the pattern in either eio_linux (which provides its own event loop that asks the OS to sleep) or the one in eio_luv (which delegates to an event loop provided by another library).

43 Likes

Thanks for the updates @talex5! Thought I’d also mention that:

6 Likes

With Eio 0.10 just released, it’s time for another update! Since the above post (which was for Eio 0.5), some of the bigger changes are:

  • A new eio_posix backed for Unix-type systems provides much better performance than the old libuv one. Removing libuv has also made it safe to share file-descriptors between domains, so you can now accept a connection with one domain and handle it with another, for example.

  • There is now an API for spawning sub-processes.

  • Networking changes include better support for datagram sockets and the new Eio.Net.run_server convenience function.

  • Many of the data-structures (promises, conditions, semaphores and synchronous streams) are now lock-free, making them faster to use across multiple domains.

  • It is safe to handle signals in Eio now that Eio.Condition.broadcast is lock-free (signal handlers can’t take locks, since they may have interrupted the thread holding the lock). Though note that reliable signal handling on OCaml 5 requires OCaml#12253 to be fixed too.

  • Fiber.fork_seq provides an easy way to create generator functions.

  • Eio now supports domain-local-await, which allows sharing e.g. kcas data-structures across Eio and Domainslib domains.

  • Error handling has been improved. You can now add extra context information to errors (e.g. an error opening a missing file will now include the path of the file). You can also choose how specific to be: e.g. you can catch all IO errors, all network errors, or all connection reset errors.

  • There are also some experimental backends under development:

    • eio_solo5 is for MirageOS unikernels.
    • eio_js is for browsers.
    • eio_windows is for Windows - see #125 if you’d like to help out.

A more detailed list of changes can be found in the release notes.

Eio’s README.md provides an introduction to most of the features.

If you’d like to get involved, the new HACKING.md document explains the structure of the code for people who want to contribute to Eio, and there are regular Eio developer meetings for anyone who wants to get involved.

25 Likes