[MemProf] Templatize CallStackRadixTreeBuilder (NFC) (#117014)
[llvm-project.git] / libc / src / __support / threads / linux / futex_utils.h
blob943a99ab38c8ca917829e3d59f054b75b626a9a9
1 //===--- Futex Wrapper ------------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
9 #ifndef LLVM_LIBC_SRC___SUPPORT_THREADS_LINUX_FUTEX_UTILS_H
10 #define LLVM_LIBC_SRC___SUPPORT_THREADS_LINUX_FUTEX_UTILS_H
12 #include "src/__support/CPP/atomic.h"
13 #include "src/__support/CPP/limits.h"
14 #include "src/__support/CPP/optional.h"
15 #include "src/__support/OSUtil/syscall.h"
16 #include "src/__support/macros/attributes.h"
17 #include "src/__support/macros/config.h"
18 #include "src/__support/threads/linux/futex_word.h"
19 #include "src/__support/time/linux/abs_timeout.h"
20 #include <linux/errno.h>
21 #include <linux/futex.h>
23 namespace LIBC_NAMESPACE_DECL {
24 class Futex : public cpp::Atomic<FutexWordType> {
25 public:
26 using Timeout = internal::AbsTimeout;
27 LIBC_INLINE constexpr Futex(FutexWordType value)
28 : cpp::Atomic<FutexWordType>(value) {}
29 LIBC_INLINE Futex &operator=(FutexWordType value) {
30 cpp::Atomic<FutexWordType>::store(value);
31 return *this;
33 LIBC_INLINE long wait(FutexWordType expected,
34 cpp::optional<Timeout> timeout = cpp::nullopt,
35 bool is_shared = false) {
36 // use bitset variants to enforce abs_time
37 uint32_t op = is_shared ? FUTEX_WAIT_BITSET : FUTEX_WAIT_BITSET_PRIVATE;
38 if (timeout && timeout->is_realtime()) {
39 op |= FUTEX_CLOCK_REALTIME;
41 for (;;) {
42 if (this->load(cpp::MemoryOrder::RELAXED) != expected)
43 return 0;
45 long ret = syscall_impl<long>(
46 /* syscall number */ FUTEX_SYSCALL_ID,
47 /* futex address */ this,
48 /* futex operation */ op,
49 /* expected value */ expected,
50 /* timeout */ timeout ? &timeout->get_timespec() : nullptr,
51 /* ignored */ nullptr,
52 /* bitset */ FUTEX_BITSET_MATCH_ANY);
54 // continue waiting if interrupted; otherwise return the result
55 // which should normally be 0 or -ETIMEOUT
56 if (ret == -EINTR)
57 continue;
59 return ret;
62 LIBC_INLINE long notify_one(bool is_shared = false) {
63 return syscall_impl<long>(
64 /* syscall number */ FUTEX_SYSCALL_ID,
65 /* futex address */ this,
66 /* futex operation */ is_shared ? FUTEX_WAKE : FUTEX_WAKE_PRIVATE,
67 /* wake up limit */ 1,
68 /* ignored */ nullptr,
69 /* ignored */ nullptr,
70 /* ignored */ 0);
72 LIBC_INLINE long notify_all(bool is_shared = false) {
73 return syscall_impl<long>(
74 /* syscall number */ FUTEX_SYSCALL_ID,
75 /* futex address */ this,
76 /* futex operation */ is_shared ? FUTEX_WAKE : FUTEX_WAKE_PRIVATE,
77 /* wake up limit */ cpp::numeric_limits<int>::max(),
78 /* ignored */ nullptr,
79 /* ignored */ nullptr,
80 /* ignored */ 0);
84 static_assert(__is_standard_layout(Futex),
85 "Futex must be a standard layout type.");
86 } // namespace LIBC_NAMESPACE_DECL
88 #endif // LLVM_LIBC_SRC___SUPPORT_THREADS_LINUX_FUTEX_UTILS_H