xref: /aosp_15_r20/external/llvm-libc/src/__support/threads/linux/futex_utils.h (revision 71db0c75aadcf003ffe3238005f61d7618a3fead)
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 //===----------------------------------------------------------------------===//
8 
9 #ifndef LLVM_LIBC_SRC___SUPPORT_THREADS_LINUX_FUTEX_UTILS_H
10 #define LLVM_LIBC_SRC___SUPPORT_THREADS_LINUX_FUTEX_UTILS_H
11 
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>
22 
23 namespace LIBC_NAMESPACE_DECL {
24 class Futex : public cpp::Atomic<FutexWordType> {
25 public:
26   using Timeout = internal::AbsTimeout;
Futex(FutexWordType value)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;
32   }
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;
40     }
41     for (;;) {
42       if (this->load(cpp::MemoryOrder::RELAXED) != expected)
43         return 0;
44 
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);
53 
54       // continue waiting if interrupted; otherwise return the result
55       // which should normally be 0 or -ETIMEOUT
56       if (ret == -EINTR)
57         continue;
58 
59       return ret;
60     }
61   }
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);
71   }
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);
81   }
82 };
83 
84 static_assert(__is_standard_layout(Futex),
85               "Futex must be a standard layout type.");
86 } // namespace LIBC_NAMESPACE_DECL
87 
88 #endif // LLVM_LIBC_SRC___SUPPORT_THREADS_LINUX_FUTEX_UTILS_H
89