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