• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/threads/linux/futex_word.h"
18 #include "src/__support/time/linux/abs_timeout.h"
19 #include <linux/errno.h>
20 #include <linux/futex.h>
21 
22 namespace LIBC_NAMESPACE {
23 class Futex : public cpp::Atomic<FutexWordType> {
24 public:
25   using Timeout = internal::AbsTimeout;
Futex(FutexWordType value)26   LIBC_INLINE constexpr Futex(FutexWordType value)
27       : cpp::Atomic<FutexWordType>(value) {}
28   LIBC_INLINE Futex &operator=(FutexWordType value) {
29     cpp::Atomic<FutexWordType>::store(value);
30     return *this;
31   }
32   LIBC_INLINE long wait(FutexWordType expected,
33                         cpp::optional<Timeout> timeout = cpp::nullopt,
34                         bool is_shared = false) {
35     // use bitset variants to enforce abs_time
36     uint32_t op = is_shared ? FUTEX_WAIT_BITSET : FUTEX_WAIT_BITSET_PRIVATE;
37     if (timeout && timeout->is_realtime()) {
38       op |= FUTEX_CLOCK_REALTIME;
39     }
40     for (;;) {
41       if (this->load(cpp::MemoryOrder::RELAXED) != expected)
42         return 0;
43 
44       long ret = syscall_impl<long>(
45           /* syscall number */ FUTEX_SYSCALL_ID,
46           /* futex address */ this,
47           /* futex operation  */ op,
48           /* expected value */ expected,
49           /* timeout */ timeout ? &timeout->get_timespec() : nullptr,
50           /* ignored */ nullptr,
51           /* bitset */ FUTEX_BITSET_MATCH_ANY);
52 
53       // continue waiting if interrupted; otherwise return the result
54       // which should normally be 0 or -ETIMEOUT
55       if (ret == -EINTR)
56         continue;
57 
58       return ret;
59     }
60   }
61   LIBC_INLINE long notify_one(bool is_shared = false) {
62     return syscall_impl<long>(
63         /* syscall number */ FUTEX_SYSCALL_ID,
64         /* futex address */ this,
65         /* futex operation  */ is_shared ? FUTEX_WAKE : FUTEX_WAKE_PRIVATE,
66         /* wake up limit */ 1,
67         /* ignored */ nullptr,
68         /* ignored */ nullptr,
69         /* ignored */ 0);
70   }
71   LIBC_INLINE long notify_all(bool is_shared = false) {
72     return syscall_impl<long>(
73         /* syscall number */ FUTEX_SYSCALL_ID,
74         /* futex address */ this,
75         /* futex operation  */ is_shared ? FUTEX_WAKE : FUTEX_WAKE_PRIVATE,
76         /* wake up limit */ cpp::numeric_limits<int>::max(),
77         /* ignored */ nullptr,
78         /* ignored */ nullptr,
79         /* ignored */ 0);
80   }
81 };
82 
83 static_assert(__is_standard_layout(Futex),
84               "Futex must be a standard layout type.");
85 } // namespace LIBC_NAMESPACE
86 
87 #endif // LLVM_LIBC_SRC___SUPPORT_THREADS_LINUX_FUTEX_UTILS_H
88