- f0a03a750a36dfbd7ab06d2913430ed5f988fd68 Add absl::RegisterSymbolizer() to mutex_nonprod.cc for AP... by Derek Mauro <dmauro@google.com> - f34a2ee35b4f6b321c570c51b0c381647176df63 Add the async signal-safe Symbolizer to Abseil. by Derek Mauro <dmauro@google.com> - 6a29ec2d6dc080691f6d32e1982201d1d173bdb3 Document preferred placement of ABSL_CONST_INIT attribute... by Abseil Team <absl-team@google.com> - 6f04ed6aa9c19bd717f0e8f422a97f3e3368cf30 Internal change. by Abseil Team <absl-team@google.com> - 0af9a330aff8fc0b41dcb3fe519930c36b01a9ef Declare absl::raw_logging_internal::SafeWriteToStderr in ... by Abseil Team <absl-team@google.com> - 223ff26745d31dfb4b59c36f3dee5441506af3c2 Fix ABSL_ARRAYSIZE() to handle rvalues. by Xiaoyi Zhang <zhangxy@google.com> GitOrigin-RevId: f0a03a750a36dfbd7ab06d2913430ed5f988fd68 Change-Id: I491f9cc81ca3ee078fb737cbf8fa9bf6a730eee1
		
			
				
	
	
		
			318 lines
		
	
	
	
		
			8.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			318 lines
		
	
	
	
		
			8.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // Copyright 2017 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
 | |
| //
 | |
| //      http://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.
 | |
| 
 | |
| // Implementation of a small subset of Mutex and CondVar functionality
 | |
| // for platforms where the production implementation hasn't been fully
 | |
| // ported yet.
 | |
| 
 | |
| #include "absl/synchronization/mutex.h"
 | |
| 
 | |
| #if defined(_WIN32)
 | |
| #include <chrono>  // NOLINT(build/c++11)
 | |
| #else
 | |
| #include <sys/time.h>
 | |
| #include <time.h>
 | |
| #endif
 | |
| 
 | |
| #include <algorithm>
 | |
| 
 | |
| #include "absl/base/internal/raw_logging.h"
 | |
| #include "absl/time/time.h"
 | |
| 
 | |
