• 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_LIB_GPRPP_SYNC_H
20 #define GRPC_SRC_CORE_LIB_GPRPP_SYNC_H
21 
22 #include <grpc/support/port_platform.h>
23 
24 #include "absl/base/thread_annotations.h"
25 #include "absl/synchronization/mutex.h"
26 
27 #include <grpc/support/log.h>
28 #include <grpc/support/sync.h>
29 
30 #ifndef GPR_ABSEIL_SYNC
31 #include "src/core/lib/gprpp/time_util.h"
32 #endif
33 
34 // The core library is not accessible in C++ codegen headers, and vice versa.
35 // Thus, we need to have duplicate headers with similar functionality.
36 // Make sure any change to this file is also reflected in
37 // include/grpcpp/impl/sync.h.
38 //
39 // Whenever possible, prefer using this file over <grpcpp/impl/sync.h>
40 // since this file doesn't rely on g_core_codegen_interface and hence does not
41 // pay the costs of virtual function calls.
42 
43 namespace grpc_core {
44 
45 #ifdef GPR_ABSEIL_SYNC
46 
47 using Mutex = absl::Mutex;
48 using MutexLock = absl::MutexLock;
49 using ReleasableMutexLock = absl::ReleasableMutexLock;
50 using CondVar = absl::CondVar;
51 
52 // Returns the underlying gpr_mu from Mutex. This should be used only when
53 // it has to like passing the C++ mutex to C-core API.
54 // TODO(veblush): Remove this after C-core no longer uses gpr_mu.
GetUnderlyingGprMu(Mutex * mutex)55 inline gpr_mu* GetUnderlyingGprMu(Mutex* mutex) {
56   return reinterpret_cast<gpr_mu*>(mutex);
57 }
58 
59 #else
60 
61 class ABSL_LOCKABLE Mutex {
62  public:
63   Mutex() { gpr_mu_init(&mu_); }
64   ~Mutex() { gpr_mu_destroy(&mu_); }
65 
66   Mutex(const Mutex&) = delete;
67   Mutex& operator=(const Mutex&) = delete;
68 
69   void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION() { gpr_mu_lock(&mu_); }
70   void Unlock() ABSL_UNLOCK_FUNCTION() { gpr_mu_unlock(&mu_); }
71   bool TryLock() ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(true) {
72     return gpr_mu_trylock(&mu_) != 0;
73   }
74   void AssertHeld() ABSL_ASSERT_EXCLUSIVE_LOCK() {}
75 
76  private:
77   gpr_mu mu_;
78 
79   friend class CondVar;
80   friend gpr_mu* GetUnderlyingGprMu(Mutex* mutex);
81 };
82 
83 // Returns the underlying gpr_mu from Mutex. This should be used only when
84 // it has to like passing the C++ mutex to C-core API.
85 // TODO(veblush): Remove this after C-core no longer uses gpr_mu.
86 inline gpr_mu* GetUnderlyingGprMu(Mutex* mutex) { return &mutex->mu_; }
87 
88 class ABSL_SCOPED_LOCKABLE MutexLock {
89  public:
90   explicit MutexLock(Mutex* mu) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu) : mu_(mu) {
91     mu_->Lock();
92   }
93   ~MutexLock() ABSL_UNLOCK_FUNCTION() { mu_->Unlock(); }
94 
95   MutexLock(const MutexLock&) = delete;
96   MutexLock& operator=(const MutexLock&) = delete;
97 
98  private:
99   Mutex* const mu_;
100 };
101 
102 class ABSL_SCOPED_LOCKABLE ReleasableMutexLock {
103  public:
104   explicit ReleasableMutexLock(Mutex* mu) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
105       : mu_(mu) {
106     mu_->Lock();
107   }
108   ~ReleasableMutexLock() ABSL_UNLOCK_FUNCTION() {
109     if (!released_) mu_->Unlock();
110   }
111 
112   ReleasableMutexLock(const ReleasableMutexLock&) = delete;
113   ReleasableMutexLock& operator=(const ReleasableMutexLock&) = delete;
114 
115   void Release() ABSL_UNLOCK_FUNCTION() {
116     GPR_DEBUG_ASSERT(!released_);
117     released_ = true;
118     mu_->Unlock();
119   }
120 
121  private:
122   Mutex* const mu_;
123   bool released_ = false;
124 };
125 
126 class CondVar {
127  public:
128   CondVar() { gpr_cv_init(&cv_); }
129   ~CondVar() { gpr_cv_destroy(&cv_); }
130 
131   CondVar(const CondVar&) = delete;
132   CondVar& operator=(const CondVar&) = delete;
133 
134   void Signal() { gpr_cv_signal(&cv_); }
135   void SignalAll() { gpr_cv_broadcast(&cv_); }
136 
137   void Wait(Mutex* mu) { WaitWithDeadline(mu, absl::InfiniteFuture()); }
138   bool WaitWithTimeout(Mutex* mu, absl::Duration timeout) {
139     return gpr_cv_wait(&cv_, &mu->mu_, ToGprTimeSpec(timeout)) != 0;
140   }
141   bool WaitWithDeadline(Mutex* mu, absl::Time deadline) {
142     return gpr_cv_wait(&cv_, &mu->mu_, ToGprTimeSpec(deadline)) != 0;
143   }
144 
145  private:
146   gpr_cv cv_;
147 };
148 
149 #endif  // GPR_ABSEIL_SYNC
150 
151 // Deprecated. Prefer MutexLock
152 class MutexLockForGprMu {
153  public:
MutexLockForGprMu(gpr_mu * mu)154   explicit MutexLockForGprMu(gpr_mu* mu) : mu_(mu) { gpr_mu_lock(mu_); }
~MutexLockForGprMu()155   ~MutexLockForGprMu() { gpr_mu_unlock(mu_); }
156 
157   MutexLockForGprMu(const MutexLock&) = delete;
158   MutexLockForGprMu& operator=(const MutexLock&) = delete;
159 
160  private:
161   gpr_mu* const mu_;
162 };
163 
164 // Deprecated. Prefer MutexLock or ReleasableMutexLock
165 class ABSL_SCOPED_LOCKABLE LockableAndReleasableMutexLock {
166  public:
LockableAndReleasableMutexLock(Mutex * mu)167   explicit LockableAndReleasableMutexLock(Mutex* mu)
168       ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
169       : mu_(mu) {
170     mu_->Lock();
171   }
ABSL_UNLOCK_FUNCTION()172   ~LockableAndReleasableMutexLock() ABSL_UNLOCK_FUNCTION() {
173     if (!released_) mu_->Unlock();
174   }
175 
176   LockableAndReleasableMutexLock(const LockableAndReleasableMutexLock&) =
177       delete;
178   LockableAndReleasableMutexLock& operator=(
179       const LockableAndReleasableMutexLock&) = delete;
180 
Lock()181   void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION() {
182     GPR_DEBUG_ASSERT(released_);
183     mu_->Lock();
184     released_ = false;
185   }
186 
Release()187   void Release() ABSL_UNLOCK_FUNCTION() {
188     GPR_DEBUG_ASSERT(!released_);
189     released_ = true;
190     mu_->Unlock();
191   }
192 
193  private:
194   Mutex* const mu_;
195   bool released_ = false;
196 };
197 
198 }  // namespace grpc_core
199 
200 #endif  // GRPC_SRC_CORE_LIB_GPRPP_SYNC_H
201