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