| namespace absl {
 | |
| namespace synchronization_internal {
 | |
| 
 | |
| namespace {
 | |
| 
 | |
| // Return the current time plus the timeout.
 | |
| absl::Time DeadlineFromTimeout(absl::Duration timeout) {
 | |
|   return absl::Now() + timeout;
 | |
| }
 | |
| 
 | |
| // Limit the deadline to a positive, 32-bit time_t value to accommodate
 | |
| // implementation restrictions.  This also deals with InfinitePast and
 | |
| // InfiniteFuture.
 | |
| absl::Time LimitedDeadline(absl::Time deadline) {
 | |
|   deadline = std::max(absl::FromTimeT(0), deadline);
 | |
|   deadline = std::min(deadline, absl::FromTimeT(0x7fffffff));
 | |
|   return deadline;
 | |
| }
 | |
| 
 | |
| }  // namespace
 | |
| 
 | |
| #if defined(_WIN32)
 | |
| 
 | |
| MutexImpl::MutexImpl() {}
 | |
| 
 | |
| MutexImpl::~MutexImpl() {
 | |
|   if (locked_) {
 | |
|     std_mutex_.unlock();
 | |
|   }
 | |
| }
 | |
| 
 | |
| void MutexImpl::Lock() {
 | |
|   std_mutex_.lock();
 | |
|   locked_ = true;
 | |
| }
 | |
| 
 | |
| bool MutexImpl::TryLock() {
 | |
|   bool locked = std_mutex_.try_lock();
 | |
|   if (locked) locked_ = true;
 | |
|   return locked;
 | |
| }
 | |
| 
 | |
| void MutexImpl::Unlock() {
 | |
|   locked_ = false;
 | |
|   released_.SignalAll();
 | |
|   std_mutex_.unlock();
 | |
| }
 | |
| 
 | |
| CondVarImpl::CondVarImpl() {}
 | |
| 
 | |
| CondVarImpl::~CondVarImpl() {}
 | |
| 
 | |
| void CondVarImpl::Signal() { std_cv_.notify_one(); }
 | |
| 
 | |
| void CondVarImpl::SignalAll() { std_cv_.notify_all(); }
 | |
| 
 | |
| void CondVarImpl::Wait(MutexImpl* mu) {
 | |
|   mu->released_.SignalAll();
 | |
|   std_cv_.wait(mu->std_mutex_);
 | |
| }
 | |
| 
 | |
| bool CondVarImpl::WaitWithDeadline(MutexImpl* mu, absl::Time deadline) {
 | |
|   mu->released_.SignalAll();
 | |
|   time_t when = ToTimeT(deadline);
 | |
|   int64_t nanos = ToInt64Nanoseconds(deadline - absl::FromTimeT(when));
 | |
|   std::chrono::system_clock::time_point deadline_tp =
 | |
|       std::chrono::system_clock::from_time_t(when) +
 | |
|       std::chrono::duration_cast<std::chrono::system_clock::duration>(
 | |
|           std::chrono::nanoseconds(nanos));
 | |
|   auto deadline_since_epoch =
 | |
|       std::chrono::duration_cast<std::chrono::duration<double>>(
 | |
|           deadline_tp - std::chrono::system_clock::from_time_t(0));
 | |
|   return std_cv_.wait_until(mu->std_mutex_, deadline_tp) ==
 | |
|          std::cv_status::timeout;
 | |
| }
 | |
| 
 | |
| #else  // ! _WIN32
 | |
| 
 | |
| MutexImpl::MutexImpl() {
 | |
|   ABSL_RAW_CHECK(pthread_mutex_init(&pthread_mutex_, nullptr) == 0,
 | |
|                  "pthread error");
 | |
| }
 | |
| 
 | |
| MutexImpl::~MutexImpl() {
 | |
|   if (locked_) {
 | |
|     ABSL_RAW_CHECK(pthread_mutex_unlock(&pthread_mutex_) == 0, "pthread error");
 | |
|   }
 | |
|   ABSL_RAW_CHECK(pthread_mutex_destroy(&pthread_mutex_) == 0, "pthread error");
 | |
| }
 | |
| 
 | |
| void MutexImpl::Lock() {
 | |
|   ABSL_RAW_CHECK(pthread_mutex_lock(&pthread_mutex_) == 0, "pthread error");
 | |
|   locked_ = true;
 | |
| }
 | |
| 
 | |
| bool MutexImpl::TryLock() {
 | |
|   bool locked = (0 == pthread_mutex_trylock(&pthread_mutex_));
 | |
|   if (locked) locked_ = true;
 | |
|   return locked;
 | |
| }
 | |
| 
 | |
| void MutexImpl::Unlock() {
 | |
|   locked_ = false;
 | |
|   released_.SignalAll();
 | |
|   ABSL_RAW_CHECK(pthread_mutex_unlock(&pthread_mutex_) == 0, "pthread error");
 | |
| }
 | |
| 
 | |
| CondVarImpl::CondVarImpl() {
 | |
|   ABSL_RAW_CHECK(pthread_cond_init(&pthread_cv_, nullptr) == 0,
 | |
|                  "pthread error");
 | |
| }
 | |
| 
 | |
| CondVarImpl::~CondVarImpl() {
 | |
|   ABSL_RAW_CHECK(pthread_cond_destroy(&pthread_cv_) == 0, "pthread error");
 | |
| }
 | |
| 
 | |
| void CondVarImpl::Signal() {
 | |
|   ABSL_RAW_CHECK(pthread_cond_signal(&pthread_cv_) == 0, "pthread error");
 | |
| }
 | |
| 
 | |
| void CondVarImpl::SignalAll() {
 | |
|   ABSL_RAW_CHECK(pthread_cond_broadcast(&pthread_cv_) == 0, "pthread error");
 | |
| }
 | |
| 
 | |
| void CondVarImpl::Wait(MutexImpl* mu) {
 | |
|   mu->released_.SignalAll();
 | |
|   ABSL_RAW_CHECK(pthread_cond_wait(&pthread_cv_, &mu->pthread_mutex_) == 0,
 | |
|                  "pthread error");
 | |
| }
 | |
| 
 | |
| bool CondVarImpl::WaitWithDeadline(MutexImpl* mu, absl::Time deadline) {
 | |
|   mu->released_.SignalAll();
 | |
|   struct timespec ts = ToTimespec(deadline);
 | |
|   int rc = pthread_cond_timedwait(&pthread_cv_, &mu->pthread_mutex_, &ts);
 | |
|   if (rc == ETIMEDOUT) return true;
 | |
|   ABSL_RAW_CHECK(rc == 0, "pthread error");
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| #endif  // ! _WIN32
 | |
| 
 | |
| void MutexImpl::Await(const Condition& cond) {
 | |
|   if (cond.Eval()) return;
 | |
|   released_.SignalAll();
 | |
|   do {
 | |
|     released_.Wait(this);
 | |
|   } while (!cond.Eval());
 | |
| }
 | |
| 
 | |
| bool MutexImpl::AwaitWithDeadline(const Condition& cond, absl::Time deadline) {
 | |
|   if (cond.Eval()) return true;
 | |
|   released_.SignalAll();
 | |
|   while (true) {
 | |
|     if (released_.WaitWithDeadline(this, deadline)) return false;
 | |
|     if (cond.Eval()) return true;
 | |
|   }
 | |
| }
 | |
| 
 | |
| }  // namespace synchronization_internal
 | |
| 
 | |
| Mutex::Mutex() {}
 | |
| 
 | |
| Mutex::~Mutex() {}
 | |
| 
 | |
| void Mutex::Lock() { impl()->Lock(); }
 | |
| 
 | |
| void Mutex::Unlock() { impl()->Unlock(); }
 | |
| 
 | |
| bool Mutex::TryLock() { return impl()->TryLock(); }
 | |
| 
 | |
| void Mutex::ReaderLock() { Lock(); }
 | |
| 
 | |
| void Mutex::ReaderUnlock() { Unlock(); }
 | |
| 
 | |
| void Mutex::Await(const Condition& cond) { impl()->Await(cond); }
 | |
| 
 | |
| void Mutex::LockWhen(const Condition& cond) {
 | |
|   Lock();
 | |
|   Await(cond);
 | |
| }
 | |
| 
 | |
| bool Mutex::AwaitWithDeadline(const Condition& cond, absl::Time deadline) {
 | |
|   return impl()->AwaitWithDeadline(
 | |
|       cond, synchronization_internal::LimitedDeadline(deadline));
 | |
| }
 | |
| 
 | |
| bool Mutex::AwaitWithTimeout(const Condition& cond, absl::Duration timeout) {
 | |
|   return AwaitWithDeadline(
 | |
|       cond, synchronization_internal::DeadlineFromTimeout(timeout));
 | |
| }
 | |
| 
 | |
| bool Mutex::LockWhenWithDeadline(const Condition& cond, absl::Time deadline) {
 | |
|   Lock();
 | |
|   return AwaitWithDeadline(cond, deadline);
 | |
| }
 | |
| 
 | |
| bool Mutex::LockWhenWithTimeout(const Condition& cond, absl::Duration timeout) {
 | |
|   return LockWhenWithDeadline(
 | |
|       cond, synchronization_internal::DeadlineFromTimeout(timeout));
 | |
| }
 | |
| 
 | |
| void Mutex::ReaderLockWhen(const Condition& cond) {
 | |
|   ReaderLock();
 | |
|   Await(cond);
 | |
| }
 | |
| 
 | |
| bool Mutex::ReaderLockWhenWithTimeout(const Condition& cond,
 | |
|                                       absl::Duration timeout) {
 | |
|   return LockWhenWithTimeout(cond, timeout);
 | |
| }
 | |
| bool Mutex::ReaderLockWhenWithDeadline(const Condition& cond,
 | |
|                                        absl::Time deadline) {
 | |
|   return LockWhenWithDeadline(cond, deadline);
 | |
| }
 | |
| 
 | |
| void Mutex::EnableDebugLog(const char*) {}
 | |
| void Mutex::EnableInvariantDebugging(void (*)(void*), void*) {}
 | |
| void Mutex::ForgetDeadlockInfo() {}
 | |
| void Mutex::AssertHeld() const {}
 | |
| void Mutex::AssertReaderHeld() const {}
 | |
| void Mutex::AssertNotHeld() const {}
 | |
| 
 | |
| CondVar::CondVar() {}
 | |
| 
 | |
| CondVar::~CondVar() {}
 | |
| 
 | |
| void CondVar::Signal() { impl()->Signal(); }
 | |
| 
 | |
| void CondVar::SignalAll() { impl()->SignalAll(); }
 | |
| 
 | |
| void CondVar::Wait(Mutex* mu) { return impl()->Wait(mu->impl()); }
 | |
| 
 | |
| bool CondVar::WaitWithDeadline(Mutex* mu, absl::Time deadline) {
 | |
|   return impl()->WaitWithDeadline(
 | |
|       mu->impl(), synchronization_internal::LimitedDeadline(deadline));
 | |
| }
 | |
| 
 | |
| bool CondVar::WaitWithTimeout(Mutex* mu, absl::Duration timeout) {
 | |
|   return WaitWithDeadline(mu, absl::Now() + timeout);
 | |
| }
 | |
| 
 | |
| void CondVar::EnableDebugLog(const char*) {}
 | |
| 
 | |
| #ifdef THREAD_SANITIZER
 | |
| extern "C" void __tsan_read1(void *addr);
 | |
| #else
 | |
| #define __tsan_read1(addr)  // do nothing if TSan not enabled
 | |
| #endif
 | |
| 
 | |
| // A function that just returns its argument, dereferenced
 | |
| static bool Dereference(void *arg) {
 | |
|   // ThreadSanitizer does not instrument this file for memory accesses.
 | |
|   // This function dereferences a user variable that can participate
 | |
|   // in a data race, so we need to manually tell TSan about this memory access.
 | |
|   __tsan_read1(arg);
 | |
|   return *(static_cast<bool *>(arg));
 | |
| }
 | |
| 
 | |
| Condition::Condition() {}   // null constructor, used for kTrue only
 | |
| const Condition Condition::kTrue;
 | |
| 
 | |
| Condition::Condition(bool (*func)(void *), void *arg)
 | |
|     : eval_(&CallVoidPtrFunction),
 | |
|       function_(func),
 | |
|       method_(nullptr),
 | |
|       arg_(arg) {}
 | |
| 
 | |
| bool Condition::CallVoidPtrFunction(const Condition *c) {
 | |
|   return (*c->function_)(c->arg_);
 | |
| }
 | |
| 
 | |
| Condition::Condition(const bool *cond)
 | |
|     : eval_(CallVoidPtrFunction),
 | |
|       function_(Dereference),
 | |
|       method_(nullptr),
 | |
|       // const_cast is safe since Dereference does not modify arg
 | |
|       arg_(const_cast<bool *>(cond)) {}
 | |
| 
 | |
| bool Condition::Eval() const {
 | |
|   // eval_ == null for kTrue
 | |
|   return (this->eval_ == nullptr) || (*this->eval_)(this);
 | |
| }
 | |
| 
 | |
| void RegisterSymbolizer(bool (*)(const void*, char*, int)) {}
 | |
| 
 | |
| }  // namespace absl
 |