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_CODEGEN_SYNC_H
20 #define GRPCPP_IMPL_CODEGEN_SYNC_H
21
22 #include <grpc/impl/codegen/port_platform.h>
23
24 #ifdef GPR_HAS_PTHREAD_H
25 #include <pthread.h>
26 #endif
27
28 #include <mutex>
29
30 #include <grpc/impl/codegen/log.h>
31 #include <grpc/impl/codegen/sync.h>
32
33 #include <grpcpp/impl/codegen/core_codegen_interface.h>
34
35 #include "absl/synchronization/mutex.h"
36
37 // The core library is not accessible in C++ codegen headers, and vice versa.
38 // Thus, we need to have duplicate headers with similar functionality.
39 // Make sure any change to this file is also reflected in
40 // src/core/lib/gprpp/sync.h too.
41 //
42 // Whenever possible, prefer "src/core/lib/gprpp/sync.h" over this file,
43 // since in core we do not rely on g_core_codegen_interface and hence do not
44 // pay the costs of virtual function calls.
45
46 namespace grpc {
47 namespace internal {
48
49 #ifdef GRPCPP_ABSEIL_SYNC
50
51 using Mutex = absl::Mutex;
52 using MutexLock = absl::MutexLock;
53 using ReleasableMutexLock = absl::ReleasableMutexLock;
54 using CondVar = absl::CondVar;
55
56 #else
57
58 class ABSL_LOCKABLE Mutex {
59 public:
60 Mutex() { g_core_codegen_interface->gpr_mu_init(&mu_); }
61 ~Mutex() { g_core_codegen_interface->gpr_mu_destroy(&mu_); }
62
63 Mutex(const Mutex&) = delete;
64 Mutex& operator=(const Mutex&) = delete;
65
66 void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION() {
67 g_core_codegen_interface->gpr_mu_lock(&mu_);
68 }
69 void Unlock() ABSL_UNLOCK_FUNCTION() {
70 g_core_codegen_interface->gpr_mu_unlock(&mu_);
71 }
72
73 private:
74 union {
75 gpr_mu mu_;
76 std::mutex do_not_use_sth_;
77 #ifdef GPR_HAS_PTHREAD_H
78 pthread_mutex_t do_not_use_pth_;
79 #endif
80 };
81
82 friend class CondVar;
83 };
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() { g_core_codegen_interface->gpr_cv_init(&cv_); }
126 ~CondVar() { g_core_codegen_interface->gpr_cv_destroy(&cv_); }
127
128 CondVar(const CondVar&) = delete;
129 CondVar& operator=(const CondVar&) = delete;
130
131 void Signal() { g_core_codegen_interface->gpr_cv_signal(&cv_); }
132 void SignalAll() { g_core_codegen_interface->gpr_cv_broadcast(&cv_); }
133
134 void Wait(Mutex* mu) {
135 g_core_codegen_interface->gpr_cv_wait(
136 &cv_, &mu->mu_,
137 g_core_codegen_interface->gpr_inf_future(GPR_CLOCK_REALTIME));
138 }
139
140 private:
141 gpr_cv cv_;
142 };
143
144 #endif // GRPCPP_ABSEIL_SYNC
145
146 template <typename Predicate>
WaitUntil(CondVar * cv,Mutex * mu,Predicate pred)147 static void WaitUntil(CondVar* cv, Mutex* mu, Predicate pred) {
148 while (!pred()) {
149 cv->Wait(mu);
150 }
151 }
152
153 } // namespace internal
154 } // namespace grpc
155
156 #endif // GRPCPP_IMPL_CODEGEN_SYNC_H
157