1 // Copyright 2023 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_BASE_H_ 17 #define ABSL_SYNCHRONIZATION_INTERNAL_WAITER_BASE_H_ 18 19 #include "absl/base/config.h" 20 #include "absl/base/internal/thread_identity.h" 21 #include "absl/synchronization/internal/kernel_timeout.h" 22 23 namespace absl { 24 ABSL_NAMESPACE_BEGIN 25 namespace synchronization_internal { 26 27 // `Waiter` is a platform specific semaphore implementation that `PerThreadSem` 28 // waits on to implement blocking in `absl::Mutex`. Implementations should 29 // inherit from `WaiterCrtp` and must implement `Wait()`, `Post()`, and `Poke()` 30 // as described in `WaiterBase`. `waiter.h` selects the implementation and uses 31 // static-dispatch for performance. 32 class WaiterBase { 33 public: 34 WaiterBase() = default; 35 36 // Not copyable or movable 37 WaiterBase(const WaiterBase&) = delete; 38 WaiterBase& operator=(const WaiterBase&) = delete; 39 40 // Blocks the calling thread until a matching call to `Post()` or 41 // `t` has passed. Returns `true` if woken (`Post()` called), 42 // `false` on timeout. 43 // 44 // bool Wait(KernelTimeout t); 45 46 // Restart the caller of `Wait()` as with a normal semaphore. 47 // 48 // void Post(); 49 50 // If anyone is waiting, wake them up temporarily and cause them to 51 // call `MaybeBecomeIdle()`. They will then return to waiting for a 52 // `Post()` or timeout. 53 // 54 // void Poke(); 55 56 // Returns the name of this implementation. Used only for debugging. 57 // 58 // static constexpr char kName[]; 59 60 // How many periods to remain idle before releasing resources 61 #ifndef ABSL_HAVE_THREAD_SANITIZER 62 static constexpr int kIdlePeriods = 60; 63 #else 64 // Memory consumption under ThreadSanitizer is a serious concern, 65 // so we release resources sooner. The value of 1 leads to 1 to 2 second 66 // delay before marking a thread as idle. 67 static constexpr int kIdlePeriods = 1; 68 #endif 69 70 protected: 71 static void MaybeBecomeIdle(); 72 }; 73 74 template <typename T> 75 class WaiterCrtp : public WaiterBase { 76 public: 77 // Returns the Waiter associated with the identity. GetWaiter(base_internal::ThreadIdentity * identity)78 static T* GetWaiter(base_internal::ThreadIdentity* identity) { 79 static_assert( 80 sizeof(T) <= sizeof(base_internal::ThreadIdentity::WaiterState), 81 "Insufficient space for Waiter"); 82 return reinterpret_cast<T*>(identity->waiter_state.data); 83 } 84 }; 85 86 } // namespace synchronization_internal 87 ABSL_NAMESPACE_END 88 } // namespace absl 89 90 #endif // ABSL_SYNCHRONIZATION_INTERNAL_WAITER_BASE_H_ 91