EVL implements the classic Dijkstra semaphore construct, with an API close to the POSIX specification for the basic operations.
This call creates a semaphore, returning a file descriptor representing the new object upon success. This is the generic call form; for creating a semaphore with common pre-defined settings, see [evl_new_sem()}(#evl_new_sem).
An in-memory semaphore descriptor is constructed by
evl_create_sem(),
which contains ancillary information other calls will need. sem
is a pointer to such descriptor of type struct evl_sem
.
Some semaphore-related calls are timed like evl_timedget_sem() which receives a timeout value. You can specify the EVL clock this timeout refers to by passing its file descriptor as clockfd. Built-in EVL clocks are accepted here.
The initial value of the semaphore count.
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 semaphore 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 semaphore name. See this description of the naming convention.
The optional variable argument list completing the format.
evl_create_sem() returns the file descriptor of the newly created semaphore on success. Otherwise, a negated error code is returned:
-EEXIST The generated name is conflicting with an existing mutex, event, semaphore or flag group name.
-EINVAL Either clockfd does not refer to a valid EVL clock, or the generated semaphore name is badly formed, likely containing invalid character(s), such as a slash. Keep in mind that it should be usable as a basename of a device element’s file path.
-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 an EVL semaphore.
#include <evl/sem.h>
static struct evl_sem sem;
int create_new_sem(void)
{
int fd;
fd = evl_create_sem(sem, EVL_CLOCK_MONOTONIC, 1, EVL_CLONE_PRIVATE, "name_of_semaphore");
/* skipping checks */
return fd;
}
This call is a shorthand for creating a zero-initialized private semaphore, timed on the built-in EVL monotonic clock. It is identical to calling:
evl_create_sem(sem, EVL_CLOCK_MONOTONIC, 0, 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 static initializer you can use with semaphores. All arguments to this macro refer to their counterpart in the call to evl_create_sem().
struct evl_sem sem = EVL_SEM_INITIALIZER("name_of_semaphore", EVL_CLOCK_MONOTONIC, 1, EVL_CLONE_PUBLIC);
This call broadcasts a semaphore causing all waiters to be flushed
atomically. Any thread which is currently blocked on the semaphore by
evl_get_sem() or
evl_timedget_sem() is unblocked
and returns with the -EAGAIN
error code without being granted any
resource.
The in-memory semaphore descriptor constructed by either
evl_create_sem()
or evl_open_sem(), or statically built with
EVL_SEM_INITIALIZER. In
the latter case, an implicit call to
evl_create_sem() for sem
is
issued before the semaphore is posted, which may trigger a transition to
the in-band execution mode for the caller.
evl_flush_sem() returns zero upon success. Otherwise, a negated error code is returned:
-EINVAL sem
does not represent a valid in-memory semaphore
descriptor. If that pointer is out of the caller’s
address space or points to read-only memory, the
caller bluntly gets a memory access exception.
If sem
was statically initialized with EVL_SEM_INITIALIZER but not passed to any
semaphore-related call yet, then any error status returned by
evl_create_sem() may be passed
back to the caller in case the implicit initialization call fails.
You can open an existing semaphore, possibly from a different process, by calling evl_open_sem().
An in-memory semaphore descriptor is constructed by
evl_open_sem(),
which contains ancillary information other calls will need. sem
is a
pointer to such descriptor of type struct evl_sem
. The information
is retrieved from the existing semaphore which was opened.
A printf-like format string to generate the name of the semaphore to open. This name must exist in the EVL device file hierarchy at /dev/evl/monitor. See this description of the naming convention.
The optional variable argument list completing the format.
evl_open_sem() returns the file descriptor referring to the opened semaphore on success, Otherwise, a negated error code is returned:
-EINVAL The name refers to an existing object, but not to a semaphore.
-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.
This service decrements a semaphore by one. If the resulting semaphore value is negative, the caller is blocked until a call to evl_put_sem() eventually releases it. Otherwise, the caller returns immediately. Waiters are queued by order of scheduling priority.
The in-memory semaphore descriptor constructed by
either evl_create_sem() or
evl_open_sem(), or statically built
with EVL_SEM_INITIALIZER. In the latter case, an implicit call to
evl_create_sem() for
sem
is issued before a get operation is attempted, which may trigger
a transition to the in-band execution mode for the caller.
evl_get_sem() returns zero on success. Otherwise, a negated error code may be returned if:
-EINVAL sem
does not represent a valid in-memory semaphore
descriptor. If that pointer is out of the caller’s
address space or points to read-only memory, the
caller bluntly gets a memory access exception.
-EAGAIN evl_flush_sem() was called for the semaphore, unblocking all waiters. In this case, the unblocked thread(s) was NOT granted any resource.
If sem
was statically initialized with EVL_SEM_INITIALIZER, then any error returned by
evl_create_sem() may be passed
back to the caller in case the implicit initialization call fails.
This call is a variant of evl_get_sem() which allows specifying a timeout on the get operation, so that the caller is automatically unblocked when a time limit is reached.
The in-memory semaphore descriptor constructed by
either evl_create_sem() or
evl_open_sem(), or statically built
with EVL_SEM_INITIALIZER. In the latter case, an implicit call to
evl_create_sem() is
issued for sem
before a get operation is attempted, which may
trigger a transition to the in-band execution mode for the caller.
A time limit to wait for the caller to be unblocked before the call returns on error. The clock mentioned in the call to evl_create_sem() will be used for tracking the elapsed time.
The possible return values include any status from evl_get_sem(), plus:
-ETIMEDOUT The timeout fired, after the amount of time specified by timeout.
-EAGAIN evl_flush_sem() was called for the semaphore, unblocking all waiters. In this case, the unblocked thread(s) was NOT granted any resource.
This call posts a semaphore, releasing a resource. If some thread is currently blocked on the semaphore by evl_get_sem() or evl_timedget_sem(), the one leading the wait queue is unblocked. Otherwise, the semaphore count is incremented by one.
The in-memory semaphore descriptor constructed by either
evl_create_sem()
or evl_open_sem(), or statically built with
EVL_SEM_INITIALIZER. In
the latter case, an implicit call to
evl_create_sem() for sem
is
issued before the semaphore is posted, which may trigger a transition to
the in-band execution mode for the caller.
evl_put_sem() returns zero upon success. Otherwise, a negated error code is returned:
-EINVAL sem
does not represent a valid in-memory semaphore
descriptor. If that pointer is out of the caller’s
address space or points to read-only memory, the
caller bluntly gets a memory access exception.
If sem
was statically initialized with EVL_SEM_INITIALIZER but not passed to any
semaphore-related call yet, then any error status returned by
evl_create_sem() may be passed
back to the caller in case the implicit initialization call fails.
This call attempts to decrement the semaphore provided the result does not yield a negative count. Otherwise, the routine immediately returns with an error status.
The in-memory semaphore descriptor constructed by
either evl_create_sem() or
evl_open_sem(), or statically built
with EVL_SEM_INITIALIZER. In the latter case, an implicit call to
evl_create_sem() for
sem
is issued before a wait is attempted, which may trigger a transition
to the in-band execution mode for the caller.
evl_tryget_sem() returns zero on success. Otherwise, one of the following negated error code may be returned:
-EAGAIN sem
count value is zero or negative at the time of the call.
-EINVAL sem
does not represent a valid in-memory semaphore
descriptor. If that pointer is out of the caller’s
address space or points to read-only memory, the
caller bluntly gets a memory access exception.
If sem
was statically initialized with EVL_SEM_INITIALIZER, then any error returned by
evl_create_sem() may be passed
back to the caller in case the implicit initialization call fails.
This call returns the count value of the semaphore. If a negative count is returned in *r_val, its absolute value can be interpreted as the number of waiters blocked on the semaphore’s wait queue at the time of the call. A zero or positive value means that the semaphore is not contended.
The in-memory semaphore descriptor constructed by either evl_create_sem() or evl_open_sem(), or statically built with EVL_SEM_INITIALIZER. In the latter case, the semaphore becomes valid for a call to evl_peek_sem() only after a put or [try]get operation was issued for it.
The address of an integer where to copy the semaphore value on success.
evl_peek_sem() returns zero on success. Otherwise, a negated error code may be returned if:
-EINVAL sem
does not represent a valid in-memory semaphore
descriptor. If that pointer is out of the caller’s
address space or points to read-only memory, the
caller bluntly gets a memory access exception.
You can use evl_close_sem() to
dispose of an EVL semaphore, releasing the associated file descriptor,
at which point sem
will not be valid for any subsequent operation
from the current process. However, this semaphore is kept alive in the
EVL core until all file descriptors opened on it by call(s) to
evl_open_sem() have been released,
whether from the current process or any other process.
The in-memory descriptor of the semaphore to dismantle.
evl_close_sem() returns zero upon success. Otherwise, a negated error code is returned:
-EINVAL sem
does not represent a valid in-memory semaphore
descriptor. If that pointer is out of the caller’s
address space or points to read-only memory, the
caller bluntly gets a memory access exception.
Closing a statically initialized semaphore descriptor which has never been used in get or put operations always returns zero.
The evl_poll() interface can monitor the following events occurring on a semaphore file descriptor: