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