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 GRPCPP_IMPL_SYNC_H
20 #define GRPCPP_IMPL_SYNC_H
21
22 #include <grpc/support/port_platform.h>
23
24 #ifdef GPR_HAS_PTHREAD_H
25 #include <pthread.h>
26 #endif
27
28 #include <mutex>
29
30 #include "absl/synchronization/mutex.h"
31
32 #include <grpc/support/log.h>
33 #include <grpc/support/sync.h>
34 #include <grpc/support/time.h>
35
36 // The core library is not accessible in C++ codegen headers, and vice versa.
37 // Thus, we need to have duplicate headers with similar functionality.
38 // Make sure any change to this file is also reflected in
39 // src/core/lib/gprpp/sync.h too.
40 //
41 // Whenever possible, prefer "src/core/lib/gprpp/sync.h" over this file,
42 // since in core we do not rely on g_core_codegen_interface and hence do not
43 // pay the costs of virtual function calls.
44
45 namespace grpc {
46 namespace internal {
47
48 #ifdef GPR_ABSEIL_SYNC
49
50 using Mutex = absl::Mutex;
51 using MutexLock = absl::MutexLock;
52 using ReleasableMutexLock = absl::ReleasableMutexLock;
53 using CondVar = absl::CondVar;
54
55 #else
56
57 class ABSL_LOCKABLE Mutex {
58 public:
59 Mutex() { gpr_mu_init(&mu_); }
60 ~Mutex() { gpr_mu_destroy(&mu_); }
61
62 Mutex(const Mutex&) = delete;
63 Mutex& operator=(const Mutex&) = delete;
64
65 void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION() { gpr_mu_lock(&mu_); }
66 void Unlock() ABSL_UNLOCK_FUNCTION() { gpr_mu_unlock(&mu_); }
67
68 private:
69 union {
70 gpr_mu mu_;
71 std::mutex do_not_use_sth_;
72 #ifdef GPR_HAS_PTHREAD_H
73 pthread_mutex_t do_not_use_pth_;
74 #endif
75 };
76
77 friend class CondVar;
78 };
79
80 class ABSL_SCOPED_LOCKABLE MutexLock {
81 public:
82 explicit MutexLock(Mutex* mu) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu) : mu_(mu) {
83 mu_->Lock();
84 }
85 ~MutexLock() ABSL_UNLOCK_FUNCTION() { mu_->Unlock(); }
86
87 MutexLock(const MutexLock&) = delete;
88 MutexLock& operator=(const MutexLock&) = delete;
89
90 private:
91 Mutex* const mu_;
92 };
93
94 class ABSL_SCOPED_LOCKABLE ReleasableMutexLock {
95 public:
96 explicit ReleasableMutexLock(Mutex* mu) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
97 : mu_(mu) {
98 mu_->Lock();
99 }
100 ~ReleasableMutexLock() ABSL_UNLOCK_FUNCTION() {
101 if (!released_) mu_->Unlock();
102 }
103
104 ReleasableMutexLock(const ReleasableMutexLock&) = delete;
105 ReleasableMutexLock& operator=(const ReleasableMutexLock&) = delete;
106
107 void Release() ABSL_UNLOCK_FUNCTION() {
108 GPR_DEBUG_ASSERT(!released_);
109 released_ = true;
110 mu_->Unlock();
111 }
112
113 private:
114 Mutex* const mu_;
115 bool released_ = false;
116 };
117
118 class CondVar {
119 public:
120 CondVar() { gpr_cv_init(&cv_); }
121 ~CondVar() { gpr_cv_destroy(&cv_); }
122
123 CondVar(const CondVar&) = delete;
124 CondVar& operator=(const CondVar&) = delete;
125
126 void Signal() { gpr_cv_signal(&cv_); }
127 void SignalAll() { gpr_cv_broadcast(&cv_); }
128
129 void Wait(Mutex* mu) {
130 gpr_cv_wait(&cv_, &mu->mu_, gpr_inf_future(GPR_CLOCK_REALTIME));
131 }
132
133 private:
134 gpr_cv cv_;
135 };
136
137 #endif // GPR_ABSEIL_SYNC
138
139 template <typename Predicate>
140 GRPC_DEPRECATED("incompatible with thread safety analysis")
WaitUntil(CondVar * cv,Mutex * mu,Predicate pred)141 static void WaitUntil(CondVar* cv, Mutex* mu, Predicate pred) {
142 while (!pred()) {
143 cv->Wait(mu);
144 }
145 }
146
147 } // namespace internal
148 } // namespace grpc
149
150 #endif // GRPCPP_IMPL_SYNC_H
151