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