53 #include "CADebugMacros.h"
54 #include "CAException.h"
55 #include "CAHostTimeBase.h"
74 CAGuard::CAGuard(
const char* inName)
77 #if Log_Average_Latency
78 ,mAverageLatencyAccumulator(0.0),
79 mAverageLatencyCount(0)
83 OSStatus theError = pthread_cond_init(&mCondVar, NULL);
84 ThrowIf(theError != 0, CAException(theError),
"CAGuard::CAGuard: Could not init the cond var");
86 mEvent = CreateEvent(NULL,
true,
false, NULL);
87 ThrowIfNULL(mEvent, CAException(GetLastError()),
"CAGuard::CAGuard: Could not create the event");
94 pthread_cond_destroy(&mCondVar);
106 ThrowIf(!pthread_equal(pthread_self(), mOwner), CAException(1),
"CAGuard::Wait: A thread has to have locked a guard before it can wait");
110 #if Log_WaitOwnership
111 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);
114 OSStatus theError = pthread_cond_wait(&mCondVar, &mMutex);
115 ThrowIf(theError != 0, CAException(theError),
"CAGuard::Wait: Could not wait for a signal");
116 mOwner = pthread_self();
118 #if Log_WaitOwnership
119 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);
121 #elif TARGET_OS_WIN32
122 ThrowIf(GetCurrentThreadId() != mOwner, CAException(1),
"CAGuard::Wait: A thread has to have locked a guard before it can wait");
126 #if Log_WaitOwnership
127 DebugPrintfRtn(DebugPrintfFileComma
"%lu %.4f: CAGuard::Wait: thread %lu is waiting on %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner);
130 ReleaseMutex(mMutex);
131 HANDLE theHandles[] = { mMutex, mEvent };
132 OSStatus theError = WaitForMultipleObjects(2, theHandles,
true, INFINITE);
133 ThrowIfError(theError, CAException(GetLastError()),
"CAGuard::Wait: Could not wait for the signal");
134 mOwner = GetCurrentThreadId();
137 #if Log_WaitOwnership
138 DebugPrintfRtn(DebugPrintfFileComma
"%lu %.4f: CAGuard::Wait: thread %lu waited on %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner);
143 bool CAGuard::WaitFor(UInt64 inNanos)
145 bool theAnswer =
false;
148 ThrowIf(!pthread_equal(pthread_self(), mOwner), CAException(1),
"CAGuard::WaitFor: A thread has to have locked a guard be for it can wait");
151 DebugMessageN1(
"CAGuard::WaitFor: waiting %.0f", (Float64)inNanos);
154 struct timespec theTimeSpec;
155 static const UInt64 kNanosPerSecond = 1000000000ULL;
156 if(inNanos >= kNanosPerSecond)
158 theTimeSpec.tv_sec =
static_cast<UInt32
>(inNanos / kNanosPerSecond);
159 theTimeSpec.tv_nsec =
static_cast<UInt32
>(inNanos % kNanosPerSecond);
163 theTimeSpec.tv_sec = 0;
164 theTimeSpec.tv_nsec =
static_cast<UInt32
>(inNanos);
167 #if Log_TimedWaits || Log_Latency || Log_Average_Latency
168 UInt64 theStartNanos = CAHostTimeBase::GetCurrentTimeInNanos();
173 #if Log_WaitOwnership
174 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);
177 OSStatus theError = pthread_cond_timedwait_relative_np(&mCondVar, &mMutex, &theTimeSpec);
178 ThrowIf((theError != 0) && (theError != ETIMEDOUT), CAException(theError),
"CAGuard::WaitFor: Wait got an error");
179 mOwner = pthread_self();
181 #if Log_TimedWaits || Log_Latency || Log_Average_Latency
182 UInt64 theEndNanos = CAHostTimeBase::GetCurrentTimeInNanos();
186 DebugMessageN1(
"CAGuard::WaitFor: waited %.0f", (Float64)(theEndNanos - theStartNanos));
190 DebugMessageN1(
"CAGuard::WaitFor: latency %.0f", (Float64)((theEndNanos - theStartNanos) - inNanos));
193 #if Log_Average_Latency
194 ++mAverageLatencyCount;
195 mAverageLatencyAccumulator += (theEndNanos - theStartNanos) - inNanos;
196 if(mAverageLatencyCount >= 50)
198 DebugMessageN2(
"CAGuard::WaitFor: average latency %.3f ns over %ld waits", mAverageLatencyAccumulator / mAverageLatencyCount, mAverageLatencyCount);
199 mAverageLatencyCount = 0;
200 mAverageLatencyAccumulator = 0.0;
204 #if Log_WaitOwnership
205 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);
208 theAnswer = theError == ETIMEDOUT;
209 #elif TARGET_OS_WIN32
210 ThrowIf(GetCurrentThreadId() != mOwner, CAException(1),
"CAGuard::WaitFor: A thread has to have locked a guard be for it can wait");
213 DebugMessageN1(
"CAGuard::WaitFor: waiting %.0f", (Float64)inNanos);
217 UInt32 theWaitTime =
static_cast<UInt32
>(inNanos / 1000000ULL);
219 #if Log_TimedWaits || Log_Latency || Log_Average_Latency
220 UInt64 theStartNanos = CAHostTimeBase::GetCurrentTimeInNanos();
225 #if Log_WaitOwnership
226 DebugPrintfRtn(DebugPrintfFileComma
"%lu %.4f: CAGuard::WaitFor: thread %lu is waiting on %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner);
229 ReleaseMutex(mMutex);
230 HANDLE theHandles[] = { mMutex, mEvent };
231 OSStatus theError = WaitForMultipleObjects(2, theHandles,
true, theWaitTime);
232 ThrowIf((theError != WAIT_OBJECT_0) && (theError != WAIT_TIMEOUT), CAException(GetLastError()),
"CAGuard::WaitFor: Wait got an error");
233 mOwner = GetCurrentThreadId();
236 #if Log_TimedWaits || Log_Latency || Log_Average_Latency
237 UInt64 theEndNanos = CAHostTimeBase::GetCurrentTimeInNanos();
241 DebugMessageN1(
"CAGuard::WaitFor: waited %.0f", (Float64)(theEndNanos - theStartNanos));
245 DebugMessageN1(
"CAGuard::WaitFor: latency %.0f", (Float64)((theEndNanos - theStartNanos) - inNanos));
248 #if Log_Average_Latency
249 ++mAverageLatencyCount;
250 mAverageLatencyAccumulator += (theEndNanos - theStartNanos) - inNanos;
251 if(mAverageLatencyCount >= 50)
253 DebugMessageN2(
"CAGuard::WaitFor: average latency %.3f ns over %ld waits", mAverageLatencyAccumulator / mAverageLatencyCount, mAverageLatencyCount);
254 mAverageLatencyCount = 0;
255 mAverageLatencyAccumulator = 0.0;
259 #if Log_WaitOwnership
260 DebugPrintfRtn(DebugPrintfFileComma
"%lu %.4f: CAGuard::WaitFor: thread %lu waited on %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner);
263 theAnswer = theError == WAIT_TIMEOUT;
269 bool CAGuard::WaitUntil(UInt64 inNanos)
271 bool theAnswer =
false;
272 UInt64 theCurrentNanos = CAHostTimeBase::GetCurrentTimeInNanos();
275 DebugMessageN2(
"CAGuard::WaitUntil: now: %.0f, requested: %.0f", (
double)theCurrentNanos, (
double)inNanos);
278 if(inNanos > theCurrentNanos)
281 if((inNanos - theCurrentNanos) > 1000000000ULL)
283 DebugMessage(
"CAGuard::WaitUntil: about to wait for more than a second");
286 theAnswer = WaitFor(inNanos - theCurrentNanos);
291 DebugMessageN2(
"CAGuard::WaitUntil: Time has expired before waiting, now: %.0f, requested: %.0f", (
double)theCurrentNanos, (
double)inNanos);
299 void CAGuard::Notify()
302 #if Log_WaitOwnership
303 DebugPrintfRtn(DebugPrintfFileComma
"%p %.4f: CAGuard::Notify: thread %p is notifying %s, owner: %p\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), pthread_self(), mName, mOwner);
306 OSStatus theError = pthread_cond_signal(&mCondVar);
307 ThrowIf(theError != 0, CAException(theError),
"CAGuard::Notify: failed");
308 #elif TARGET_OS_WIN32
309 #if Log_WaitOwnership
310 DebugPrintfRtn(DebugPrintfFileComma
"%lu %.4f: CAGuard::Notify: thread %lu is notifying %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner);
317 void CAGuard::NotifyAll()
320 #if Log_WaitOwnership
321 DebugPrintfRtn(DebugPrintfFileComma
"%p %.4f: CAGuard::NotifyAll: thread %p is notifying %s, owner: %p\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), pthread_self(), mName, mOwner);
324 OSStatus theError = pthread_cond_broadcast(&mCondVar);
325 ThrowIf(theError != 0, CAException(theError),
"CAGuard::NotifyAll: failed");
326 #elif TARGET_OS_WIN32
327 #if Log_WaitOwnership
328 DebugPrintfRtn(DebugPrintfFileComma
"%lu %.4f: CAGuard::NotifyAll: thread %lu is notifying %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner);