DragonFly On-Line Manual Pages
UMTX(2) DragonFly System Calls Manual UMTX(2)
NAME
umtx_sleep, umtx_wakeup -- kernel support for userland mutexes
LIBRARY
Standard C Library (libc, -lc)
SYNOPSIS
#include <unistd.h>
int
umtx_sleep(volatile const int *ptr, int value, int timeout);
int
umtx_wakeup(volatile const int *ptr, int count);
DESCRIPTION
The umtx_sleep() system call will put the calling process to sleep for
timeout microseconds if the contents of the specified pointer matches the
specified value. Specifying a timeout of 0 indicates an indefinite
timeout. The comparison is not atomic with the sleep but is properly
interlocked against another process calling umtx_wakeup(). In
particular, while it is possible for two userland threads to race, one
going to sleep simultaneously with another releasing the mutex, this
condition is caught when the second userland thread calls umtx_wakeup()
after releasing the contended mutex.
The timeout has no specific limitation other than what fits in the signed
integer. A negative timeout will return EINVAL.
WARNING! In order to properly interlock against fork(), this function
will do an atomic read-modify-write on the underlying memory by
atomically adding the value 0 to it.
The umtx_wakeup() system call will wakeup the specified number of
processes sleeping in umtx_sleep() on the specified user address. A
count of 0 will wake up all sleeping processes. This function may wake
up more processes then the specified count but will never wake up fewer
processes (unless there are simply not that many currently sleeping on
the address). The current DragonFly implementation optimized the count =
1 case but otherwise just wakes up all processes sleeping on the address.
Kernel support for userland mutexes is based on the physical memory
backing the user address. That is, the kernel will typically construct a
sleep id based on the underlying physical memory address. Two userland
programs may use this facility through mmap(), sysv(), rfork(), or light
weight process-based shared memory. It is important to note that the
kernel does not take responsibility for adjusting the contents of the
mutex or for the userland implementation of the mutex.
umtx_sleep() does not restart in case of a signal, even if the signal
specifies that system calls should restart.
Various operating system events can cause umtx_sleep() to return
prematurely, with the contents of the mutex unchanged relative to the
compare value. Callers must be able to deal with such returns.
RETURN VALUES
umtx_sleep() will return 0 if it successfully slept and was then woken
up. Otherwise it will return -1 and set errno as shown below.
umtx_wakeup() will generally return 0 unless the address is bad.
EXAMPLES
void
userland_get_mutex(struct umtx *mtx)
{
int v;
v = mtx->lock;
for (;;) {
if (v == 0) {
if (atomic_fcmpset_int(&mtx->lock, &v, 1))
break;
} else if (atomic_fcmpset_int(&mtx->lock, &v, 2)) {
umtx_sleep(&mtx->lock, 2, 0);
}
}
}
void
userland_rel_mutex(struct umtx *mtx)
{
int v;
v = atomic_swap_int(&mtx->lock, 0);
if (v == 2)
umtx_wakeup(&mtx->lock, 1);
}
WARNINGS
This function can return -1 with errno set to EWOULDBLOCK early and even
if no timeout is specified due to the kernel failsafe timeout activating.
The caller is advised to track the timeout independently using
clock_gettime().
This function can return -1 with errno set to EINTR and it is up to the
caller to loop if the caller's own API disallows returning EINTR.
This function can also return -1 with errno set to EBUSY due to internal
kernel effects.
This function can return without error when woken up via internal kernel
effects and not necessarily just by a umtx_wakeup() call.
Because the kernel will always use the underlying physical address for
its tsleep/wakeup id (e.g. which is required to properly supported
memory-mapped locks shared between processes), certain actions taken by
the program and/or by the kernel can disrupt synchronization between
umtx_sleep() and umtx_wakeup(). The kernel is responsible for handling
fork() actions, and will typically wakeup all blocked umtx_sleep() for
all threads of a process upon any thread forking. However, other actions
such as pagein and pageout can also desynchronize sleeps and wakeups. To
deal with these actions, the kernel typically implements a failsafe
timeout of around 2 seconds for umtx_sleep(). To properly resynchronize
the physical address, ALL threads blocking on the address should perform
a modifying operation on the underlying memory before re-entering the
wait state, or otherwise be willing to incur the failsafe timeout as
their recovery mechanism.
ERRORS
[EBUSY] The contents of *ptr possibly did not match value
[EWOULDBLOCK] The specified timeout occurred, or a kernel-defined
failsafe timeout occurred, or the kernel requires a
retry due to a copy-on-write / fork operation.
Callers should not assume that the precise requested
timeout occurred when this error is returned, and this
error can be returned even when no timeout is
specified.
[EINTR] The umtx_sleep() call was interrupted by a signal.
[EINVAL] An invalid parameter (typically an invalid timeout)
was specified.
SEE ALSO
tls(2)
HISTORY
The umtx_sleep(), and umtx_wakeup() function calls first appeared in
DragonFly 1.1.
DragonFly 5.5 January 15, 2015 DragonFly 5.5