A lighweight, lockless multi-reader/multi-writer FIFO with a
base-offset variant which can work over a memory segment shared
between processes. Scalar data or simple (small!) aggregates are
conveyed though a tube inside canisters which exactly fit their type.
By design, a tube is meant to be a basic, spartan mechanism: it
imposes no usage policy whatsoever on users.
As a result, a tube is strictly non-blocking, it solely detects and
notifies the caller on return about empty input (no message in) and
output contention (no buffer space for output). If required, the
caller can implement blocking states, typically with a pair of EVL
semaphores, e.g. setting up a tube conveying integers which supports
blocking mode:
DECLARE_EVL_TUBE_CANISTER(canister_type, int); /* defines struct canister_type */
DECLARE_EVL_TUBE(tube_type, cannister_type) tube;
struct cannister_type items[1024];
evl_init_tube(&tube, items, 1024);
evl_new_sem(&in, ...);
evl_new_sem_any(&out, CLOCK_MONOTONIC, tube.max_items, ...);
evl_get_sem(&in, ...); @ evl_get_sem(&out);
evl_tube_receive(&tube, ...); @ evl_tube_send(&tube, ...);
evl_put_sem(&out); @ evl_put_sem(&in, ...);
Returns version information about the running EVL interface including
the API and kernel ABI levels. A negative ABI level denotes the EVL
shim layer (eshi).
Stress load running in parallel to this test might be high enough to
have udelay() actually skipped by the EVL core since the sleep_until
(absolute) form is used internally, preventing evl_schedule() from
ever being called, which in turn skip the PP boost for the caller.
This has been observed on qemu-aarch64 under extreme load.
Increase the delay to 5ms.
Events timed on the monotonic clock is the most common form used by
applications. Allow people to write more compact code by providing
creation calls and static initializers aimed at building these
directly:
- evl_new_event(), EVL_EVENT_INITIALIZER() for events timed on the
monotonic clock.
- evl_new_event_any() and EVL_EVENT_ANY_INITIALIZER() usable for
specifying the clock.
Zero-initialized semaphores timed on the monotonic clock is the
most common form used by applications. Allow people to write more
compact code by providing creation calls and static initializers aimed
at building these directly:
- evl_new_sem(), EVL_SEM_INITIALIZER() for zero-init semaphores
timed on the monotonic clock.
- evl_new_sem_any() and EVL_SEM_ANY_INITIALIZER() usable for any
initialization form, specifying the clock and init value.
Zero-initialized event groups timed on the monotonic clock is the
most common form used by applications. Allow people to write more
compact code by providing creation calls and static initializers aimed
at building these directly:
- evl_new_flags(), EVL_FLAGS_INITIALIZER() for zero-init event groups
timed on the monotonic clock.
- evl_new_flags_any() and EVL_FLAGS_ANY_INITIALIZER() usable for any
initialization form, specifying the clock and init value.
Normal (i.e. non-recursive) mutexes timed on the monotonic clock are
the most common form of locks used by applications. Allow people to
write more compact code by providing creation calls and static
initializers aimed at building these directly:
- evl_new_mutex(), EVL_MUTEX_INITIALIZER() for PI locks timed on the
monotonic clock.
- evl_new_mutex_any() and EVL_MUTEX_ANY_INITIALIZER() for building any
supported type of lock (normal/recursive), specifying the protocol
(PI/PP) and the base clock.
The EVL shim library mimics the behavior of the original EVL API based
on plain POSIX calls from the native *libc, which does not require the
EVL core to be enabled in the host kernel. It is useful when the
real-time guarantees delivered by the EVL core are not required for
quick prototyping or debugging application code.