diff options
author | Derek Mauro <dmauro@google.com> | 2023-03-21 07:30:38 -0700 |
---|---|---|
committer | Copybara-Service <copybara-worker@google.com> | 2023-03-21 07:31:48 -0700 |
commit | 276f88cb77dd543ae9cc4ed55c08fb5f74f405ea (patch) | |
tree | fdf03e39bcee86795f8f2515f806dcf836158bcd /absl/synchronization/internal/stdcpp_waiter.cc | |
parent | 819272485a0c06abc8d7d62b188a6f54174881cb (diff) | |
download | abseil-276f88cb77dd543ae9cc4ed55c08fb5f74f405ea.tar.gz abseil-276f88cb77dd543ae9cc4ed55c08fb5f74f405ea.tar.bz2 abseil-276f88cb77dd543ae9cc4ed55c08fb5f74f405ea.zip |
Add an implementation of Waiter that uses std::mutex/std::condition_variable
This implementation may at some point become the default on some
platforms. Currently not all platforms have widespread support for
both real absolute timeouts or real relative timeouts (here "real"
means without converting to the other timeout type which is the only
one supported by the underlying APIs). In this case we can defer to
their standard library to implement correct support.
This is not currently the default on any platform
Note: The size of WaiterState had to increase to fit the new implementation
PiperOrigin-RevId: 518266646
Change-Id: I7f246646a960d6e1b155f9de0bf2f681c5d3d245
Diffstat (limited to 'absl/synchronization/internal/stdcpp_waiter.cc')
-rw-r--r-- | absl/synchronization/internal/stdcpp_waiter.cc | 91 |
1 files changed, 91 insertions, 0 deletions
diff --git a/absl/synchronization/internal/stdcpp_waiter.cc b/absl/synchronization/internal/stdcpp_waiter.cc new file mode 100644 index 00000000..8b5d1df4 --- /dev/null +++ b/absl/synchronization/internal/stdcpp_waiter.cc @@ -0,0 +1,91 @@ +// Copyright 2023 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/synchronization/internal/stdcpp_waiter.h" + +#ifdef ABSL_INTERNAL_HAVE_STDCPP_WAITER + +#include <chrono> // NOLINT(build/c++11) +#include <condition_variable> // NOLINT(build/c++11) +#include <mutex> // NOLINT(build/c++11) + +#include "absl/base/config.h" +#include "absl/base/internal/raw_logging.h" +#include "absl/base/internal/thread_identity.h" +#include "absl/base/optimization.h" +#include "absl/synchronization/internal/kernel_timeout.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace synchronization_internal { + +#ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL +constexpr char StdcppWaiter::kName[]; +#endif + +StdcppWaiter::StdcppWaiter() : waiter_count_(0), wakeup_count_(0) {} + +bool StdcppWaiter::Wait(KernelTimeout t) { + std::unique_lock<std::mutex> lock(mu_); + ++waiter_count_; + + // Loop until we find a wakeup to consume or timeout. + // Note that, since the thread ticker is just reset, we don't need to check + // whether the thread is idle on the very first pass of the loop. + bool first_pass = true; + while (wakeup_count_ == 0) { + if (!first_pass) MaybeBecomeIdle(); + // No wakeups available, time to wait. + if (!t.has_timeout()) { + cv_.wait(lock); + } else { + auto wait_result = t.is_relative_timeout() + ? cv_.wait_for(lock, t.ToChronoDuration()) + : cv_.wait_until(lock, t.ToChronoTimePoint()); + if (wait_result == std::cv_status::timeout) { + --waiter_count_; + return false; + } + } + first_pass = false; + } + + // Consume a wakeup and we're done. + --wakeup_count_; + --waiter_count_; + return true; +} + +void StdcppWaiter::Post() { + std::lock_guard<std::mutex> lock(mu_); + ++wakeup_count_; + InternalCondVarPoke(); +} + +void StdcppWaiter::Poke() { + std::lock_guard<std::mutex> lock(mu_); + InternalCondVarPoke(); +} + +void StdcppWaiter::InternalCondVarPoke() { + if (waiter_count_ != 0) { + cv_.notify_one(); + } +} + +} // namespace synchronization_internal +ABSL_NAMESPACE_END +} // namespace absl + +#endif // ABSL_INTERNAL_HAVE_STDCPP_WAITER |