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