A most typical requirement in dual kernel systems is to exchange data between threads running in separate execution stages, i.e. out-of-band vs in-band, without incuring any delay for the out-of-band side. The EVL core implements a feature called a cross-buffer (aka xbuf), which connects the sending out-of-band end of a communication channel to its receiving in-band end, and conversely. As a result, data sent to a cross-buffer by calling oob_write() are received by calling read(2), data sent by calling write(2) are received by calling oob_read(). A cross-buffer can be used for transferring fixed-size or variable-size data, supports message-based and byte-oriented streams. For instance, such a mechanism would enable a GUI front-end to receive monitoring data from a real-time work loop.
The following rules apply to cross-buffer transfers, in either directions (inbound and outbound):
If you plan to send fixed-size messages through a cross-buffer and keeping the message boundaries intact matters, you should pick a buffer size which is a multiple of the basic message size, reading and writing complete messages at each transfer.
Otherwise, if O_NONBLOCK
is set and not enough bytes are immediately
available from the ring buffer for satisfying the request, the write
operation fails with the EAGAIN
error status.
EAGAIN
).This call creates a new cross-buffer, then returns a file descriptor representing the communication channel upon success. Internally, a cross-buffer is implemented as a pair of ring buffers conveying data from in-band to out-of-band context (i.e. inbound traffic), and conversely (i.e. outbound traffic). oob_write() and oob_read() should be used by callers running on the out-of-band stage for sending/receiving data through this channel respectively. Conversely, write(2) and read(2) should be used for accessing the channel from the in-band stage.
The size in bytes of the ring buffer conveying inbound traffic. If zero, the cross-buffer is intended to relay outbound messages exclusively, i.e. from the in-band to the out-of-band context. i_bufsz must not exceed 2^30.
The size in bytes of the ring buffer conveying outbound traffic. If zero, the cross-buffer is intended to relay inbound messages exclusively, i.e. from the out-of-band to the in-band context. i_bufsz must not exceed 2^30.
A set of creation flags for the new element, defining its visibility:
EVL_CLONE_PUBLIC
denotes a public element which is represented
by a device file in the /dev/evl file hierarchy, which
makes it visible to other processes for sharing.
EVL_CLONE_PRIVATE
denotes an element which is private to the
calling process. No device file appears for it in the /dev/evl file hierarchy.
EVL_CLONE_NONBLOCK
sets the file descriptor of the new cross-buffer in
non-blocking I/O mode (O_NONBLOCK
). By default, O_NONBLOCK
is
cleared for the file descriptor.
A printf-like format string to generate the cross-buffer name. See this description of the naming convention.
The optional variable argument list completing the format.
evl_create_xbuf() returns the file descriptor of the new cross-buffer on success. If the call fails, a negated error code is returned instead:
-EEXIST The generated name is conflicting with an existing cross-buffer name.
-EINVAL Either flags is wrong, i_bufsz and/or o_bufsz are wrong, or the generated name is badly formed.
-ENAMETOOLONG The overall length of the device element’s file path including the generated name exceeds PATH_MAX.
-EMFILE The per-process limit on the number of open file descriptors has been reached.
-ENFILE The system-wide limit on the total number of open files has been reached.
-ENOMEM No memory available.
-ENXIO The EVL library is not initialized for the current process. Such initialization happens implicitly when evl_attach_self() is called by any thread of your process, or by explicitly calling evl_init(). You have to bootstrap the library services in a way or another before creating a cross-buffer.
This call is a shorthand for creating a private cross-buffer with identically-sized I/O buffers. It is identical to calling:
evl_create_xbuf(io_bufsz, io_bufsz, EVL_CLONE_PRIVATE, fmt, ...);
Note that if the generated name starts with a
slash (’/’) character, EVL_CLONE_PRIVATE
would be automatically turned
into EVL_CLONE_PUBLIC
internally.
The evl_poll() interface can monitor the following events occurring on a cross-buffer file descriptor:
POLLIN and POLLRDNORM are set whenever data coming from the in-band side is available for reading by a call to oob_read().
POLLOUT and POLLWRNORM are set whenever there is still room in the output ring buffer for sending more data to the in-band side using oob_write().
Conversely, you can also use the in-band poll(2) on a cross-buffer file descriptor, monitoring the following events:
POLLIN and POLLRDNORM are set whenever data coming from the out-of-band side is available for reading, by a call to read(2).
POLLOUT and POLLWRNORM are set whenever there is still room in the output ring buffer for sending more data to the out-of-band side, using write(2).