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