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