• 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/config.h"
31 #include "absl/base/internal/raw_logging.h"
32 #include "absl/time/time.h"
33 
34 namespace absl {
35 ABSL_NAMESPACE_BEGIN
36 
SetMutexDeadlockDetectionMode(OnDeadlockCycle)37 void SetMutexDeadlockDetectionMode(OnDeadlockCycle) {}
EnableMutexInvariantDebugging(bool)38 void EnableMutexInvariantDebugging(bool) {}
39 
40 namespace synchronization_internal {
41 
42 namespace {
43 
44 // Return the current time plus the timeout.
DeadlineFromTimeout(absl::Duration timeout)45 absl::Time DeadlineFromTimeout(absl::Duration timeout) {
46   return absl::Now() + timeout;
47 }
48 
49 // Limit the deadline to a positive, 32-bit time_t value to accommodate
50 // implementation restrictions.  This also deals with InfinitePast and
51 // InfiniteFuture.
LimitedDeadline(absl::Time deadline)52 absl::Time LimitedDeadline(absl::Time deadline) {
53   deadline = std::max(absl::FromTimeT(0), deadline);
54   deadline = std::min(deadline, absl::FromTimeT(0x7fffffff));
55   return deadline;
56 }
57 
58 }  // namespace
59 
60 #if defined(_WIN32)
61 
MutexImpl()62 MutexImpl::MutexImpl() {}
63 
~MutexImpl()64 MutexImpl::~MutexImpl() {
65   if (locked_) {
66     std_mutex_.unlock();
67   }
68 }
69 
Lock()70 void MutexImpl::Lock() {
71   std_mutex_.lock();
72   locked_ = true;
73 }
74 
TryLock()75 bool MutexImpl::TryLock() {
76   bool locked = std_mutex_.try_lock();
77   if (locked) locked_ = true;
78   return locked;
79 }
80 
Unlock()81 void MutexImpl::Unlock() {
82   locked_ = false;
83   released_.SignalAll();
84   std_mutex_.unlock();
85 }
86 
CondVarImpl()87 CondVarImpl::CondVarImpl() {}
88 
~CondVarImpl()89 CondVarImpl::~CondVarImpl() {}
90 
Signal()91 void CondVarImpl::Signal() { std_cv_.notify_one(); }
92 
SignalAll()93 void CondVarImpl::SignalAll() { std_cv_.notify_all(); }
94 
Wait(MutexImpl * mu)95 void CondVarImpl::Wait(MutexImpl* mu) {
96   mu->released_.SignalAll();
97   std_cv_.wait(mu->std_mutex_);
98 }
99 
WaitWithDeadline(MutexImpl * mu,absl::Time deadline)100 bool CondVarImpl::WaitWithDeadline(MutexImpl* mu, absl::Time deadline) {
101   mu->released_.SignalAll();
102   time_t when = ToTimeT(deadline);
103   int64_t nanos = ToInt64Nanoseconds(deadline - absl::FromTimeT(when));
104   std::chrono::system_clock::time_point deadline_tp =
105       std::chrono::system_clock::from_time_t(when) +
106       std::chrono::duration_cast<std::chrono::system_clock::duration>(
107           std::chrono::nanoseconds(nanos));
108   auto deadline_since_epoch =
109       std::chrono::duration_cast<std::chrono::duration<double>>(
110           deadline_tp - std::chrono::system_clock::from_time_t(0));
111   return std_cv_.wait_until(mu->std_mutex_, deadline_tp) ==
112          std::cv_status::timeout;
113 }
114 
115 #else  // ! _WIN32
116 
MutexImpl()117 MutexImpl::MutexImpl() {
118   ABSL_RAW_CHECK(pthread_mutex_init(&pthread_mutex_, nullptr) == 0,
119                  "pthread error");
120 }
121 
~MutexImpl()122 MutexImpl::~MutexImpl() {
123   if (locked_) {
124     ABSL_RAW_CHECK(pthread_mutex_unlock(&pthread_mutex_) == 0, "pthread error");
125   }
126   ABSL_RAW_CHECK(pthread_mutex_destroy(&pthread_mutex_) == 0, "pthread error");
127 }
128 
Lock()129 void MutexImpl::Lock() {
130   ABSL_RAW_CHECK(pthread_mutex_lock(&pthread_mutex_) == 0, "pthread error");
131   locked_ = true;
132 }
133 
TryLock()134 bool MutexImpl::TryLock() {
135   bool locked = (0 == pthread_mutex_trylock(&pthread_mutex_));
136   if (locked) locked_ = true;
137   return locked;
138 }
139 
Unlock()140 void MutexImpl::Unlock() {
141   locked_ = false;
142   released_.SignalAll();
143   ABSL_RAW_CHECK(pthread_mutex_unlock(&pthread_mutex_) == 0, "pthread error");
144 }
145 
CondVarImpl()146 CondVarImpl::CondVarImpl() {
147   ABSL_RAW_CHECK(pthread_cond_init(&pthread_cv_, nullptr) == 0,
148                  "pthread error");
149 }
150 
~CondVarImpl()151 CondVarImpl::~CondVarImpl() {
152   ABSL_RAW_CHECK(pthread_cond_destroy(&pthread_cv_) == 0, "pthread error");
153 }
154 
Signal()155 void CondVarImpl::Signal() {
156   ABSL_RAW_CHECK(pthread_cond_signal(&pthread_cv_) == 0, "pthread error");
157 }
158 
SignalAll()159 void CondVarImpl::SignalAll() {
160   ABSL_RAW_CHECK(pthread_cond_broadcast(&pthread_cv_) == 0, "pthread error");
161 }
162 
Wait(MutexImpl * mu)163 void CondVarImpl::Wait(MutexImpl* mu) {
164   mu->released_.SignalAll();
165   ABSL_RAW_CHECK(pthread_cond_wait(&pthread_cv_, &mu->pthread_mutex_) == 0,
166                  "pthread error");
167 }
168 
WaitWithDeadline(MutexImpl * mu,absl::Time deadline)169 bool CondVarImpl::WaitWithDeadline(MutexImpl* mu, absl::Time deadline) {
170   mu->released_.SignalAll();
171   struct timespec ts = ToTimespec(deadline);
172   int rc = pthread_cond_timedwait(&pthread_cv_, &mu->pthread_mutex_, &ts);
173   if (rc == ETIMEDOUT) return true;
174   ABSL_RAW_CHECK(rc == 0, "pthread error");
175   return false;
176 }
177 
178 #endif  // ! _WIN32
179 
Await(const Condition & cond)180 void MutexImpl::Await(const Condition& cond) {
181   if (cond.Eval()) return;
182   released_.SignalAll();
183   do {
184     released_.Wait(this);
185   } while (!cond.Eval());
186 }
187 
AwaitWithDeadline(const Condition & cond,absl::Time deadline)188 bool MutexImpl::AwaitWithDeadline(const Condition& cond, absl::Time deadline) {
189   if (cond.Eval()) return true;
190   released_.SignalAll();
191   while (true) {
192     if (released_.WaitWithDeadline(this, deadline)) return false;
193     if (cond.Eval()) return true;
194   }
195 }
196 
197 }  // namespace synchronization_internal
198 
Mutex()199 Mutex::Mutex() {}
200 
~Mutex()201 Mutex::~Mutex() {}
202 
Lock()203 void Mutex::Lock() { impl()->Lock(); }
204 
Unlock()205 void Mutex::Unlock() { impl()->Unlock(); }
206 
TryLock()207 bool Mutex::TryLock() { return impl()->TryLock(); }
208 
ReaderLock()209 void Mutex::ReaderLock() { Lock(); }
210 
ReaderUnlock()211 void Mutex::ReaderUnlock() { Unlock(); }
212 
Await(const Condition & cond)213 void Mutex::Await(const Condition& cond) { impl()->Await(cond); }
214 
LockWhen(const Condition & cond)215 void Mutex::LockWhen(const Condition& cond) {
216   Lock();
217   Await(cond);
218 }
219 
AwaitWithDeadline(const Condition & cond,absl::Time deadline)220 bool Mutex::AwaitWithDeadline(const Condition& cond, absl::Time deadline) {
221   return impl()->AwaitWithDeadline(
222       cond, synchronization_internal::LimitedDeadline(deadline));
223 }
224 
AwaitWithTimeout(const Condition & cond,absl::Duration timeout)225 bool Mutex::AwaitWithTimeout(const Condition& cond, absl::Duration timeout) {
226   return AwaitWithDeadline(
227       cond, synchronization_internal::DeadlineFromTimeout(timeout));
228 }
229 
LockWhenWithDeadline(const Condition & cond,absl::Time deadline)230 bool Mutex::LockWhenWithDeadline(const Condition& cond, absl::Time deadline) {
231   Lock();
232   return AwaitWithDeadline(cond, deadline);
233 }
234 
LockWhenWithTimeout(const Condition & cond,absl::Duration timeout)235 bool Mutex::LockWhenWithTimeout(const Condition& cond, absl::Duration timeout) {
236   return LockWhenWithDeadline(
237       cond, synchronization_internal::DeadlineFromTimeout(timeout));
238 }
239 
ReaderLockWhen(const Condition & cond)240 void Mutex::ReaderLockWhen(const Condition& cond) {
241   ReaderLock();
242   Await(cond);
243 }
244 
ReaderLockWhenWithTimeout(const Condition & cond,absl::Duration timeout)245 bool Mutex::ReaderLockWhenWithTimeout(const Condition& cond,
246                                       absl::Duration timeout) {
247   return LockWhenWithTimeout(cond, timeout);
248 }
ReaderLockWhenWithDeadline(const Condition & cond,absl::Time deadline)249 bool Mutex::ReaderLockWhenWithDeadline(const Condition& cond,
250                                        absl::Time deadline) {
251   return LockWhenWithDeadline(cond, deadline);
252 }
253 
EnableDebugLog(const char *)254 void Mutex::EnableDebugLog(const char*) {}
EnableInvariantDebugging(void (*)(void *),void *)255 void Mutex::EnableInvariantDebugging(void (*)(void*), void*) {}
ForgetDeadlockInfo()256 void Mutex::ForgetDeadlockInfo() {}
AssertHeld() const257 void Mutex::AssertHeld() const {}
AssertReaderHeld() const258 void Mutex::AssertReaderHeld() const {}
AssertNotHeld() const259 void Mutex::AssertNotHeld() const {}
260 
CondVar()261 CondVar::CondVar() {}
262 
~CondVar()263 CondVar::~CondVar() {}
264 
Signal()265 void CondVar::Signal() { impl()->Signal(); }
266 
SignalAll()267 void CondVar::SignalAll() { impl()->SignalAll(); }
268 
Wait(Mutex * mu)269 void CondVar::Wait(Mutex* mu) { return impl()->Wait(mu->impl()); }
270 
WaitWithDeadline(Mutex * mu,absl::Time deadline)271 bool CondVar::WaitWithDeadline(Mutex* mu, absl::Time deadline) {
272   return impl()->WaitWithDeadline(
273       mu->impl(), synchronization_internal::LimitedDeadline(deadline));
274 }
275 
WaitWithTimeout(Mutex * mu,absl::Duration timeout)276 bool CondVar::WaitWithTimeout(Mutex* mu, absl::Duration timeout) {
277   return WaitWithDeadline(mu, absl::Now() + timeout);
278 }
279 
EnableDebugLog(const char *)280 void CondVar::EnableDebugLog(const char*) {}
281 
282 #ifdef ABSL_HAVE_THREAD_SANITIZER
283 extern "C" void __tsan_read1(void *addr);
284 #else
285 #define __tsan_read1(addr)  // do nothing if TSan not enabled
286 #endif
287 
288 // A function that just returns its argument, dereferenced
Dereference(void * arg)289 static bool Dereference(void *arg) {
290   // ThreadSanitizer does not instrument this file for memory accesses.
291   // This function dereferences a user variable that can participate
292   // in a data race, so we need to manually tell TSan about this memory access.
293   __tsan_read1(arg);
294   return *(static_cast<bool *>(arg));
295 }
296 
Condition()297 Condition::Condition() {}   // null constructor, used for kTrue only
298 const Condition Condition::kTrue;
299 
Condition(bool (* func)(void *),void * arg)300 Condition::Condition(bool (*func)(void *), void *arg)
301     : eval_(&CallVoidPtrFunction),
302       function_(func),
303       method_(nullptr),
304       arg_(arg) {}
305 
CallVoidPtrFunction(const Condition * c)306 bool Condition::CallVoidPtrFunction(const Condition *c) {
307   return (*c->function_)(c->arg_);
308 }
309 
Condition(const bool * cond)310 Condition::Condition(const bool *cond)
311     : eval_(CallVoidPtrFunction),
312       function_(Dereference),
313       method_(nullptr),
314       // const_cast is safe since Dereference does not modify arg
315       arg_(const_cast<bool *>(cond)) {}
316 
Eval() const317 bool Condition::Eval() const {
318   // eval_ == null for kTrue
319   return (this->eval_ == nullptr) || (*this->eval_)(this);
320 }
321 
RegisterSymbolizer(bool (*)(const void *,char *,int))322 void RegisterSymbolizer(bool (*)(const void*, char*, int)) {}
323 
324 ABSL_NAMESPACE_END
325 }  // namespace absl
326