#ifndef LLVM_LIBC_SRC___SUPPORT_THREADS_LINUX_FUTEX_UTILS_H
#define LLVM_LIBC_SRC___SUPPORT_THREADS_LINUX_FUTEX_UTILS_H
#include "src/__support/CPP/atomic.h"
#include "src/__support/CPP/limits.h"
#include "src/__support/CPP/optional.h"
#include "src/__support/OSUtil/syscall.h"
#include "src/__support/macros/attributes.h"
#include "src/__support/macros/config.h"
#include "src/__support/threads/linux/futex_word.h"
#include "src/__support/time/linux/abs_timeout.h"
#include <linux/errno.h>
#include <linux/futex.h>
namespace LIBC_NAMESPACE_DECL {
class Futex : public cpp::Atomic<FutexWordType> {
public:
using Timeout = internal::AbsTimeout;
LIBC_INLINE constexpr Futex(FutexWordType value)
: cpp::Atomic<FutexWordType>(value) {}
LIBC_INLINE Futex &operator=(FutexWordType value) {
cpp::Atomic<FutexWordType>::store(value);
return *this;
}
LIBC_INLINE long wait(FutexWordType expected,
cpp::optional<Timeout> timeout = cpp::nullopt,
bool is_shared = false) {
uint32_t op = is_shared ? FUTEX_WAIT_BITSET : FUTEX_WAIT_BITSET_PRIVATE;
if (timeout && timeout->is_realtime()) {
op |= FUTEX_CLOCK_REALTIME;
}
for (;;) {
if (this->load(cpp::MemoryOrder::RELAXED) != expected)
return 0;
long ret = syscall_impl<long>(
FUTEX_SYSCALL_ID,
this,
op,
expected,
timeout ? &timeout->get_timespec() : nullptr,
nullptr,
FUTEX_BITSET_MATCH_ANY);
if (ret == -EINTR)
continue;
return ret;
}
}
LIBC_INLINE long notify_one(bool is_shared = false) {
return syscall_impl<long>(
FUTEX_SYSCALL_ID,
this,
is_shared ? FUTEX_WAKE : FUTEX_WAKE_PRIVATE,
1,
nullptr,
nullptr,
0);
}
LIBC_INLINE long notify_all(bool is_shared = false) {
return syscall_impl<long>(
FUTEX_SYSCALL_ID,
this,
is_shared ? FUTEX_WAKE : FUTEX_WAKE_PRIVATE,
cpp::numeric_limits<int>::max(),
nullptr,
nullptr,
0);
}
};
static_assert(__is_standard_layout(Futex),
"Futex must be a standard layout type.");
}
#endif