| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311 | // 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  // ! _WIN32MutexImpl::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  // ! _WIN32void 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_internalMutex::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));}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_SANITIZERextern "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, dereferencedstatic 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 onlyconst 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);}}  // namespace absl
 |