Monitoring a file descriptor

The Generic event source wraps a file descriptor ("fd") and fires its callback any time there are events on it ie. becoming readable or writable, or encountering an error. It's pretty simple, but it's what every other event source is based around. And since the platforms that calloop runs on expose many different kinds of events via fds, it's usually the key to using those events in calloop.

For example on Linux, fd-based interfaces are available for GPIO, I2C, USB, UART, network interfaces, timers and many other systems. Integrating these into calloop starts with obtaining the appropriate fd, creating a Generic event source from it, and building up a more useful, abstracted event source around that. A detailed example of this is given for ZeroMQ.

You do not have to use a low-level fd either: any type that implements AsFd can be provided. This means that you can use a wrapper type that handles allocation and disposal itself, and implement AsRawFd on it so that Generic can manage it in the event loop.

Creating a Generic source

Creating a Generic event source requires three things:

  • An OwnedFd or a wrapper type that implements AsFd
  • The "interest" you have in this descriptor — this means, whether you want to generate events when the fd becomes readable, writeable, or both
  • The "mode" of event generation - level triggered or edge triggered

The easiest constructor to use is the new() method, but if you need control over the associated error type there is also new_with_error().

Ownership and AsFd wrappers

Rust 1.63 introduced a concept of file descriptor ownership and borrowing through the OwnedFd and BorrowedFd types. The AsFd trait provides a way to get a BorrowedFd corresponding to a file, socket, etc. while guaranteeing the fd will be valid for the lifetime of the BorrowedFd.

Not all third party crates use AsFd yet, and may instead provide types implementing AsRawFd. 'AsFdWrapper' provides a way to adapt these types. To use this safely, ensure the AsRawFd implementation of the type it wraps returns a valid fd as long as the type exists. And to avoid an fd leak, it should ultimately be closed properly.

Safe types like OwnedFd and BorrowedFd should be preferred over RawFds, and the use of RawFds outside of implementing FFI shouldn't be necessary as libraries move to using the IO safe types and traits.