UMTX(2) BSD System Calls Manual UMTX(2)NAME
umtx_sleep, umtx_wakeup — kernel support for userland mutexes
LIBRARY
Standard C Library (libc, -lc)
SYNOPSIS
int
umtx_sleep(const int *ptr, int value, int timeout);
int
umtx_wakeup(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 point matches the
specified value. Specifying a timeout of 0 indicates an indefinite time‐
out. The comparison is not atomic with the sleep but is properly inter‐
locked 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 is not specific limitation other than what fits in the signed
integer. A negative timeout will return EINVAL.
The umtx_wakeup() system call will wakeup the specified number of pro‐
cesses 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 back‐
ing the user 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 responsi‐
bility for adjusting the contents of the mutex or for the userland imple‐
mentation 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 prema‐
turely, with the contents of the mutex unchanged relative to the compare
value. Callers must be able to deal with such returns.
RETURN VALUESumtx_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.
EXAMPLE
void
userland_get_mutex(struct umtx *mtx)
{
int v;
for (;;) {
v = mtx->lock;
if ((v & MTX_LOCKED) == 0) {
/*
* not locked, attempt to lock.
*/
if (cmp_and_exg(&mtx->lock, v, v | MTX_LOCKED) == 0)
return;
} else {
/*
* Locked, bump the contested count and obtain the contested
* mutex.
*/
if (cmp_and_exg(&mtx->lock, v, v + 1) == 0) {
userland_get_mutex_contested(mtx);
return;
}
}
}
}
static void
userland_get_mutex_contested(struct umtx *mtx)
{
int v;
for (;;) {
v = mtx->lock;
assert(v & ~MTX_LOCKED); /* our contesting count still there */
if ((v & MTX_LOCKED) == 0) {
/*
* not locked, attempt to remove our contested count and
* lock at the same time.
*/
if (cmp_and_exg(&mtx->lock, v, (v - 1) | MTX_LOCKED) == 0)
return;
} else {
/*
* Still locked, sleep and try again.
*/
umtx_sleep(&mtx->lock, v, 0);
/*
* XXX note: if we are woken up here but do not proceed to
* attempt to obtain the mutex, we should chain the
* umtx_wakeup() along.
*/
}
}
}
void
userland_rel_mutex(struct umtx *mtx)
{
int v;
for (;;) {
v = mtx->lock;
assert(v & MTX_LOCKED); /* we still have it locked */
if (v == MTX_LOCKED) {
/*
* We hold an uncontested lock, try to set to an unlocked
* state.
*/
if (cmp_and_exg(&mtx->lock, MTX_LOCKED, 0) == 0)
return;
} else {
/*
* We hold a contested lock, unlock and wakeup exactly
* one sleeper. It is possible for this to race a new
* thread obtaining a lock, in which case any contested
* sleeper we wake up will simply go back to sleep.
*/
if (cmp_and_exg(&mtx->lock, v, v & ~MTX_LOCKED) == 0) {
umtx_wakeup(&mtx->lock, 1);
return;
}
}
}
}
ERRORS
[EBUSY] The contents of *ptr did not match value
[EWOULDBLOCK] The specified timeout occurred.
[EINTR] The umtx_sleep() call was interrupted by a signal.
[EINVAL] An invalid parameter (typically an invalid timeout)
was specified.
SEE ALSOtls(2)HISTORY
The umtx_sleep(), and umtx_wakeup() function calls first appeared in
DragonFly 1.1.
BSD February 21, 2005 BSD