struct futex_item { uint64_t addr; uint32_t expected; uint32_t flags; }; #define FUTEX_WAIT 1 #define FUTEX_WAKE 2 int futex(int operation, struct futex_item *futexes, size_t count, struct timespec *time);
This syscall helps implement fast userland mutexes (futexes!). It is typically used as a blocking construct in the context of shared-memory synchronization.
When using futexes, the majority of the synchronization operations are
performed in user space by atomically testing for a 32-bit value. User-space is
to use futex
only when it is likely that the program has to block for a
longer time until the condition becomes true. Other futex
operations
can be used to wake any processes or threads waiting for an address.
When executing a futex operation that requests to block a thread, the kernel
will block only if the futex contents has the value that the call suplied under
expected
. The loading of the futex’s contents and comparison of that
value are atomic, and will be totally ordered with respect to concurrent
operations performed by other threads on the same futex contents. Thus, the
futex contents are used to connect the synchronization in user space with the
implementation of blocking by the kernel. Analogously to an atomic
compare-and-exchange operation that potentially changes shared memory, blocking
via a futex is an atomic compare-and-block operation. When blocked, the kernel
will calmly wait for waking by FUTEX_WAKE
, waking is not automatic once
the values are acquired.
Note that no explicit initialization or destruction is necessary to use
futexes; the kernel maintains a futex only while operations such as
FUTEX_WAIT
are being performed on particular futex contents.
When compared with other implementations like Linux’s, Ironclad’s allows for waiting and waking several futexes at once, this is done as to ease handling several futexes at once.
The available futex operations are:
FUTEX_WAIT
The passed values in futexes will be waited for.
FUTEX_WAKE
The passed values in futexes will be woken up.
The syscall returns 0
on success or -1
on failure, with the
following errno:
EFAULT
The passed addresses would fault if accessed.
EINVAL
The passed operation is not valid.