HelenOS sources
This source file includes following definitions.
- futex_destroy
- futex_allocate_waitq
- futex_down_composable
- futex_up
- futex_down_timeout
- futex_trydown
- futex_down
#ifndef _LIBC_FUTEX_H_
#define _LIBC_FUTEX_H_
#include <assert.h>
#include <stdatomic.h>
#include <errno.h>
#include <libc.h>
#include <time.h>
#include <fibril.h>
#include <abi/cap.h>
#include <abi/synch.h>
typedef struct futex {
volatile atomic_int val;
volatile cap_waitq_handle_t whandle;
#ifdef CONFIG_DEBUG_FUTEX
_Atomic(fibril_t *) owner;
#endif
} futex_t;
extern errno_t futex_initialize(futex_t *futex, int value);
static inline errno_t futex_destroy(futex_t *futex)
{
if (futex->whandle) {
errno_t rc;
rc = __SYSCALL1(SYS_WAITQ_DESTROY, (sysarg_t) futex->whandle);
futex->whandle = CAP_NIL;
return rc;
}
return EOK;
}
#ifdef CONFIG_DEBUG_FUTEX
void __futex_assert_is_locked(futex_t *, const char *);
void __futex_assert_is_not_locked(futex_t *, const char *);
void __futex_lock(futex_t *, const char *);
void __futex_unlock(futex_t *, const char *);
bool __futex_trylock(futex_t *, const char *);
void __futex_give_to(futex_t *, void *, const char *);
#define futex_lock(futex) __futex_lock((futex), #futex)
#define futex_unlock(futex) __futex_unlock((futex), #futex)
#define futex_trylock(futex) __futex_trylock((futex), #futex)
#define futex_give_to(futex, new_owner) __futex_give_to((futex), (new_owner), #futex)
#define futex_assert_is_locked(futex) __futex_assert_is_locked((futex), #futex)
#define futex_assert_is_not_locked(futex) __futex_assert_is_not_locked((futex), #futex)
#else
#define futex_lock(fut) (void) futex_down((fut))
#define futex_trylock(fut) futex_trydown((fut))
#define futex_unlock(fut) (void) futex_up((fut))
#define futex_give_to(fut, owner) ((void)0)
#define futex_assert_is_locked(fut) assert(atomic_load_explicit(&(fut)->val, memory_order_relaxed) <= 0)
#define futex_assert_is_not_locked(fut) ((void)0)
#endif
static inline errno_t futex_allocate_waitq(futex_t *futex)
{
return __SYSCALL1(SYS_WAITQ_CREATE, (sysarg_t) &futex->whandle);
}
static inline errno_t futex_down_composable(futex_t *futex,
const struct timespec *expires)
{
assert(futex->whandle != CAP_NIL);
if (atomic_fetch_sub_explicit(&futex->val, 1, memory_order_acquire) > 0)
return EOK;
usec_t timeout;
if (!expires) {
timeout = 0;
} else {
if (expires->tv_sec == 0) {
timeout = 1;
} else {
struct timespec tv;
getuptime(&tv);
timeout = ts_gteq(&tv, expires) ? 1 :
NSEC2USEC(ts_sub_diff(expires, &tv));
}
assert(timeout > 0);
}
return __SYSCALL3(SYS_WAITQ_SLEEP, (sysarg_t) futex->whandle,
(sysarg_t) timeout, (sysarg_t) SYNCH_FLAGS_FUTEX);
}
static inline errno_t futex_up(futex_t *futex)
{
if (atomic_fetch_add_explicit(&futex->val, 1, memory_order_release) < 0)
return __SYSCALL1(SYS_WAITQ_WAKEUP, (sysarg_t) futex->whandle);
return EOK;
}
static inline errno_t futex_down_timeout(futex_t *futex,
const struct timespec *expires)
{
errno_t rc = futex_down_composable(futex, expires);
if (rc != EOK)
futex_up(futex);
return rc;
}
static inline bool futex_trydown(futex_t *futex)
{
struct timespec tv = { .tv_sec = 0, .tv_nsec = 0 };
return futex_down_timeout(futex, &tv) == EOK;
}
static inline errno_t futex_down(futex_t *futex)
{
return futex_down_timeout(futex, NULL);
}
#endif
HelenOS homepage, sources at GitHub