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