]>
Commit | Line | Data |
---|---|---|
f67539c2 TL |
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; | |
87 | 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> |