Out-of-band I/O services

Talking to real-time capable device drivers

Using the EVL kernel API, you can extend an existing character driver for supporting out-of-band I/O requests, or even write one from scratch.

On the user side, application can exchange data with, send requests to these real-time capable drivers from the out-of-band execution stage with the a couple of additional services libevl provides.

The EVL core does not currently support out-of-band socket semantics. Maybe at some point this will happen, but this needs more thought about proper integration of this feature. Not there yet.

You may notice that several POSIX file I/O services such as open(2), close(2), fcntl(2), mmap(2) and so on have no out-of-band counterpart in the following list. The reason is that we don’t need them: opening, closing or mapping a file are inherently non-deterministic operations, which may block for an unspecified amount of time for a number of reasons, depending on the underlying file and current runtime conditions. Besides, those are hardly useful in a time-critical loop.

However, issuing data transfers and control requests to the driver is definitely something we may want to happen within a bounded time, hence directly from the out-of-band execution stage.

Since the EVL core exports each element as a character device which can be accessed from /dev/evl, interacting with EVL elements via libevl is a actually done through the out-of-band I/O interface documented here.

Out-of-band I/O services

ssize_t oob_read(int efd, void *buf, size_t count)

This is the strict equivalent to the standard read(2) system call, but for running the request from the out-of-band stage. In other words, oob_read() attempts to read up to count bytes from file descriptor fd into the buffer starting at buf, from the out-of-band execution stage.

The caller must be an EVL thread, which may be switched automatically by the EVL core to the out-of-band execution stage as a result of this call.

  • fd

    A file descriptor obtained by opening a real-time capable driver which we want to read from.

  • buf

    A buffer to receive the data.

  • count

    The number of bytes to read at most, which should fit into buf.

  • oob_read() returns the actual number of bytes read, copied to buf on success. Otherwise, -1 is returned, and errno is set to the error code:

    EBADF if fd does not refer to a real-time capable driver, or fd was not opened for reading.

    EINVAL if fd does not support the .oob_read operation.

    EFAULT if buf points to invalid memory.

    EAGAIN fd is marked as non-blocking (O_NONBLOCK), and the read operation would block.

    Other driver-specific error codes may be returned, such as:

    ENOBUFS fd is a cross-buffer file descriptor, and there is no ring buffer space associated with the outbound traffic (i.e. o_bufsz parameter was zero when creating the cross-buffer).

    EINVAL fd is a cross-buffer file descriptor, and count is greater than the size of the ring buffer associated with the traffic direction. (i.e. either the i_bufsz or o_bufsz parameter given when creating the cross-buffer).


    ssize_t oob_write(int efd, const void *buf, size_t count)

    This is the strict equivalent to the standard write(2) system call, but for running the request from the out-of-band stage. In other words, oob_write() attempts to write up to count bytes to file descriptor fd from the buffer starting at buf, from the out-of-band execution stage.

    The caller must be an EVL thread, which may be switched automatically by the EVL core to the out-of-band execution stage as a result of this call.

  • fd

    A file descriptor obtained by opening a real-time capable driver which we want to read from.

  • buf

    A buffer containing the data to be written.

  • count

    The number of bytes to write starting from buf.

  • oob_write() returns the actual number of bytes written from buf on success. Otherwise, -1 is returned, and errno is set to the error code:

    EBADF if fd does not refer to a real-time capable driver, or fd was not opened for writing.

    EINVAL if fd does not support the .oob_write operation.

    EFAULT if buf points to invalid memory.

    EAGAIN fd is marked as non-blocking (O_NONBLOCK), and the write operation would block.

    Other driver-specific error codes may be returned, such as:

    EFBIG fd is a proxy file descriptor, and count is larger than the size of the output buffer as specified in the call to evl_new_proxy().

    EINVAL fd is a proxy file descriptor, and count is not a multiple of the output granularity as specified in the call to evl_new_proxy().

    ENOBUFS fd is a cross-buffer file descriptor, and there is no ring buffer space associated with the inbound traffic (i.e. i_bufsz parameter was zero when creating the cross-buffer).

    EINVAL fd is a cross-buffer file descriptor, and count is greater than the size of the ring buffer associated with the traffic direction. (i.e. either the i_bufsz or o_bufsz parameter given when creating the cross-buffer).


    int oob_ioctl(int efd, unsigned long request, ...)

    This is the strict equivalent to the standard ioctl(2) system call, but for running the I/O control request from the out-of-band stage. In other words, oob_ioctl() issues request to file descriptor fd from the out-of-band execution stage.

    The caller must be an EVL thread, which may be switched automatically by the EVL core to the out-of-band execution stage as a result of this call.

  • fd

    A file descriptor obtained by opening a real-time capable driver which we want to send a request to.

  • request

    The I/O control request code.

  • ...

    An optional variable argument list which applies to request.

  • oob_ioctl() returns zero on success. Otherwise, -1 is returned, and errno is set to the error code:

    EBADF if fd does not refer to a real-time capable driver.

    ENOTTY if fd does not support the .oob_ioctl operation, or the driver does not implement request.

    EFAULT if buf points to invalid memory.

    EAGAIN fd is marked as [non-blocking (O_NONBLOCK)], and the control request would block.

    Other driver-specific error codes may be returned.


    Last modified: Tue, 26 Nov 2019 18:03:02 CET