#include "os/c-api/il2cpp-config-platforms.h" #if IL2CPP_THREADS_PTHREAD && !IL2CPP_TINY_WITHOUT_DEBUGGER #include "MutexImpl.h" #include "PosixHelpers.h" #include "os/Thread.h" namespace il2cpp { namespace os { MutexImpl::MutexImpl() : posix::PosixWaitObject(kMutex) , m_OwningThread(NULL) , m_RecursionCount(0) { // For a mutex, 1 means unlocked. m_Count = 1; } void MutexImpl::Lock(bool interruptible) { TryLock(posix::kNoTimeout, interruptible); } bool MutexImpl::TryLock(uint32_t milliseconds, bool interruptible) { Thread* currentThread = Thread::GetCurrentThread(); if (m_OwningThread == currentThread) { IL2CPP_ASSERT(m_Count == 0); ++m_RecursionCount; return true; } if (Wait(milliseconds, interruptible) == kWaitStatusSuccess) { m_OwningThread = currentThread; m_RecursionCount = 1; return true; } return false; } void MutexImpl::Unlock() { IL2CPP_ASSERT(m_OwningThread == Thread::GetCurrentThread()); // Undo one locking level. --m_RecursionCount; if (m_RecursionCount > 0) { // Still locked. return; } // Ok, we're releasing the mutex. Lock and signal. We don't absolutely // need the lock as we are already owning the mutex here but play it safe. posix::PosixAutoLock lock(&m_Mutex); IL2CPP_ASSERT(m_Count == 0); m_Count = 1; // Unintuitive but 1 means unlocked. m_OwningThread = NULL; // Signal condition so that either a thread that's already waiting or a thread that // comes around later and waits can claim the mutex. if (HaveWaitingThreads()) pthread_cond_signal(&m_Condition); } } } #endif