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 // Blocks the calling thread until a matching call to `Post()` or 75 // `t` has passed. Returns `true` if woken (`Post()` called), 76 // `false` on timeout. 77 bool Wait(KernelTimeout t); 78 79 // Restart the caller of `Wait()` as with a normal semaphore. 80 void Post(); 81 82 // If anyone is waiting, wake them up temporarily and cause them to 83 // call `MaybeBecomeIdle()`. They will then return to waiting for a 84 // `Post()` or timeout. 85 void Poke(); 86 87 // Returns the Waiter associated with the identity. GetWaiter(base_internal::ThreadIdentity * identity)88 static Waiter* GetWaiter(base_internal::ThreadIdentity* identity) { 89 static_assert( 90 sizeof(Waiter) <= sizeof(base_internal::ThreadIdentity::WaiterState), 91 "Insufficient space for Waiter"); 92 return reinterpret_cast<Waiter*>(identity->waiter_state.data); 93 } 94 95 // How many periods to remain idle before releasing resources 96 #ifndef ABSL_HAVE_THREAD_SANITIZER 97 static constexpr int kIdlePeriods = 60; 98 #else 99 // Memory consumption under ThreadSanitizer is a serious concern, 100 // so we release resources sooner. The value of 1 leads to 1 to 2 second 101 // delay before marking a thread as idle. 102 static const int kIdlePeriods = 1; 103 #endif 104 105 private: 106 // The destructor must not be called since Mutex/CondVar 107 // can use PerThreadSem/Waiter after the thread exits. 108 // Waiter objects are embedded in ThreadIdentity objects, 109 // which are reused via a freelist and are never destroyed. 110 ~Waiter() = delete; 111 112 #if ABSL_WAITER_MODE == ABSL_WAITER_MODE_FUTEX 113 // Futexes are defined by specification to be 32-bits. 114 // Thus std::atomic<int32_t> must be just an int32_t with lockfree methods. 115 std::atomic<int32_t> futex_; 116 static_assert(sizeof(int32_t) == sizeof(futex_), "Wrong size for futex"); 117 118 #elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_CONDVAR 119 // REQUIRES: mu_ must be held. 120 void InternalCondVarPoke(); 121 122 pthread_mutex_t mu_; 123 pthread_cond_t cv_; 124 int waiter_count_; 125 int wakeup_count_; // Unclaimed wakeups. 126 127 #elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_SEM 128 sem_t sem_; 129 // This seems superfluous, but for Poke() we need to cause spurious 130 // wakeups on the semaphore. Hence we can't actually use the 131 // semaphore's count. 132 std::atomic<int> wakeups_; 133 134 #elif ABSL_WAITER_MODE == ABSL_WAITER_MODE_WIN32 135 // WinHelper - Used to define utilities for accessing the lock and 136 // condition variable storage once the types are complete. 137 class WinHelper; 138 139 // REQUIRES: WinHelper::GetLock(this) must be held. 140 void InternalCondVarPoke(); 141 142 // We can't include Windows.h in our headers, so we use aligned character 143 // buffers to define the storage of SRWLOCK and CONDITION_VARIABLE. 144 // SRW locks and condition variables do not need to be explicitly destroyed. 145 // https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-initializesrwlock 146 // https://stackoverflow.com/questions/28975958/why-does-windows-have-no-deleteconditionvariable-function-to-go-together-with 147 alignas(void*) unsigned char mu_storage_[sizeof(void*)]; 148 alignas(void*) unsigned char cv_storage_[sizeof(void*)]; 149 int waiter_count_; 150 int wakeup_count_; 151 152 #else 153 #error Unknown ABSL_WAITER_MODE 154 #endif 155 }; 156 157 } // namespace synchronization_internal 158 ABSL_NAMESPACE_END 159 } // namespace absl 160 161 #endif // ABSL_SYNCHRONIZATION_INTERNAL_WAITER_H_ 162