void CAMutex::Unlock() { #if TARGET_OS_MAC if(pthread_equal(pthread_self(), mOwner)) { #if Log_Ownership DebugPrintfRtn(DebugPrintfFile, "%p %.4f: CAMutex::Unlock: thread %p is unlocking %s, owner: %p\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), pthread_self(), mName, mOwner); #endif mOwner = 0; OSStatus theError = pthread_mutex_unlock(&mMutex); ThrowIf(theError != 0, CAException(theError), "CAMutex::Unlock: Could not unlock the mutex"); #if Log_Ownership DebugPrintfRtn(DebugPrintfFile, "%p %.4f: CAMutex::Unlock: thread %p has unlocked %s, owner: %p\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), pthread_self(), mName, mOwner); #endif } else { DebugMessage("CAMutex::Unlock: A thread is attempting to unlock a Mutex it doesn't own"); } #elif TARGET_OS_WIN32 if(mOwner == GetCurrentThreadId()) { #if Log_Ownership DebugPrintfRtn(DebugPrintfFile, "%lu %.4f: CAMutex::Unlock: thread %lu is unlocking %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner); #endif mOwner = 0; bool wasReleased = ReleaseMutex(mMutex); ThrowIf(!wasReleased, CAException(GetLastError()), "CAMutex::Unlock: Could not unlock the mutex"); #if Log_Ownership DebugPrintfRtn(DebugPrintfFile, "%lu %.4f: CAMutex::Unlock: thread %lu has unlocked %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner); #endif } else { DebugMessage("CAMutex::Unlock: A thread is attempting to unlock a Mutex it doesn't own"); } #endif }
CAMutex::CAMutex(const char* inName) : mName(inName), mOwner(0) { #if TARGET_OS_MAC OSStatus theError = pthread_mutex_init(&mMutex, NULL); ThrowIf(theError != 0, CAException(theError), "CAMutex::CAMutex: Could not init the mutex"); #if Log_Ownership DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: CAMutex::CAMutex: creating %s, owner: %p\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), mName, mOwner); #endif #elif TARGET_OS_WIN32 mMutex = CreateMutex(NULL, false, NULL); ThrowIfNULL(mMutex, CAException(GetLastError()), "CAMutex::CAMutex: could not create the mutex."); #if Log_Ownership DebugPrintfRtn(DebugPrintfFileComma "%lu %.4f: CAMutex::CAMutex: creating %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), mName, mOwner); #endif #endif }
void CAGuard::Wait() { #if TARGET_OS_MAC ThrowIf(!pthread_equal(pthread_self(), mOwner), CAException(1), "CAGuard::Wait: A thread has to have locked a guard before it can wait"); mOwner = 0; #if Log_WaitOwnership DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: CAGuard::Wait: thread %p is waiting on %s, owner: %p\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), pthread_self(), mName, mOwner); #endif OSStatus theError = pthread_cond_wait(&mCondVar, &mMutex); ThrowIf(theError != 0, CAException(theError), "CAGuard::Wait: Could not wait for a signal"); mOwner = pthread_self(); #if Log_WaitOwnership DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: CAGuard::Wait: thread %p waited on %s, owner: %p\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), pthread_self(), mName, mOwner); #endif #elif TARGET_OS_WIN32 ThrowIf(GetCurrentThreadId() != mOwner, CAException(1), "CAGuard::Wait: A thread has to have locked a guard before it can wait"); mOwner = 0; #if Log_WaitOwnership DebugPrintfRtn(DebugPrintfFileComma "%lu %.4f: CAGuard::Wait: thread %lu is waiting on %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner); #endif ReleaseMutex(mMutex); HANDLE theHandles[] = { mMutex, mEvent }; OSStatus theError = WaitForMultipleObjects(2, theHandles, true, INFINITE); ThrowIfError(theError, CAException(GetLastError()), "CAGuard::Wait: Could not wait for the signal"); mOwner = GetCurrentThreadId(); ResetEvent(mEvent); #if Log_WaitOwnership DebugPrintfRtn(DebugPrintfFileComma "%lu %.4f: CAGuard::Wait: thread %lu waited on %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner); #endif #endif }
bool CAMutex::Try(bool& outWasLocked) { bool theAnswer = false; outWasLocked = false; #if TARGET_OS_MAC pthread_t theCurrentThread = pthread_self(); if(!pthread_equal(theCurrentThread, mOwner)) { // this means the current thread doesn't already own the lock #if Log_Ownership DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: CAMutex::Try: thread %p is try-locking %s, owner: %p\n", theCurrentThread, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), theCurrentThread, mName, mOwner); #endif // go ahead and call trylock to see if we can lock it. int theError = pthread_mutex_trylock(&mMutex); if(theError == 0) { // return value of 0 means we successfully locked the lock mOwner = theCurrentThread; theAnswer = true; outWasLocked = true; #if Log_Ownership DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: CAMutex::Try: thread %p has locked %s, owner: %p\n", theCurrentThread, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), theCurrentThread, mName, mOwner); #endif } else if(theError == EBUSY) { // return value of EBUSY means that the lock was already locked by another thread theAnswer = false; outWasLocked = false; #if Log_Ownership DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: CAMutex::Try: thread %p failed to lock %s, owner: %p\n", theCurrentThread, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), theCurrentThread, mName, mOwner); #endif } else { // any other return value means something really bad happenned ThrowIfError(theError, CAException(theError), "CAMutex::Try: call to pthread_mutex_trylock failed"); } } else { // this means the current thread already owns the lock theAnswer = true; outWasLocked = false; } #elif TARGET_OS_WIN32 if(mOwner != GetCurrentThreadId()) { // this means the current thread doesn't own the lock #if Log_Ownership DebugPrintfRtn(DebugPrintfFileComma "%lu %.4f: CAMutex::Try: thread %lu is try-locking %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner); #endif // try to acquire the mutex OSStatus theError = WaitForSingleObject(mMutex, 0); if(theError == WAIT_OBJECT_0) { // this means we successfully locked the lock mOwner = GetCurrentThreadId(); theAnswer = true; outWasLocked = true; #if Log_Ownership DebugPrintfRtn(DebugPrintfFileComma "%lu %.4f: CAMutex::Try: thread %lu has locked %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner); #endif } else if(theError == WAIT_TIMEOUT) { // this means that the lock was already locked by another thread theAnswer = false; outWasLocked = false; #if Log_Ownership DebugPrintfRtn(DebugPrintfFileComma "%lu %.4f: CAMutex::Try: thread %lu failed to lock %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner); #endif } else { // any other return value means something really bad happenned ThrowIfError(theError, CAException(GetLastError()), "CAMutex::Try: call to lock the mutex failed"); } } else { // this means the current thread already owns the lock theAnswer = true; outWasLocked = false; } #endif return theAnswer; }
bool CAGuard::WaitFor(UInt64 inNanos) { bool theAnswer = false; #if TARGET_OS_MAC ThrowIf(!pthread_equal(pthread_self(), mOwner), CAException(1), "CAGuard::WaitFor: A thread has to have locked a guard be for it can wait"); #if Log_TimedWaits DebugMessageN1("CAGuard::WaitFor: waiting %.0f", (Float64)inNanos); #endif struct timespec theTimeSpec; static const UInt64 kNanosPerSecond = 1000000000ULL; if(inNanos >= kNanosPerSecond) { theTimeSpec.tv_sec = static_cast<UInt32>(inNanos / kNanosPerSecond); theTimeSpec.tv_nsec = static_cast<UInt32>(inNanos % kNanosPerSecond); } else { theTimeSpec.tv_sec = 0; theTimeSpec.tv_nsec = static_cast<UInt32>(inNanos); } #if Log_TimedWaits || Log_Latency || Log_Average_Latency UInt64 theStartNanos = CAHostTimeBase::GetCurrentTimeInNanos(); #endif mOwner = 0; #if Log_WaitOwnership DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: CAGuard::WaitFor: thread %p is waiting on %s, owner: %p\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), pthread_self(), mName, mOwner); #endif OSStatus theError = pthread_cond_timedwait_relative_np(&mCondVar, &mMutex, &theTimeSpec); ThrowIf((theError != 0) && (theError != ETIMEDOUT), CAException(theError), "CAGuard::WaitFor: Wait got an error"); mOwner = pthread_self(); #if Log_TimedWaits || Log_Latency || Log_Average_Latency UInt64 theEndNanos = CAHostTimeBase::GetCurrentTimeInNanos(); #endif #if Log_TimedWaits DebugMessageN1("CAGuard::WaitFor: waited %.0f", (Float64)(theEndNanos - theStartNanos)); #endif #if Log_Latency DebugMessageN1("CAGuard::WaitFor: latency %.0f", (Float64)((theEndNanos - theStartNanos) - inNanos)); #endif #if Log_Average_Latency ++mAverageLatencyCount; mAverageLatencyAccumulator += (theEndNanos - theStartNanos) - inNanos; if(mAverageLatencyCount >= 50) { DebugMessageN2("CAGuard::WaitFor: average latency %.3f ns over %ld waits", mAverageLatencyAccumulator / mAverageLatencyCount, mAverageLatencyCount); mAverageLatencyCount = 0; mAverageLatencyAccumulator = 0.0; } #endif #if Log_WaitOwnership DebugPrintfRtn(DebugPrintfFileComma "%p %.4f: CAGuard::WaitFor: thread %p waited on %s, owner: %p\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), pthread_self(), mName, mOwner); #endif theAnswer = theError == ETIMEDOUT; #elif TARGET_OS_WIN32 ThrowIf(GetCurrentThreadId() != mOwner, CAException(1), "CAGuard::WaitFor: A thread has to have locked a guard be for it can wait"); #if Log_TimedWaits DebugMessageN1("CAGuard::WaitFor: waiting %.0f", (Float64)inNanos); #endif // the time out is specified in milliseconds(!) UInt32 theWaitTime = static_cast<UInt32>(inNanos / 1000000ULL); #if Log_TimedWaits || Log_Latency || Log_Average_Latency UInt64 theStartNanos = CAHostTimeBase::GetCurrentTimeInNanos(); #endif mOwner = 0; #if Log_WaitOwnership DebugPrintfRtn(DebugPrintfFileComma "%lu %.4f: CAGuard::WaitFor: thread %lu is waiting on %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner); #endif ReleaseMutex(mMutex); HANDLE theHandles[] = { mMutex, mEvent }; OSStatus theError = WaitForMultipleObjects(2, theHandles, true, theWaitTime); ThrowIf((theError != WAIT_OBJECT_0) && (theError != WAIT_TIMEOUT), CAException(GetLastError()), "CAGuard::WaitFor: Wait got an error"); mOwner = GetCurrentThreadId(); ResetEvent(mEvent); #if Log_TimedWaits || Log_Latency || Log_Average_Latency UInt64 theEndNanos = CAHostTimeBase::GetCurrentTimeInNanos(); #endif #if Log_TimedWaits DebugMessageN1("CAGuard::WaitFor: waited %.0f", (Float64)(theEndNanos - theStartNanos)); #endif #if Log_Latency DebugMessageN1("CAGuard::WaitFor: latency %.0f", (Float64)((theEndNanos - theStartNanos) - inNanos)); #endif #if Log_Average_Latency ++mAverageLatencyCount; mAverageLatencyAccumulator += (theEndNanos - theStartNanos) - inNanos; if(mAverageLatencyCount >= 50) { DebugMessageN2("CAGuard::WaitFor: average latency %.3f ns over %ld waits", mAverageLatencyAccumulator / mAverageLatencyCount, mAverageLatencyCount); mAverageLatencyCount = 0; mAverageLatencyAccumulator = 0.0; } #endif #if Log_WaitOwnership DebugPrintfRtn(DebugPrintfFileComma "%lu %.4f: CAGuard::WaitFor: thread %lu waited on %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner); #endif theAnswer = theError == WAIT_TIMEOUT; #endif return theAnswer; }