#ifndef ABSL_SYNCHRONIZATION_MUTEX_H_
#define ABSL_SYNCHRONIZATION_MUTEX_H_
#include <atomic>
#include <cstdint>
#include <cstring>
#include <iterator>
#include <string>
#include "absl/base/attributes.h"
#include "absl/base/const_init.h"
#include "absl/base/internal/identity.h"
#include "absl/base/internal/low_level_alloc.h"
#include "absl/base/internal/thread_identity.h"
#include "absl/base/internal/tsan_mutex_interface.h"
#include "absl/base/port.h"
#include "absl/base/thread_annotations.h"
#include "absl/synchronization/internal/kernel_timeout.h"
#include "absl/synchronization/internal/per_thread_sem.h"
#include "absl/time/time.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
class Condition;
struct SynchWaitParams;
class ABSL_LOCKABLE ABSL_ATTRIBUTE_WARN_UNUSED Mutex {
public:
Mutex();
explicit constexpr Mutex(absl::ConstInitType);
~Mutex();
void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION();
void Unlock() ABSL_UNLOCK_FUNCTION();
ABSL_MUST_USE_RESULT bool TryLock() ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(true);
void AssertHeld() const ABSL_ASSERT_EXCLUSIVE_LOCK();
void ReaderLock() ABSL_SHARED_LOCK_FUNCTION();
void ReaderUnlock() ABSL_UNLOCK_FUNCTION();
ABSL_MUST_USE_RESULT bool ReaderTryLock() ABSL_SHARED_TRYLOCK_FUNCTION(true);
void AssertReaderHeld() const ABSL_ASSERT_SHARED_LOCK();
void WriterLock() ABSL_EXCLUSIVE_LOCK_FUNCTION() { this->Lock(); }
void WriterUnlock() ABSL_UNLOCK_FUNCTION() { this->Unlock(); }
ABSL_MUST_USE_RESULT bool WriterTryLock()
ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(true) {
return this->TryLock();
}
void Await(const Condition& cond) {
AwaitCommon(cond, synchronization_internal::KernelTimeout::Never());
}
void LockWhen(const Condition& cond) ABSL_EXCLUSIVE_LOCK_FUNCTION() {
LockWhenCommon(cond, synchronization_internal::KernelTimeout::Never(),
true);
}
void ReaderLockWhen(const Condition& cond) ABSL_SHARED_LOCK_FUNCTION() {
LockWhenCommon(cond, synchronization_internal::KernelTimeout::Never(),
false);
}
void WriterLockWhen(const Condition& cond) ABSL_EXCLUSIVE_LOCK_FUNCTION() {
this->LockWhen(cond);
}
bool AwaitWithTimeout(const Condition& cond, absl::Duration timeout) {
return AwaitCommon(cond, synchronization_internal::KernelTimeout{timeout});
}
bool AwaitWithDeadline(const Condition& cond, absl::Time deadline) {
return AwaitCommon(cond, synchronization_internal::KernelTimeout{deadline});
}
bool LockWhenWithTimeout(const Condition& cond, absl::Duration timeout)
ABSL_EXCLUSIVE_LOCK_FUNCTION() {
return LockWhenCommon(
cond, synchronization_internal::KernelTimeout{timeout}, true);
}
bool ReaderLockWhenWithTimeout(const Condition& cond, absl::Duration timeout)
ABSL_SHARED_LOCK_FUNCTION() {
return LockWhenCommon(
cond, synchronization_internal::KernelTimeout{timeout}, false);
}
bool WriterLockWhenWithTimeout(const Condition& cond, absl::Duration timeout)
ABSL_EXCLUSIVE_LOCK_FUNCTION() {
return this->LockWhenWithTimeout(cond, timeout);
}
bool LockWhenWithDeadline(const Condition& cond, absl::Time deadline)
ABSL_EXCLUSIVE_LOCK_FUNCTION() {
return LockWhenCommon(
cond, synchronization_internal::KernelTimeout{deadline}, true);
}
bool ReaderLockWhenWithDeadline(const Condition& cond, absl::Time deadline)
ABSL_SHARED_LOCK_FUNCTION() {
return LockWhenCommon(
cond, synchronization_internal::KernelTimeout{deadline}, false);
}
bool WriterLockWhenWithDeadline(const Condition& cond, absl::Time deadline)
ABSL_EXCLUSIVE_LOCK_FUNCTION() {
return this->LockWhenWithDeadline(cond, deadline);
}
void EnableInvariantDebugging(void (*invariant)(void*), void* arg);
void EnableDebugLog(const char* name);
void ForgetDeadlockInfo();
void AssertNotHeld() const;
typedef const struct MuHowS* MuHow;
static void InternalAttemptToUseMutexInFatalSignalHandler();
private:
std::atomic<intptr_t> mu_;
static void IncrementSynchSem(Mutex* mu, base_internal::PerThreadSynch* w);
static bool DecrementSynchSem(Mutex* mu, base_internal::PerThreadSynch* w,
synchronization_internal::KernelTimeout t);
void LockSlowLoop(SynchWaitParams* waitp, int flags);
bool LockSlowWithDeadline(MuHow how, const Condition* cond,
synchronization_internal::KernelTimeout t,
int flags);
void LockSlow(MuHow how, const Condition* cond,
int flags) ABSL_ATTRIBUTE_COLD;
void UnlockSlow(SynchWaitParams* waitp) ABSL_ATTRIBUTE_COLD;
bool TryLockSlow();
bool ReaderTryLockSlow();
bool AwaitCommon(const Condition& cond,
synchronization_internal::KernelTimeout t);
bool LockWhenCommon(const Condition& cond,
synchronization_internal::KernelTimeout t, bool write);
void TryRemove(base_internal::PerThreadSynch* s);
void Block(base_internal::PerThreadSynch* s);
base_internal::PerThreadSynch* Wakeup(base_internal::PerThreadSynch* w);
void Dtor();
friend class CondVar; void Trans(MuHow how); void Fer(
base_internal::PerThreadSynch* w);
explicit Mutex(const volatile Mutex* ) {}
Mutex(const Mutex&) = delete;
Mutex& operator=(const Mutex&) = delete;
};
class ABSL_SCOPED_LOCKABLE MutexLock {
public:
explicit MutexLock(Mutex* mu) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu) : mu_(mu) {
this->mu_->Lock();
}
explicit MutexLock(Mutex* mu, const Condition& cond)
ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
: mu_(mu) {
this->mu_->LockWhen(cond);
}
MutexLock(const MutexLock&) = delete; MutexLock(MutexLock&&) = delete; MutexLock& operator=(const MutexLock&) = delete;
MutexLock& operator=(MutexLock&&) = delete;
~MutexLock() ABSL_UNLOCK_FUNCTION() { this->mu_->Unlock(); }
private:
Mutex* const mu_;
};
class ABSL_SCOPED_LOCKABLE ReaderMutexLock {
public:
explicit ReaderMutexLock(Mutex* mu) ABSL_SHARED_LOCK_FUNCTION(mu) : mu_(mu) {
mu->ReaderLock();
}
explicit ReaderMutexLock(Mutex* mu, const Condition& cond)
ABSL_SHARED_LOCK_FUNCTION(mu)
: mu_(mu) {
mu->ReaderLockWhen(cond);
}
ReaderMutexLock(const ReaderMutexLock&) = delete;
ReaderMutexLock(ReaderMutexLock&&) = delete;
ReaderMutexLock& operator=(const ReaderMutexLock&) = delete;
ReaderMutexLock& operator=(ReaderMutexLock&&) = delete;
~ReaderMutexLock() ABSL_UNLOCK_FUNCTION() { this->mu_->ReaderUnlock(); }
private:
Mutex* const mu_;
};
class ABSL_SCOPED_LOCKABLE WriterMutexLock {
public:
explicit WriterMutexLock(Mutex* mu) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
: mu_(mu) {
mu->WriterLock();
}
explicit WriterMutexLock(Mutex* mu, const Condition& cond)
ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
: mu_(mu) {
mu->WriterLockWhen(cond);
}
WriterMutexLock(const WriterMutexLock&) = delete;
WriterMutexLock(WriterMutexLock&&) = delete;
WriterMutexLock& operator=(const WriterMutexLock&) = delete;
WriterMutexLock& operator=(WriterMutexLock&&) = delete;
~WriterMutexLock() ABSL_UNLOCK_FUNCTION() { this->mu_->WriterUnlock(); }
private:
Mutex* const mu_;
};
class Condition {
public:
Condition(bool (*func)(void*), void* arg);
template <typename T>
Condition(bool (*func)(T*), T* arg);
template <typename T, typename = void>
Condition(bool (*func)(T*),
typename absl::internal::type_identity<T>::type* arg);
template <typename T>
Condition(T* object,
bool (absl::internal::type_identity<T>::type::*method)());
template <typename T>
Condition(const T* object,
bool (absl::internal::type_identity<T>::type::*method)() const);
explicit Condition(const bool* cond);
template <typename T, typename E = decltype(static_cast<bool (T::*)() const>(
&T::operator()))>
explicit Condition(const T* obj)
: Condition(obj, static_cast<bool (T::*)() const>(&T::operator())) {}
ABSL_CONST_INIT static const Condition kTrue;
bool Eval() const;
static bool GuaranteedEqual(const Condition* a, const Condition* b);
private:
#ifndef _MSC_VER
using MethodPtr = bool (Condition::*)();
char callback_[sizeof(MethodPtr)] = {0};
#else
char callback_[24] = {0};
#endif
bool (*eval_)(const Condition*) = nullptr;
void* arg_ = nullptr;
static bool CallVoidPtrFunction(const Condition*);
template <typename T>
static bool CastAndCallFunction(const Condition* c);
template <typename T, typename ConditionMethodPtr>
static bool CastAndCallMethod(const Condition* c);
template <typename T>
inline void StoreCallback(T callback) {
static_assert(
sizeof(callback) <= sizeof(callback_),
"An overlarge pointer was passed as a callback to Condition.");
std::memcpy(callback_, &callback, sizeof(callback));
}
template <typename T>
inline void ReadCallback(T* callback) const {
std::memcpy(callback, callback_, sizeof(*callback));
}
static bool AlwaysTrue(const Condition*) { return true; }
constexpr Condition() : eval_(AlwaysTrue), arg_(nullptr) {}
};
class CondVar {
public:
CondVar();
void Wait(Mutex* mu) {
WaitCommon(mu, synchronization_internal::KernelTimeout::Never());
}
bool WaitWithTimeout(Mutex* mu, absl::Duration timeout) {
return WaitCommon(mu, synchronization_internal::KernelTimeout(timeout));
}
bool WaitWithDeadline(Mutex* mu, absl::Time deadline) {
return WaitCommon(mu, synchronization_internal::KernelTimeout(deadline));
}
void Signal();
void SignalAll();
void EnableDebugLog(const char* name);
private:
bool WaitCommon(Mutex* mutex, synchronization_internal::KernelTimeout t);
void Remove(base_internal::PerThreadSynch* s);
std::atomic<intptr_t> cv_; CondVar(const CondVar&) = delete;
CondVar& operator=(const CondVar&) = delete;
};
class ABSL_SCOPED_LOCKABLE MutexLockMaybe {
public:
explicit MutexLockMaybe(Mutex* mu) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
: mu_(mu) {
if (this->mu_ != nullptr) {
this->mu_->Lock();
}
}
explicit MutexLockMaybe(Mutex* mu, const Condition& cond)
ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
: mu_(mu) {
if (this->mu_ != nullptr) {
this->mu_->LockWhen(cond);
}
}
~MutexLockMaybe() ABSL_UNLOCK_FUNCTION() {
if (this->mu_ != nullptr) {
this->mu_->Unlock();
}
}
private:
Mutex* const mu_;
MutexLockMaybe(const MutexLockMaybe&) = delete;
MutexLockMaybe(MutexLockMaybe&&) = delete;
MutexLockMaybe& operator=(const MutexLockMaybe&) = delete;
MutexLockMaybe& operator=(MutexLockMaybe&&) = delete;
};
class ABSL_SCOPED_LOCKABLE ReleasableMutexLock {
public:
explicit ReleasableMutexLock(Mutex* mu) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
: mu_(mu) {
this->mu_->Lock();
}
explicit ReleasableMutexLock(Mutex* mu, const Condition& cond)
ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
: mu_(mu) {
this->mu_->LockWhen(cond);
}
~ReleasableMutexLock() ABSL_UNLOCK_FUNCTION() {
if (this->mu_ != nullptr) {
this->mu_->Unlock();
}
}
void Release() ABSL_UNLOCK_FUNCTION();
private:
Mutex* mu_;
ReleasableMutexLock(const ReleasableMutexLock&) = delete;
ReleasableMutexLock(ReleasableMutexLock&&) = delete;
ReleasableMutexLock& operator=(const ReleasableMutexLock&) = delete;
ReleasableMutexLock& operator=(ReleasableMutexLock&&) = delete;
};
inline Mutex::Mutex() : mu_(0) {
ABSL_TSAN_MUTEX_CREATE(this, __tsan_mutex_not_static);
}
inline constexpr Mutex::Mutex(absl::ConstInitType) : mu_(0) {}
#if !defined(__APPLE__) && !defined(ABSL_BUILD_DLL)
ABSL_ATTRIBUTE_ALWAYS_INLINE
inline Mutex::~Mutex() { Dtor(); }
#endif
#if defined(NDEBUG) && !defined(ABSL_HAVE_THREAD_SANITIZER)
ABSL_ATTRIBUTE_ALWAYS_INLINE
inline void Mutex::Dtor() {}
#endif
inline CondVar::CondVar() : cv_(0) {}
template <typename T, typename ConditionMethodPtr>
bool Condition::CastAndCallMethod(const Condition* c) {
T* object = static_cast<T*>(c->arg_);
ConditionMethodPtr condition_method_pointer;
c->ReadCallback(&condition_method_pointer);
return (object->*condition_method_pointer)();
}
template <typename T>
bool Condition::CastAndCallFunction(const Condition* c) {
bool (*function)(T*);
c->ReadCallback(&function);
T* argument = static_cast<T*>(c->arg_);
return (*function)(argument);
}
template <typename T>
inline Condition::Condition(bool (*func)(T*), T* arg)
: eval_(&CastAndCallFunction<T>),
arg_(const_cast<void*>(static_cast<const void*>(arg))) {
static_assert(sizeof(&func) <= sizeof(callback_),
"An overlarge function pointer was passed to Condition.");
StoreCallback(func);
}
template <typename T, typename>
inline Condition::Condition(
bool (*func)(T*), typename absl::internal::type_identity<T>::type* arg)
: Condition(func, arg) {}
template <typename T>
inline Condition::Condition(
T* object, bool (absl::internal::type_identity<T>::type::*method)())
: eval_(&CastAndCallMethod<T, decltype(method)>), arg_(object) {
static_assert(sizeof(&method) <= sizeof(callback_),
"An overlarge method pointer was passed to Condition.");
StoreCallback(method);
}
template <typename T>
inline Condition::Condition(
const T* object,
bool (absl::internal::type_identity<T>::type::*method)() const)
: eval_(&CastAndCallMethod<const T, decltype(method)>),
arg_(reinterpret_cast<void*>(const_cast<T*>(object))) {
StoreCallback(method);
}
void RegisterMutexProfiler(void (*fn)(int64_t wait_cycles));
void RegisterMutexTracer(void (*fn)(const char* msg, const void* obj,
int64_t wait_cycles));
void RegisterCondVarTracer(void (*fn)(const char* msg, const void* cv));
void EnableMutexInvariantDebugging(bool enabled);
enum class OnDeadlockCycle {
kIgnore, kReport, kAbort, };
void SetMutexDeadlockDetectionMode(OnDeadlockCycle mode);
ABSL_NAMESPACE_END
}
extern "C" {
void ABSL_INTERNAL_C_SYMBOL(AbslInternalMutexYield)();
}
#endif