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/futex.h" 40 #include "absl/synchronization/internal/kernel_timeout.h" 41 42 // May be chosen at compile time via -DABSL_FORCE_WAITER_MODE=<index> 43 #define ABSL_WAITER_MODE_FUTEX 0 44 #define ABSL_WAITER_MODE_SEM 1 45 #define ABSL_WAITER_MODE_CONDVAR 2 46 #define ABSL_WAITER_MODE_WIN32 3 47 48 #if defined(ABSL_FORCE_WAITER_MODE) 49 #define ABSL_WAITER_MODE ABSL_FORCE_WAITER_MODE 50 #elif defined(_WIN32) && _WIN32_WINNT >= _WIN32_WINNT_VISTA 51 #define ABSL_WAITER_MODE ABSL_WAITER_MODE_WIN32 52 #elif defined(ABSL_INTERNAL_HAVE_FUTEX) 53 #define ABSL_WAITER_MODE ABSL_WAITER_MODE_FUTEX 54 #elif defined(ABSL_HAVE_SEMAPHORE_H) 55 #define ABSL_WAITER_MODE ABSL_WAITER_MODE_SEM 56 #else 57 #define ABSL_WAITER_MODE ABSL_WAITER_MODE_CONDVAR 58 #endif 59 60 namespace absl { 61 ABSL_NAMESPACE_BEGIN 62 namespace synchronization_internal { 63 64 // Waiter is an OS-specific semaphore. 65 class Waiter { 66 public: 67 // Prepare any data to track waits. 68 Waiter(); 69 70 // Not copyable or movable 71 Waiter(const Waiter&) = delete; 72 Waiter& operator=(const Waiter&) = delete; 73 74 // Destroy any data to track waits. 75 ~Waiter(); 76 77 // Blocks the calling thread until a matching call to `Post()` or 78 // `t` has passed. Returns `true` if woken (`Post()` called), 79 // `false` on timeout. 80 bool Wait(KernelTimeout t); 81 82 // Restart the caller of `Wait()` as with a normal semaphore. 83 void Post(); 84 85 // If anyone is waiting, wake them up temporarily and cause them to 86 // call `MaybeBecomeIdle()`. They will then return to waiting for a 87 // `Post()` or timeout. 88 void Poke(); 89 90 // Returns the Waiter associated with the identity. GetWaiter(base_internal::ThreadIdentity * identity)91 static Waiter* GetWaiter(base_internal::ThreadIdentity* identity) { 92 static_assert( 93 sizeof(Waiter) <= sizeof(base_internal::ThreadIdentity::WaiterState), 94 "Insufficient space for Waiter"); 95 return reinterpret_cast<Waiter*>(identity->waiter_state.data); 96 } 97 98 // How many periods to remain idle before releasing resources 99 #ifndef ABSL_HAVE_THREAD_SANITIZER 100 static constexpr int kIdlePeriods = 60; 101 #else 102 // Memory consumption under ThreadSanitizer is a serious concern, 103 // so we release resources sooner. The value of 1 leads to 1 to 2 second 104 // delay before marking a thread as idle. 105 static const int kIdlePeriods = 1; 106 #endif 107 108 private: 109 #if ABSL_WAITER_MODE == ABSL_WAITER_MODE_FUTEX 110 // Futexes are defined by specification to be 32-bits. 111 // Thus std::atomic<int32_t> must be just an int32_t with lockfree methods. 112 std::atomic<int32_t> futex_; 113 static_assert(sizeof(int32_t) == sizeof(futex_), "Wrong size for futex"); 114 115 #elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_CONDVAR 116 // REQUIRES: mu_ must be held. 117 void InternalCondVarPoke(); 118 119 pthread_mutex_t mu_; 120 pthread_cond_t cv_; 121 int waiter_count_; 122 int wakeup_count_; // Unclaimed wakeups. 123 124 #elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_SEM 125 sem_t sem_; 126 // This seems superfluous, but for Poke() we need to cause spurious 127 // wakeups on the semaphore. Hence we can't actually use the 128 // semaphore's count. 129 std::atomic<int> wakeups_; 130 131 #elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_WIN32 132 // WinHelper - Used to define utilities for accessing the lock and 133 // condition variable storage once the types are complete. 134 class WinHelper; 135 136 // REQUIRES: WinHelper::GetLock(this) must be held. 137 void InternalCondVarPoke(); 138 139 // We can't include Windows.h in our headers, so we use aligned charachter 140 // buffers to define the storage of SRWLOCK and CONDITION_VARIABLE. 141 alignas(void*) unsigned char mu_storage_[sizeof(void*)]; 142 alignas(void*) unsigned char cv_storage_[sizeof(void*)]; 143 int waiter_count_; 144 int wakeup_count_; 145 146 #else 147 #error Unknown ABSL_WAITER_MODE 148 #endif 149 }; 150 151 } // namespace synchronization_internal 152 ABSL_NAMESPACE_END 153 } // namespace absl 154 155 #endif // ABSL_SYNCHRONIZATION_INTERNAL_WAITER_H_ 156