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


abseil_cpp
Author(s):
autogenerated on Mon Feb 28 2022 21:31:19