#include "libANGLE/GlobalMutex.h"
#include <atomic>
#include "common/debug.h"
#include "common/system_utils.h"
namespace egl
{
namespace priv
{
GlobalMutexType;
#if !defined(ANGLE_ENABLE_ASSERTS) && !defined(ANGLE_ENABLE_GLOBAL_MUTEX_RECURSION)
class GlobalMutex final : angle::NonCopyable
{
public:
ANGLE_INLINE void lock() { mMutex.lock(); }
ANGLE_INLINE void unlock() { mMutex.unlock(); }
protected:
GlobalMutexType mMutex;
};
#endif
#if defined(ANGLE_ENABLE_ASSERTS) && !defined(ANGLE_ENABLE_GLOBAL_MUTEX_RECURSION)
class GlobalMutex final : angle::NonCopyable
{ … };
#endif
#if defined(ANGLE_ENABLE_GLOBAL_MUTEX_RECURSION)
class GlobalMutex final : angle::NonCopyable
{
public:
ANGLE_INLINE void lock()
{
const angle::ThreadId threadId = angle::GetCurrentThreadId();
if (ANGLE_UNLIKELY(!mMutex.try_lock()))
{
if (ANGLE_UNLIKELY(getOwnerThreadId() == threadId))
{
ASSERT(mLockLevel > 0);
++mLockLevel;
return;
}
mMutex.lock();
}
ASSERT(getOwnerThreadId() == angle::InvalidThreadId());
ASSERT(mLockLevel == 0);
mOwnerThreadId.store(threadId, std::memory_order_relaxed);
mLockLevel = 1;
}
ANGLE_INLINE void unlock()
{
ASSERT(getOwnerThreadId() == angle::GetCurrentThreadId());
ASSERT(mLockLevel > 0);
if (ANGLE_LIKELY(--mLockLevel == 0))
{
mOwnerThreadId.store(angle::InvalidThreadId(), std::memory_order_relaxed);
mMutex.unlock();
}
}
private:
ANGLE_INLINE angle::ThreadId getOwnerThreadId() const
{
return mOwnerThreadId.load(std::memory_order_relaxed);
}
GlobalMutexType mMutex;
std::atomic<angle::ThreadId> mOwnerThreadId{angle::InvalidThreadId()};
uint32_t mLockLevel = 0;
};
#endif
}
namespace
{
#if defined(ANGLE_ENABLE_GLOBAL_MUTEX_LOAD_TIME_ALLOCATE)
# if !ANGLE_HAS_ATTRIBUTE_CONSTRUCTOR || !ANGLE_HAS_ATTRIBUTE_DESTRUCTOR
# error \
"'angle_enable_global_mutex_load_time_allocate' " \
"requires constructor/destructor compiler atributes."
# endif
priv::GlobalMutex *g_MutexPtr = nullptr;
void ANGLE_CONSTRUCTOR AllocateGlobalMutex()
{
ASSERT(g_MutexPtr == nullptr);
g_MutexPtr = new priv::GlobalMutex();
}
void ANGLE_DESTRUCTOR DeallocateGlobalMutex()
{
SafeDelete(g_MutexPtr);
}
#else
ANGLE_REQUIRE_CONSTANT_INIT std::atomic<priv::GlobalMutex *> g_Mutex(nullptr);
static_assert …;
priv::GlobalMutex *AllocateGlobalMutexImpl()
{ … }
priv::GlobalMutex *GetGlobalMutex()
{ … }
#endif
}
#if defined(ANGLE_ENABLE_GLOBAL_MUTEX_LOAD_TIME_ALLOCATE)
ScopedGlobalMutexLock::ScopedGlobalMutexLock()
{
g_MutexPtr->lock();
}
ScopedGlobalMutexLock::~ScopedGlobalMutexLock()
{
g_MutexPtr->unlock();
}
#else
ScopedGlobalMutexLock::ScopedGlobalMutexLock() : … { … }
ScopedGlobalMutexLock::~ScopedGlobalMutexLock()
{ … }
#endif
ScopedOptionalGlobalMutexLock::ScopedOptionalGlobalMutexLock(bool enabled)
{ … }
ScopedOptionalGlobalMutexLock::~ScopedOptionalGlobalMutexLock()
{ … }
#if defined(ANGLE_PLATFORM_WINDOWS) && !defined(ANGLE_STATIC)
# if defined(ANGLE_ENABLE_GLOBAL_MUTEX_LOAD_TIME_ALLOCATE)
# error "'angle_enable_global_mutex_load_time_allocate' is not supported in Windows DLL."
# endif
void AllocateGlobalMutex()
{
(void)AllocateGlobalMutexImpl();
}
void DeallocateGlobalMutex()
{
priv::GlobalMutex *mutex = g_Mutex.exchange(nullptr);
if (mutex != nullptr)
{
{
std::lock_guard<priv::GlobalMutex> lock(*mutex);
}
delete mutex;
}
}
#endif
}