|  | @@ -26,6 +26,9 @@
 | 
	
		
			
				|  |  |  #include <grpc/support/sync.h>
 | 
	
		
			
				|  |  |  #include <grpc/support/time.h>
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +#include "absl/synchronization/mutex.h"
 | 
	
		
			
				|  |  | +#include "src/core/lib/gprpp/time_util.h"
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  // The core library is not accessible in C++ codegen headers, and vice versa.
 | 
	
		
			
				|  |  |  // Thus, we need to have duplicate headers with similar functionality.
 | 
	
		
			
				|  |  |  // Make sure any change to this file is also reflected in
 | 
	
	
		
			
				|  | @@ -37,7 +40,23 @@
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  namespace grpc_core {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -class Mutex {
 | 
	
		
			
				|  |  | +#ifdef GPR_ABSEIL_SYNC
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +using Mutex = absl::Mutex;
 | 
	
		
			
				|  |  | +using MutexLock = absl::MutexLock;
 | 
	
		
			
				|  |  | +using ReleasableMutexLock = absl::ReleasableMutexLock;
 | 
	
		
			
				|  |  | +using CondVar = absl::CondVar;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// Returns the underlying gpr_mu from Mutex. This should be used only when
 | 
	
		
			
				|  |  | +// it has to like passing the C++ mutex to C-core API.
 | 
	
		
			
				|  |  | +// TODO(veblush): Remove this after C-core no longer uses gpr_mu.
 | 
	
		
			
				|  |  | +inline gpr_mu* GetUnderlyingGprMu(Mutex* mutex) {
 | 
	
		
			
				|  |  | +  return reinterpret_cast<gpr_mu*>(mutex);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#else
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +class ABSL_LOCKABLE Mutex {
 | 
	
		
			
				|  |  |   public:
 | 
	
		
			
				|  |  |    Mutex() { gpr_mu_init(&mu_); }
 | 
	
		
			
				|  |  |    ~Mutex() { gpr_mu_destroy(&mu_); }
 | 
	
	
		
			
				|  | @@ -45,52 +64,59 @@ class Mutex {
 | 
	
		
			
				|  |  |    Mutex(const Mutex&) = delete;
 | 
	
		
			
				|  |  |    Mutex& operator=(const Mutex&) = delete;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  gpr_mu* get() { return &mu_; }
 | 
	
		
			
				|  |  | -  const gpr_mu* get() const { return &mu_; }
 | 
	
		
			
				|  |  | +  void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION() { gpr_mu_lock(&mu_); }
 | 
	
		
			
				|  |  | +  void Unlock() ABSL_UNLOCK_FUNCTION() { gpr_mu_unlock(&mu_); }
 | 
	
		
			
				|  |  | +  bool TryLock() ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(true) {
 | 
	
		
			
				|  |  | +    return gpr_mu_trylock(&mu_) != 0;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |   private:
 | 
	
		
			
				|  |  |    gpr_mu mu_;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  friend class CondVar;
 | 
	
		
			
				|  |  | +  friend gpr_mu* GetUnderlyingGprMu(Mutex* mutex);
 | 
	
		
			
				|  |  |  };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -// MutexLock is a std::
 | 
	
		
			
				|  |  | -class MutexLock {
 | 
	
		
			
				|  |  | +// Returns the underlying gpr_mu from Mutex. This should be used only when
 | 
	
		
			
				|  |  | +// it has to like passing the C++ mutex to C-core API.
 | 
	
		
			
				|  |  | +// TODO(veblush): Remove this after C-core no longer uses gpr_mu.
 | 
	
		
			
				|  |  | +inline gpr_mu* GetUnderlyingGprMu(Mutex* mutex) { return &mutex->mu_; }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +class ABSL_SCOPED_LOCKABLE MutexLock {
 | 
	
		
			
				|  |  |   public:
 | 
	
		
			
				|  |  | -  explicit MutexLock(Mutex* mu) : mu_(mu->get()) { gpr_mu_lock(mu_); }
 | 
	
		
			
				|  |  | -  explicit MutexLock(gpr_mu* mu) : mu_(mu) { gpr_mu_lock(mu_); }
 | 
	
		
			
				|  |  | -  ~MutexLock() { gpr_mu_unlock(mu_); }
 | 
	
		
			
				|  |  | +  explicit MutexLock(Mutex* mu) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu) : mu_(mu) {
 | 
	
		
			
				|  |  | +    mu_->Lock();
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  ~MutexLock() ABSL_UNLOCK_FUNCTION() { mu_->Unlock(); }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    MutexLock(const MutexLock&) = delete;
 | 
	
		
			
				|  |  |    MutexLock& operator=(const MutexLock&) = delete;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |   private:
 | 
	
		
			
				|  |  | -  gpr_mu* const mu_;
 | 
	
		
			
				|  |  | +  Mutex* const mu_;
 | 
	
		
			
				|  |  |  };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -class ReleasableMutexLock {
 | 
	
		
			
				|  |  | +class ABSL_SCOPED_LOCKABLE ReleasableMutexLock {
 | 
	
		
			
				|  |  |   public:
 | 
	
		
			
				|  |  | -  explicit ReleasableMutexLock(Mutex* mu) : mu_(mu->get()) { gpr_mu_lock(mu_); }
 | 
	
		
			
				|  |  | -  explicit ReleasableMutexLock(gpr_mu* mu) : mu_(mu) { gpr_mu_lock(mu_); }
 | 
	
		
			
				|  |  | -  ~ReleasableMutexLock() {
 | 
	
		
			
				|  |  | -    if (!released_) gpr_mu_unlock(mu_);
 | 
	
		
			
				|  |  | +  explicit ReleasableMutexLock(Mutex* mu) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
 | 
	
		
			
				|  |  | +      : mu_(mu) {
 | 
	
		
			
				|  |  | +    mu_->Lock();
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  ~ReleasableMutexLock() ABSL_UNLOCK_FUNCTION() {
 | 
	
		
			
				|  |  | +    if (!released_) mu_->Unlock();
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    ReleasableMutexLock(const ReleasableMutexLock&) = delete;
 | 
	
		
			
				|  |  |    ReleasableMutexLock& operator=(const ReleasableMutexLock&) = delete;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  void Lock() {
 | 
	
		
			
				|  |  | -    GPR_DEBUG_ASSERT(released_);
 | 
	
		
			
				|  |  | -    gpr_mu_lock(mu_);
 | 
	
		
			
				|  |  | -    released_ = false;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  void Unlock() {
 | 
	
		
			
				|  |  | +  void Release() ABSL_UNLOCK_FUNCTION() {
 | 
	
		
			
				|  |  |      GPR_DEBUG_ASSERT(!released_);
 | 
	
		
			
				|  |  |      released_ = true;
 | 
	
		
			
				|  |  | -    gpr_mu_unlock(mu_);
 | 
	
		
			
				|  |  | +    mu_->Unlock();
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |   private:
 | 
	
		
			
				|  |  | -  gpr_mu* const mu_;
 | 
	
		
			
				|  |  | +  Mutex* const mu_;
 | 
	
		
			
				|  |  |    bool released_ = false;
 | 
	
		
			
				|  |  |  };
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -103,31 +129,94 @@ class CondVar {
 | 
	
		
			
				|  |  |    CondVar& operator=(const CondVar&) = delete;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    void Signal() { gpr_cv_signal(&cv_); }
 | 
	
		
			
				|  |  | -  void Broadcast() { gpr_cv_broadcast(&cv_); }
 | 
	
		
			
				|  |  | +  void SignalAll() { gpr_cv_broadcast(&cv_); }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  void Wait(Mutex* mu) { WaitWithDeadline(mu, absl::InfiniteFuture()); }
 | 
	
		
			
				|  |  | +  bool WaitWithTimeout(Mutex* mu, absl::Duration timeout) {
 | 
	
		
			
				|  |  | +    return gpr_cv_wait(&cv_, &mu->mu_, ToGprTimeSpec(timeout)) != 0;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  bool WaitWithDeadline(Mutex* mu, absl::Time deadline) {
 | 
	
		
			
				|  |  | +    return gpr_cv_wait(&cv_, &mu->mu_, ToGprTimeSpec(deadline)) != 0;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | + private:
 | 
	
		
			
				|  |  | +  gpr_cv cv_;
 | 
	
		
			
				|  |  | +};
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#endif  // GPR_ABSEIL_SYNC
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +template <typename Predicate>
 | 
	
		
			
				|  |  | +static void WaitUntil(CondVar* cv, Mutex* mu, Predicate pred) {
 | 
	
		
			
				|  |  | +  while (!pred()) {
 | 
	
		
			
				|  |  | +    cv->Wait(mu);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// Returns true iff we timed-out
 | 
	
		
			
				|  |  | +template <typename Predicate>
 | 
	
		
			
				|  |  | +static bool WaitUntilWithTimeout(CondVar* cv, Mutex* mu, Predicate pred,
 | 
	
		
			
				|  |  | +                                 absl::Duration timeout) {
 | 
	
		
			
				|  |  | +  while (!pred()) {
 | 
	
		
			
				|  |  | +    if (cv->WaitWithTimeout(mu, timeout)) return true;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  return false;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// Returns true iff we timed-out
 | 
	
		
			
				|  |  | +template <typename Predicate>
 | 
	
		
			
				|  |  | +static bool WaitUntilWithDeadline(CondVar* cv, Mutex* mu, Predicate pred,
 | 
	
		
			
				|  |  | +                                  absl::Time deadline) {
 | 
	
		
			
				|  |  | +  while (!pred()) {
 | 
	
		
			
				|  |  | +    if (cv->WaitWithDeadline(mu, deadline)) return true;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  return false;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// Deprecated. Prefer MutexLock
 | 
	
		
			
				|  |  | +class MutexLockForGprMu {
 | 
	
		
			
				|  |  | + public:
 | 
	
		
			
				|  |  | +  explicit MutexLockForGprMu(gpr_mu* mu) : mu_(mu) { gpr_mu_lock(mu_); }
 | 
	
		
			
				|  |  | +  ~MutexLockForGprMu() { gpr_mu_unlock(mu_); }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  MutexLockForGprMu(const MutexLock&) = delete;
 | 
	
		
			
				|  |  | +  MutexLockForGprMu& operator=(const MutexLock&) = delete;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | + private:
 | 
	
		
			
				|  |  | +  gpr_mu* const mu_;
 | 
	
		
			
				|  |  | +};
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  int Wait(Mutex* mu) { return Wait(mu, gpr_inf_future(GPR_CLOCK_REALTIME)); }
 | 
	
		
			
				|  |  | -  int Wait(Mutex* mu, const gpr_timespec& deadline) {
 | 
	
		
			
				|  |  | -    return gpr_cv_wait(&cv_, mu->get(), deadline);
 | 
	
		
			
				|  |  | +// Deprecated. Prefer MutexLock or ReleasableMutexLock
 | 
	
		
			
				|  |  | +class ABSL_SCOPED_LOCKABLE LockableAndReleasableMutexLock {
 | 
	
		
			
				|  |  | + public:
 | 
	
		
			
				|  |  | +  explicit LockableAndReleasableMutexLock(Mutex* mu)
 | 
	
		
			
				|  |  | +      ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
 | 
	
		
			
				|  |  | +      : mu_(mu) {
 | 
	
		
			
				|  |  | +    mu_->Lock();
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | +  ~LockableAndReleasableMutexLock() ABSL_UNLOCK_FUNCTION() {
 | 
	
		
			
				|  |  | +    if (!released_) mu_->Unlock();
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  LockableAndReleasableMutexLock(const LockableAndReleasableMutexLock&) =
 | 
	
		
			
				|  |  | +      delete;
 | 
	
		
			
				|  |  | +  LockableAndReleasableMutexLock& operator=(
 | 
	
		
			
				|  |  | +      const LockableAndReleasableMutexLock&) = delete;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  template <typename Predicate>
 | 
	
		
			
				|  |  | -  void WaitUntil(Mutex* mu, Predicate pred) {
 | 
	
		
			
				|  |  | -    while (!pred()) {
 | 
	
		
			
				|  |  | -      Wait(mu, gpr_inf_future(GPR_CLOCK_REALTIME));
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | +  void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION() {
 | 
	
		
			
				|  |  | +    GPR_DEBUG_ASSERT(released_);
 | 
	
		
			
				|  |  | +    mu_->Lock();
 | 
	
		
			
				|  |  | +    released_ = false;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  // Returns true iff we timed-out
 | 
	
		
			
				|  |  | -  template <typename Predicate>
 | 
	
		
			
				|  |  | -  bool WaitUntil(Mutex* mu, Predicate pred, const gpr_timespec& deadline) {
 | 
	
		
			
				|  |  | -    while (!pred()) {
 | 
	
		
			
				|  |  | -      if (Wait(mu, deadline)) return true;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    return false;
 | 
	
		
			
				|  |  | +  void Release() ABSL_UNLOCK_FUNCTION() {
 | 
	
		
			
				|  |  | +    GPR_DEBUG_ASSERT(!released_);
 | 
	
		
			
				|  |  | +    released_ = true;
 | 
	
		
			
				|  |  | +    mu_->Unlock();
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |   private:
 | 
	
		
			
				|  |  | -  gpr_cv cv_;
 | 
	
		
			
				|  |  | +  Mutex* const mu_;
 | 
	
		
			
				|  |  | +  bool released_ = false;
 | 
	
		
			
				|  |  |  };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  }  // namespace grpc_core
 |