• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 //
3 // Copyright 2019 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 //
18 
19 #ifndef GRPC_SRC_CORE_UTIL_SYNC_H
20 #define GRPC_SRC_CORE_UTIL_SYNC_H
21 
22 #include <grpc/support/port_platform.h>
23 #include <grpc/support/sync.h>
24 
25 #include "absl/base/thread_annotations.h"
26 #include "absl/log/check.h"
27 #include "absl/synchronization/mutex.h"
28 
29 #ifndef GPR_ABSEIL_SYNC
30 #include "src/core/util/time_util.h"
31 #endif
32 
33 // The core library is not accessible in C++ codegen headers, and vice versa.
34 // Thus, we need to have duplicate headers with similar functionality.
35 // Make sure any change to this file is also reflected in
36 // include/grpcpp/impl/sync.h.
37 //
38 // Whenever possible, prefer using this file over <grpcpp/impl/sync.h>
39 // since this file doesn't rely on g_core_codegen_interface and hence does not
40 // pay the costs of virtual function calls.
41 
42 namespace grpc_core {
43 
44 #ifdef GPR_ABSEIL_SYNC
45 
46 using Mutex = absl::Mutex;
47 using MutexLock = absl::MutexLock;
48 using ReleasableMutexLock = absl::ReleasableMutexLock;
49 using CondVar = absl::CondVar;
50 
51 // Returns the underlying gpr_mu from Mutex. This should be used only when
52 // it has to like passing the C++ mutex to C-core API.
53 // TODO(veblush): Remove this after C-core no longer uses gpr_mu.
GetUnderlyingGprMu(Mutex * mutex)54 inline gpr_mu* GetUnderlyingGprMu(Mutex* mutex) {
55   return reinterpret_cast<gpr_mu*>(mutex);
56 }
57 
58 #else
59 
60 class ABSL_LOCKABLE Mutex {
61  public:
62   Mutex() { gpr_mu_init(&mu_); }
63   ~Mutex() { gpr_mu_destroy(&mu_); }
64 
65   Mutex(const Mutex&) = delete;
66   Mutex& operator=(const Mutex&) = delete;
67 
68   void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION() { gpr_mu_lock(&mu_); }
69   void Unlock() ABSL_UNLOCK_FUNCTION() { gpr_mu_unlock(&mu_); }
70   bool TryLock() ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(true) {
71     return gpr_mu_trylock(&mu_) != 0;
72   }
73   void AssertHeld() ABSL_ASSERT_EXCLUSIVE_LOCK() {}
74 
75  private:
76   gpr_mu mu_;
77 
78   friend class CondVar;
79   friend gpr_mu* GetUnderlyingGprMu(Mutex* mutex);
80 };
81 
82 // Returns the underlying gpr_mu from Mutex. This should be used only when
83 // it has to like passing the C++ mutex to C-core API.
84 // TODO(veblush): Remove this after C-core no longer uses gpr_mu.
85 inline gpr_mu* GetUnderlyingGprMu(Mutex* mutex) { return &mutex->mu_; }
86 
87 class ABSL_SCOPED_LOCKABLE MutexLock {
88  public:
89   explicit MutexLock(Mutex* mu) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu) : mu_(mu) {
90     mu_->Lock();
91   }
92   ~MutexLock() ABSL_UNLOCK_FUNCTION() { mu_->Unlock(); }
93 
94   MutexLock(const MutexLock&) = delete;
95   MutexLock& operator=(const MutexLock&) = delete;
96 
97  private:
98   Mutex* const mu_;
99 };
100 
101 class ABSL_SCOPED_LOCKABLE ReleasableMutexLock {
102  public:
103   explicit ReleasableMutexLock(Mutex* mu) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
104       : mu_(mu) {
105     mu_->Lock();
106   }
107   ~ReleasableMutexLock() ABSL_UNLOCK_FUNCTION() {
108     if (!released_) mu_->Unlock();
109   }
110 
111   ReleasableMutexLock(const ReleasableMutexLock&) = delete;
112   ReleasableMutexLock& operator=(const ReleasableMutexLock&) = delete;
113 
114   void Release() ABSL_UNLOCK_FUNCTION() {
115     DCHECK(!released_);
116     released_ = true;
117     mu_->Unlock();
118   }
119 
120  private:
121   Mutex* const mu_;
122   bool released_ = false;
123 };
124 
125 class CondVar {
126  public:
127   CondVar() { gpr_cv_init(&cv_); }
128   ~CondVar() { gpr_cv_destroy(&cv_); }
129 
130   CondVar(const CondVar&) = delete;
131   CondVar& operator=(const CondVar&) = delete;
132 
133   void Signal() { gpr_cv_signal(&cv_); }
134   void SignalAll() { gpr_cv_broadcast(&cv_); }
135 
136   void Wait(Mutex* mu) { WaitWithDeadline(mu, absl::InfiniteFuture()); }
137   bool WaitWithTimeout(Mutex* mu, absl::Duration timeout) {
138     return gpr_cv_wait(&cv_, &mu->mu_, ToGprTimeSpec(timeout)) != 0;
139   }
140   bool WaitWithDeadline(Mutex* mu, absl::Time deadline) {
141     return gpr_cv_wait(&cv_, &mu->mu_, ToGprTimeSpec(deadline)) != 0;
142   }
143 
144  private:
145   gpr_cv cv_;
146 };
147 
148 #endif  // GPR_ABSEIL_SYNC
149 
150 // Deprecated. Prefer MutexLock
151 class MutexLockForGprMu {
152  public:
MutexLockForGprMu(gpr_mu * mu)153   explicit MutexLockForGprMu(gpr_mu* mu) : mu_(mu) { gpr_mu_lock(mu_); }
~MutexLockForGprMu()154   ~MutexLockForGprMu() { gpr_mu_unlock(mu_); }
155 
156   MutexLockForGprMu(const MutexLock&) = delete;
157   MutexLockForGprMu& operator=(const MutexLock&) = delete;
158 
159  private:
160   gpr_mu* const mu_;
161 };
162 
163 // Deprecated. Prefer MutexLock or ReleasableMutexLock
164 class ABSL_SCOPED_LOCKABLE LockableAndReleasableMutexLock {
165  public:
LockableAndReleasableMutexLock(Mutex * mu)166   explicit LockableAndReleasableMutexLock(Mutex* mu)
167       ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
168       : mu_(mu) {
169     mu_->Lock();
170   }
ABSL_UNLOCK_FUNCTION()171   ~LockableAndReleasableMutexLock() ABSL_UNLOCK_FUNCTION() {
172     if (!released_) mu_->Unlock();
173   }
174 
175   LockableAndReleasableMutexLock(const LockableAndReleasableMutexLock&) =
176       delete;
177   LockableAndReleasableMutexLock& operator=(
178       const LockableAndReleasableMutexLock&) = delete;
179 
Lock()180   void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION() {
181     DCHECK(released_);
182     mu_->Lock();
183     released_ = false;
184   }
185 
Release()186   void Release() ABSL_UNLOCK_FUNCTION() {
187     DCHECK(!released_);
188     released_ = true;
189     mu_->Unlock();
190   }
191 
192  private:
193   Mutex* const mu_;
194   bool released_ = false;
195 };
196 
197 }  // namespace grpc_core
198 
199 #endif  // GRPC_SRC_CORE_UTIL_SYNC_H
200