1 // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. 2 // This source code is licensed under both the GPLv2 (found in the 3 // COPYING file in the root directory) and Apache 2.0 License 4 // (found in the LICENSE.Apache file in the root directory). 5 6 #pragma once 7 8 #include <atomic> 9 #include <cassert> 10 #include <chrono> 11 #include <cstdint> 12 #include <limits> 13 #include <type_traits> 14 15 namespace folly { 16 namespace detail { 17 18 enum class FutexResult { 19 VALUE_CHANGED, /* futex value didn't match expected */ 20 AWOKEN, /* wakeup by matching futex wake, or spurious wakeup */ 21 INTERRUPTED, /* wakeup by interrupting signal */ 22 TIMEDOUT, /* wakeup by expiring deadline */ 23 }; 24 25 /** 26 * Futex is an atomic 32 bit unsigned integer that provides access to the 27 * futex() syscall on that value. It is templated in such a way that it 28 * can interact properly with DeterministicSchedule testing. 29 * 30 * If you don't know how to use futex(), you probably shouldn't be using 31 * this class. Even if you do know how, you should have a good reason 32 * (and benchmarks to back you up). 33 * 34 * Because of the semantics of the futex syscall, the futex family of 35 * functions are available as free functions rather than member functions 36 */ 37 template <template <typename> class Atom = std::atomic> 38 using Futex = Atom<std::uint32_t>; 39 40 /** 41 * Puts the thread to sleep if this->load() == expected. Returns true when 42 * it is returning because it has consumed a wake() event, false for any 43 * other return (signal, this->load() != expected, or spurious wakeup). 44 */ 45 template <typename Futex> 46 FutexResult 47 futexWait(const Futex* futex, uint32_t expected, uint32_t waitMask = -1); 48 49 /** 50 * Similar to futexWait but also accepts a deadline until when the wait call 51 * may block. 52 * 53 * Optimal clock types: std::chrono::system_clock, std::chrono::steady_clock. 54 * NOTE: On some systems steady_clock is just an alias for system_clock, 55 * and is not actually steady. 56 * 57 * For any other clock type, now() will be invoked twice. 58 */ 59 template <typename Futex, class Clock, class Duration> 60 FutexResult futexWaitUntil( 61 const Futex* futex, 62 uint32_t expected, 63 std::chrono::time_point<Clock, Duration> const& deadline, 64 uint32_t waitMask = -1); 65 66 /** 67 * Wakes up to count waiters where (waitMask & wakeMask) != 0, returning the 68 * number of awoken threads, or -1 if an error occurred. Note that when 69 * constructing a concurrency primitive that can guard its own destruction, it 70 * is likely that you will want to ignore EINVAL here (as well as making sure 71 * that you never touch the object after performing the memory store that is 72 * the linearization point for unlock or control handoff). See 73 * https://sourceware.org/bugzilla/show_bug.cgi?id=13690 74 */ 75 template <typename Futex> 76 int futexWake( 77 const Futex* futex, 78 int count = std::numeric_limits<int>::max(), 79 uint32_t wakeMask = -1); 80 81 /** A std::atomic subclass that can be used to force Futex to emulate 82 * the underlying futex() syscall. This is primarily useful to test or 83 * benchmark the emulated implementation on systems that don't need it. */ 84 template <typename T> 85 struct EmulatedFutexAtomic : public std::atomic<T> { 86 EmulatedFutexAtomic() noexcept = default; EmulatedFutexAtomicEmulatedFutexAtomic87 constexpr /* implicit */ EmulatedFutexAtomic(T init) noexcept 88 : std::atomic<T>(init) {} 89 // It doesn't copy or move 90 EmulatedFutexAtomic(EmulatedFutexAtomic&& rhs) = delete; 91 }; 92 93 } // namespace detail 94 } // namespace folly 95 96 #include <folly/detail/Futex-inl.h> 97