1 // Copyright 2017 The Abseil Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // 15 16 #ifndef ABSL_SYNCHRONIZATION_INTERNAL_WAITER_H_ 17 #define ABSL_SYNCHRONIZATION_INTERNAL_WAITER_H_ 18 19 #include "absl/base/config.h" 20 21 #ifdef _WIN32 22 #include <sdkddkver.h> 23 #else 24 #include <pthread.h> 25 #endif 26 27 #ifdef __linux__ 28 #include <linux/futex.h> 29 #endif 30 31 #ifdef ABSL_HAVE_SEMAPHORE_H 32 #include <semaphore.h> 33 #endif 34 35 #include <atomic> 36 #include <cstdint> 37 38 #include "absl/base/internal/thread_identity.h" 39 #include "absl/synchronization/internal/kernel_timeout.h" 40 41 // May be chosen at compile time via -DABSL_FORCE_WAITER_MODE=<index> 42 #define ABSL_WAITER_MODE_FUTEX 0 43 #define ABSL_WAITER_MODE_SEM 1 44 #define ABSL_WAITER_MODE_CONDVAR 2 45 #define ABSL_WAITER_MODE_WIN32 3 46 47 #if defined(ABSL_FORCE_WAITER_MODE) 48 #define ABSL_WAITER_MODE ABSL_FORCE_WAITER_MODE 49 #elif defined(_WIN32) && _WIN32_WINNT >= _WIN32_WINNT_VISTA 50 #define ABSL_WAITER_MODE ABSL_WAITER_MODE_WIN32 51 #elif defined(__BIONIC__) 52 // Bionic supports all the futex operations we need even when some of the futex 53 // definitions are missing. 54 #define ABSL_WAITER_MODE ABSL_WAITER_MODE_FUTEX 55 #elif defined(__linux__) && defined(FUTEX_CLOCK_REALTIME) 56 // FUTEX_CLOCK_REALTIME requires Linux >= 2.6.28. 57 #define ABSL_WAITER_MODE ABSL_WAITER_MODE_FUTEX 58 #elif defined(ABSL_HAVE_SEMAPHORE_H) 59 #define ABSL_WAITER_MODE ABSL_WAITER_MODE_SEM 60 #else 61 #define ABSL_WAITER_MODE ABSL_WAITER_MODE_CONDVAR 62 #endif 63 64 namespace absl { 65 ABSL_NAMESPACE_BEGIN 66 namespace synchronization_internal { 67 68 // Waiter is an OS-specific semaphore. 69 class Waiter { 70 public: 71 // Prepare any data to track waits. 72 Waiter(); 73 74 // Not copyable or movable 75 Waiter(const Waiter&) = delete; 76 Waiter& operator=(const Waiter&) = delete; 77 78 // Destroy any data to track waits. 79 ~Waiter(); 80 81 // Blocks the calling thread until a matching call to `Post()` or 82 // `t` has passed. Returns `true` if woken (`Post()` called), 83 // `false` on timeout. 84 bool Wait(KernelTimeout t); 85 86 // Restart the caller of `Wait()` as with a normal semaphore. 87 void Post(); 88 89 // If anyone is waiting, wake them up temporarily and cause them to 90 // call `MaybeBecomeIdle()`. They will then return to waiting for a 91 // `Post()` or timeout. 92 void Poke(); 93 94 // Returns the Waiter associated with the identity. GetWaiter(base_internal::ThreadIdentity * identity)95 static Waiter* GetWaiter(base_internal::ThreadIdentity* identity) { 96 static_assert( 97 sizeof(Waiter) <= sizeof(base_internal::ThreadIdentity::WaiterState), 98 "Insufficient space for Waiter"); 99 return reinterpret_cast<Waiter*>(identity->waiter_state.data); 100 } 101 102 // How many periods to remain idle before releasing resources 103 #ifndef ABSL_HAVE_THREAD_SANITIZER 104 static constexpr int kIdlePeriods = 60; 105 #else 106 // Memory consumption under ThreadSanitizer is a serious concern, 107 // so we release resources sooner. The value of 1 leads to 1 to 2 second 108 // delay before marking a thread as idle. 109 static const int kIdlePeriods = 1; 110 #endif 111 112 private: 113 #if ABSL_WAITER_MODE == ABSL_WAITER_MODE_FUTEX 114 // Futexes are defined by specification to be 32-bits. 115 // Thus std::atomic<int32_t> must be just an int32_t with lockfree methods. 116 std::atomic<int32_t> futex_; 117 static_assert(sizeof(int32_t) == sizeof(futex_), "Wrong size for futex"); 118 119 #elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_CONDVAR 120 // REQUIRES: mu_ must be held. 121 void InternalCondVarPoke(); 122 123 pthread_mutex_t mu_; 124 pthread_cond_t cv_; 125 int waiter_count_; 126 int wakeup_count_; // Unclaimed wakeups. 127 128 #elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_SEM 129 sem_t sem_; 130 // This seems superfluous, but for Poke() we need to cause spurious 131 // wakeups on the semaphore. Hence we can't actually use the 132 // semaphore's count. 133 std::atomic<int> wakeups_; 134 135 #elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_WIN32 136 // WinHelper - Used to define utilities for accessing the lock and 137 // condition variable storage once the types are complete. 138 class WinHelper; 139 140 // REQUIRES: WinHelper::GetLock(this) must be held. 141 void InternalCondVarPoke(); 142 143 // We can't include Windows.h in our headers, so we use aligned charachter 144 // buffers to define the storage of SRWLOCK and CONDITION_VARIABLE. 145 alignas(void*) unsigned char mu_storage_[sizeof(void*)]; 146 alignas(void*) unsigned char cv_storage_[sizeof(void*)]; 147 int waiter_count_; 148 int wakeup_count_; 149 150 #else 151 #error Unknown ABSL_WAITER_MODE 152 #endif 153 }; 154 155 } // namespace synchronization_internal 156 ABSL_NAMESPACE_END 157 } // namespace absl 158 159 #endif // ABSL_SYNCHRONIZATION_INTERNAL_WAITER_H_ 160