• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 The Abseil Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 // Implementation of a small subset of Mutex and CondVar functionality
16 // for platforms where the production implementation hasn't been fully
17 // ported yet.
18 
19 #include "absl/synchronization/mutex.h"
20 
21 #if defined(_WIN32)
22 #include <chrono>  // NOLINT(build/c++11)
23 #else
24 #include <sys/time.h>
25 #include <time.h>
26 #endif
27 
28 #include <algorithm>
29 
30 #include "absl/base/internal/raw_logging.h"
31 #include "absl/time/time.h"
32 
33 namespace absl {
34 ABSL_NAMESPACE_BEGIN
35 namespace synchronization_internal {
36 
37 namespace {
38 
39 // Return the current time plus the timeout.
DeadlineFromTimeout(absl::Duration timeout)40 absl::Time DeadlineFromTimeout(absl::Duration timeout) {
41   return absl::Now() + timeout;
42 }
43 
44 // Limit the deadline to a positive, 32-bit time_t value to accommodate
45 // implementation restrictions.  This also deals with InfinitePast and
46 // InfiniteFuture.
LimitedDeadline(absl::Time deadline)47 absl::Time LimitedDeadline(absl::Time deadline) {
48   deadline = std::max(absl::FromTimeT(0), deadline);
49   deadline = std::min(deadline, absl::FromTimeT(0x7fffffff));
50   return deadline;
51 }
52 
53 }  // namespace
54 
55 #if defined(_WIN32)
56 
MutexImpl()57 MutexImpl::MutexImpl() {}
58 
~MutexImpl()59 MutexImpl::~MutexImpl() {
60   if (locked_) {
61     std_mutex_.unlock();
62   }
63 }
64 
Lock()65 void MutexImpl::Lock() {
66   std_mutex_.lock();
67   locked_ = true;
68 }
69 
TryLock()70 bool MutexImpl::TryLock() {
71   bool locked = std_mutex_.try_lock();
72   if (locked) locked_ = true;
73   return locked;
74 }
75 
Unlock()76 void MutexImpl::Unlock() {
77   locked_ = false;
78   released_.SignalAll();
79   std_mutex_.unlock();
80 }
81 
CondVarImpl()82 CondVarImpl::CondVarImpl() {}
83 
~CondVarImpl()84 CondVarImpl::~CondVarImpl() {}
85 
Signal()86 void CondVarImpl::Signal() { std_cv_.notify_one(); }
87 
SignalAll()88 void CondVarImpl::SignalAll() { std_cv_.notify_all(); }
89 
Wait(MutexImpl * mu)90 void CondVarImpl::Wait(MutexImpl* mu) {
91   mu->released_.SignalAll();
92   std_cv_.wait(mu->std_mutex_);
93 }
94 
WaitWithDeadline(MutexImpl * mu,absl::Time deadline)95 bool CondVarImpl::WaitWithDeadline(MutexImpl* mu, absl::Time deadline) {
96   mu->released_.SignalAll();
97   time_t when = ToTimeT(deadline);
98   int64_t nanos = ToInt64Nanoseconds(deadline - absl::FromTimeT(when));
99   std::chrono::system_clock::time_point deadline_tp =
100       std::chrono::system_clock::from_time_t(when) +
101       std::chrono::duration_cast<std::chrono::system_clock::duration>(
102           std::chrono::nanoseconds(nanos));
103   auto deadline_since_epoch =
104       std::chrono::duration_cast<std::chrono::duration<double>>(
105           deadline_tp - std::chrono::system_clock::from_time_t(0));
106   return std_cv_.wait_until(mu->std_mutex_, deadline_tp) ==
107          std::cv_status::timeout;
108 }
109 
110 #else  // ! _WIN32
111 
MutexImpl()112 MutexImpl::MutexImpl() {
113   ABSL_RAW_CHECK(pthread_mutex_init(&pthread_mutex_, nullptr) == 0,
114                  "pthread error");
115 }
116 
~MutexImpl()117 MutexImpl::~MutexImpl() {
118   if (locked_) {
119     ABSL_RAW_CHECK(pthread_mutex_unlock(&pthread_mutex_) == 0, "pthread error");
120   }
121   ABSL_RAW_CHECK(pthread_mutex_destroy(&pthread_mutex_) == 0, "pthread error");
122 }
123 
Lock()124 void MutexImpl::Lock() {
125   ABSL_RAW_CHECK(pthread_mutex_lock(&pthread_mutex_) == 0, "pthread error");
126   locked_ = true;
127 }
128 
TryLock()129 bool MutexImpl::TryLock() {
130   bool locked = (0 == pthread_mutex_trylock(&pthread_mutex_));
131   if (locked) locked_ = true;
132   return locked;
133 }
134 
Unlock()135 void MutexImpl::Unlock() {
136   locked_ = false;
137   released_.SignalAll();
138   ABSL_RAW_CHECK(pthread_mutex_unlock(&pthread_mutex_) == 0, "pthread error");
139 }
140 
CondVarImpl()141 CondVarImpl::CondVarImpl() {
142   ABSL_RAW_CHECK(pthread_cond_init(&pthread_cv_, nullptr) == 0,
143                  "pthread error");
144 }
145 
~CondVarImpl()146 CondVarImpl::~CondVarImpl() {
147   ABSL_RAW_CHECK(pthread_cond_destroy(&pthread_cv_) == 0, "pthread error");
148 }
149 
Signal()150 void CondVarImpl::Signal() {
151   ABSL_RAW_CHECK(pthread_cond_signal(&pthread_cv_) == 0, "pthread error");
152 }
153 
SignalAll()154 void CondVarImpl::SignalAll() {
155   ABSL_RAW_CHECK(pthread_cond_broadcast(&pthread_cv_) == 0, "pthread error");
156 }
157 
Wait(MutexImpl * mu)158 void CondVarImpl::Wait(MutexImpl* mu) {
159   mu->released_.SignalAll();
160   ABSL_RAW_CHECK(pthread_cond_wait(&pthread_cv_, &mu->pthread_mutex_) == 0,
161                  "pthread error");
162 }
163 
WaitWithDeadline(MutexImpl * mu,absl::Time deadline)164 bool CondVarImpl::WaitWithDeadline(MutexImpl* mu, absl::Time deadline) {
165   mu->released_.SignalAll();
166   struct timespec ts = ToTimespec(deadline);
167   int rc = pthread_cond_timedwait(&pthread_cv_, &mu->pthread_mutex_, &ts);
168   if (rc == ETIMEDOUT) return true;
169   ABSL_RAW_CHECK(rc == 0, "pthread error");
170   return false;
171 }
172 
173 #endif  // ! _WIN32
174 
Await(const Condition & cond)175 void MutexImpl::Await(const Condition& cond) {
176   if (cond.Eval()) return;
177   released_.SignalAll();
178   do {
179     released_.Wait(this);
180   } while (!cond.Eval());
181 }
182 
AwaitWithDeadline(const Condition & cond,absl::Time deadline)183 bool MutexImpl::AwaitWithDeadline(const Condition& cond, absl::Time deadline) {
184   if (cond.Eval()) return true;
185   released_.SignalAll();
186   while (true) {
187     if (released_.WaitWithDeadline(this, deadline)) return false;
188     if (cond.Eval()) return true;
189   }
190 }
191 
192 }  // namespace synchronization_internal
193 
Mutex()194 Mutex::Mutex() {}
195 
~Mutex()196 Mutex::~Mutex() {}
197 
Lock()198 void Mutex::Lock() { impl()->Lock(); }
199 
Unlock()200 void Mutex::Unlock() { impl()->Unlock(); }
201 
TryLock()202 bool Mutex::TryLock() { return impl()->TryLock(); }
203 
ReaderLock()204 void Mutex::ReaderLock() { Lock(); }
205 
ReaderUnlock()206 void Mutex::ReaderUnlock() { Unlock(); }
207 
Await(const Condition & cond)208 void Mutex::Await(const Condition& cond) { impl()->Await(cond); }
209 
LockWhen(const Condition & cond)210 void Mutex::LockWhen(const Condition& cond) {
211   Lock();
212   Await(cond);
213 }
214 
AwaitWithDeadline(const Condition & cond,absl::Time deadline)215 bool Mutex::AwaitWithDeadline(const Condition& cond, absl::Time deadline) {
216   return impl()->AwaitWithDeadline(
217       cond, synchronization_internal::LimitedDeadline(deadline));
218 }
219 
AwaitWithTimeout(const Condition & cond,absl::Duration timeout)220 bool Mutex::AwaitWithTimeout(const Condition& cond, absl::Duration timeout) {
221   return AwaitWithDeadline(
222       cond, synchronization_internal::DeadlineFromTimeout(timeout));
223 }
224 
LockWhenWithDeadline(const Condition & cond,absl::Time deadline)225 bool Mutex::LockWhenWithDeadline(const Condition& cond, absl::Time deadline) {
226   Lock();
227   return AwaitWithDeadline(cond, deadline);
228 }
229 
LockWhenWithTimeout(const Condition & cond,absl::Duration timeout)230 bool Mutex::LockWhenWithTimeout(const Condition& cond, absl::Duration timeout) {
231   return LockWhenWithDeadline(
232       cond, synchronization_internal::DeadlineFromTimeout(timeout));
233 }
234 
ReaderLockWhen(const Condition & cond)235 void Mutex::ReaderLockWhen(const Condition& cond) {
236   ReaderLock();
237   Await(cond);
238 }
239 
ReaderLockWhenWithTimeout(const Condition & cond,absl::Duration timeout)240 bool Mutex::ReaderLockWhenWithTimeout(const Condition& cond,
241                                       absl::Duration timeout) {
242   return LockWhenWithTimeout(cond, timeout);
243 }
ReaderLockWhenWithDeadline(const Condition & cond,absl::Time deadline)244 bool Mutex::ReaderLockWhenWithDeadline(const Condition& cond,
245                                        absl::Time deadline) {
246   return LockWhenWithDeadline(cond, deadline);
247 }
248 
EnableDebugLog(const char *)249 void Mutex::EnableDebugLog(const char*) {}
EnableInvariantDebugging(void (*)(void *),void *)250 void Mutex::EnableInvariantDebugging(void (*)(void*), void*) {}
ForgetDeadlockInfo()251 void Mutex::ForgetDeadlockInfo() {}
AssertHeld() const252 void Mutex::AssertHeld() const {}
AssertReaderHeld() const253 void Mutex::AssertReaderHeld() const {}
AssertNotHeld() const254 void Mutex::AssertNotHeld() const {}
255 
CondVar()256 CondVar::CondVar() {}
257 
~CondVar()258 CondVar::~CondVar() {}
259 
Signal()260 void CondVar::Signal() { impl()->Signal(); }
261 
SignalAll()262 void CondVar::SignalAll() { impl()->SignalAll(); }
263 
Wait(Mutex * mu)264 void CondVar::Wait(Mutex* mu) { return impl()->Wait(mu->impl()); }
265 
WaitWithDeadline(Mutex * mu,absl::Time deadline)266 bool CondVar::WaitWithDeadline(Mutex* mu, absl::Time deadline) {
267   return impl()->WaitWithDeadline(
268       mu->impl(), synchronization_internal::LimitedDeadline(deadline));
269 }
270 
WaitWithTimeout(Mutex * mu,absl::Duration timeout)271 bool CondVar::WaitWithTimeout(Mutex* mu, absl::Duration timeout) {
272   return WaitWithDeadline(mu, absl::Now() + timeout);
273 }
274 
EnableDebugLog(const char *)275 void CondVar::EnableDebugLog(const char*) {}
276 
277 #ifdef THREAD_SANITIZER
278 extern "C" void __tsan_read1(void *addr);
279 #else
280 #define __tsan_read1(addr)  // do nothing if TSan not enabled
281 #endif
282 
283 // A function that just returns its argument, dereferenced
Dereference(void * arg)284 static bool Dereference(void *arg) {
285   // ThreadSanitizer does not instrument this file for memory accesses.
286   // This function dereferences a user variable that can participate
287   // in a data race, so we need to manually tell TSan about this memory access.
288   __tsan_read1(arg);
289   return *(static_cast<bool *>(arg));
290 }
291 
Condition()292 Condition::Condition() {}   // null constructor, used for kTrue only
293 const Condition Condition::kTrue;
294 
Condition(bool (* func)(void *),void * arg)295 Condition::Condition(bool (*func)(void *), void *arg)
296     : eval_(&CallVoidPtrFunction),
297       function_(func),
298       method_(nullptr),
299       arg_(arg) {}
300 
CallVoidPtrFunction(const Condition * c)301 bool Condition::CallVoidPtrFunction(const Condition *c) {
302   return (*c->function_)(c->arg_);
303 }
304 
Condition(const bool * cond)305 Condition::Condition(const bool *cond)
306     : eval_(CallVoidPtrFunction),
307       function_(Dereference),
308       method_(nullptr),
309       // const_cast is safe since Dereference does not modify arg
310       arg_(const_cast<bool *>(cond)) {}
311 
Eval() const312 bool Condition::Eval() const {
313   // eval_ == null for kTrue
314   return (this->eval_ == nullptr) || (*this->eval_)(this);
315 }
316 
RegisterSymbolizer(bool (*)(const void *,char *,int))317 void RegisterSymbolizer(bool (*)(const void*, char*, int)) {}
318 
319 ABSL_NAMESPACE_END
320 }  // namespace absl
321