this repo has no description
1/* Copyright: � Copyright 2005 Apple Computer, Inc. All rights reserved.
2
3 Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
4 ("Apple") in consideration of your agreement to the following terms, and your
5 use, installation, modification or redistribution of this Apple software
6 constitutes acceptance of these terms. If you do not agree with these terms,
7 please do not use, install, modify or redistribute this Apple software.
8
9 In consideration of your agreement to abide by the following terms, and subject
10 to these terms, Apple grants you a personal, non-exclusive license, under Apple�s
11 copyrights in this original Apple software (the "Apple Software"), to use,
12 reproduce, modify and redistribute the Apple Software, with or without
13 modifications, in source and/or binary forms; provided that if you redistribute
14 the Apple Software in its entirety and without modifications, you must retain
15 this notice and the following text and disclaimers in all such redistributions of
16 the Apple Software. Neither the name, trademarks, service marks or logos of
17 Apple Computer, Inc. may be used to endorse or promote products derived from the
18 Apple Software without specific prior written permission from Apple. Except as
19 expressly stated in this notice, no other rights or licenses, express or implied,
20 are granted by Apple herein, including but not limited to any patent rights that
21 may be infringed by your derivative works or by other works in which the Apple
22 Software may be incorporated.
23
24 The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
25 WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
26 WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
27 PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
28 COMBINATION WITH YOUR PRODUCTS.
29
30 IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
31 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
32 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
34 OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
35 (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
36 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37*/
38/*==================================================================================================
39 CAGuard.cpp
40
41==================================================================================================*/
42
43//==================================================================================================
44// Includes
45//==================================================================================================
46
47// Self Include
48#include "CAGuard.h"
49
50#if TARGET_OS_MAC
51 #include <errno.h>
52#endif
53
54// PublicUtility Inludes
55#include "CADebugMacros.h"
56#include "CAException.h"
57#include "CAHostTimeBase.h"
58
59//==================================================================================================
60// Logging
61//==================================================================================================
62
63#if CoreAudio_Debug
64// #define Log_Ownership 1
65// #define Log_WaitOwnership 1
66// #define Log_TimedWaits 1
67// #define Log_Latency 1
68// #define Log_Errors 1
69#endif
70
71//#warning Need a try-based Locker too
72//==================================================================================================
73// CAGuard
74//==================================================================================================
75
76CAGuard::CAGuard(const char* inName)
77:
78 CAMutex(inName)
79#if Log_Average_Latency
80 ,mAverageLatencyAccumulator(0.0),
81 mAverageLatencyCount(0)
82#endif
83{
84#if TARGET_OS_MAC
85 OSStatus theError = pthread_cond_init(&mCondVar, NULL);
86 ThrowIf(theError != 0, CAException(theError), "CAGuard::CAGuard: Could not init the cond var");
87#elif TARGET_OS_WIN32
88 mEvent = CreateEvent(NULL, true, false, NULL);
89 ThrowIfNULL(mEvent, CAException(GetLastError()), "CAGuard::CAGuard: Could not create the event");
90#endif
91}
92
93CAGuard::~CAGuard()
94{
95#if TARGET_OS_MAC
96 pthread_cond_destroy(&mCondVar);
97#elif TARGET_OS_WIN32
98 if(mEvent != NULL)
99 {
100 CloseHandle(mEvent);
101 }
102#endif
103}
104
105void CAGuard::Wait()
106{
107#if TARGET_OS_MAC
108 ThrowIf(!pthread_equal(pthread_self(), mOwner), CAException(1), "CAGuard::Wait: A thread has to have locked a guard before it can wait");
109
110 mOwner = 0;
111
112 #if Log_WaitOwnership
113 DebugPrintfRtn(DebugPrintfFile, "%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 #endif
115
116 OSStatus theError = pthread_cond_wait(&mCondVar, &mMutex);
117 ThrowIf(theError != 0, CAException(theError), "CAGuard::Wait: Could not wait for a signal");
118 mOwner = pthread_self();
119
120 #if Log_WaitOwnership
121 DebugPrintfRtn(DebugPrintfFile, "%p %.4f: CAGuard::Wait: thread %p waited on %s, owner: %p\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), pthread_self(), mName, mOwner);
122 #endif
123#elif TARGET_OS_WIN32
124 ThrowIf(GetCurrentThreadId() != mOwner, CAException(1), "CAGuard::Wait: A thread has to have locked a guard before it can wait");
125
126 mOwner = 0;
127
128 #if Log_WaitOwnership
129 DebugPrintfRtn(DebugPrintfFile, "%lu %.4f: CAGuard::Wait: thread %lu is waiting on %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner);
130 #endif
131
132 ReleaseMutex(mMutex);
133 HANDLE theHandles[] = { mMutex, mEvent };
134 OSStatus theError = WaitForMultipleObjects(2, theHandles, true, INFINITE);
135 ThrowIfError(theError, CAException(GetLastError()), "CAGuard::Wait: Could not wait for the signal");
136 mOwner = GetCurrentThreadId();
137 ResetEvent(mEvent);
138
139 #if Log_WaitOwnership
140 DebugPrintfRtn(DebugPrintfFile, "%lu %.4f: CAGuard::Wait: thread %lu waited on %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner);
141 #endif
142#endif
143}
144
145bool CAGuard::WaitFor(UInt64 inNanos)
146{
147 bool theAnswer = false;
148
149#if TARGET_OS_MAC
150 ThrowIf(!pthread_equal(pthread_self(), mOwner), CAException(1), "CAGuard::WaitFor: A thread has to have locked a guard be for it can wait");
151
152 #if Log_TimedWaits
153 DebugMessageN1("CAGuard::WaitFor: waiting %.0f", (Float64)inNanos);
154 #endif
155
156 struct timespec theTimeSpec;
157 static const UInt64 kNanosPerSecond = 1000000000ULL;
158 if(inNanos > kNanosPerSecond)
159 {
160 theTimeSpec.tv_sec = inNanos / kNanosPerSecond;
161 theTimeSpec.tv_nsec = inNanos % kNanosPerSecond;
162 }
163 else
164 {
165 theTimeSpec.tv_sec = 0;
166 theTimeSpec.tv_nsec = inNanos;
167 }
168
169 #if Log_TimedWaits || Log_Latency || Log_Average_Latency
170 UInt64 theStartNanos = CAHostTimeBase::GetCurrentTimeInNanos();
171 #endif
172
173 mOwner = 0;
174
175 #if Log_WaitOwnership
176 DebugPrintfRtn(DebugPrintfFile, "%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 #endif
178
179 OSStatus theError = pthread_cond_timedwait_relative_np(&mCondVar, &mMutex, &theTimeSpec);
180 ThrowIf((theError != 0) && (theError != ETIMEDOUT), CAException(theError), "CAGuard::WaitFor: Wait got an error");
181 mOwner = pthread_self();
182
183 #if Log_TimedWaits || Log_Latency || Log_Average_Latency
184 UInt64 theEndNanos = CAHostTimeBase::GetCurrentTimeInNanos();
185 #endif
186
187 #if Log_TimedWaits
188 DebugMessageN1("CAGuard::WaitFor: waited %.0f", (Float64)(theEndNanos - theStartNanos));
189 #endif
190
191 #if Log_Latency
192 DebugMessageN1("CAGuard::WaitFor: latency %.0f", (Float64)((theEndNanos - theStartNanos) - inNanos));
193 #endif
194
195 #if Log_Average_Latency
196 ++mAverageLatencyCount;
197 mAverageLatencyAccumulator += (theEndNanos - theStartNanos) - inNanos;
198 if(mAverageLatencyCount >= 50)
199 {
200 DebugMessageN2("CAGuard::WaitFor: average latency %.3f ns over %ld waits", mAverageLatencyAccumulator / mAverageLatencyCount, mAverageLatencyCount);
201 mAverageLatencyCount = 0;
202 mAverageLatencyAccumulator = 0.0;
203 }
204 #endif
205
206 #if Log_WaitOwnership
207 DebugPrintfRtn(DebugPrintfFile, "%p %.4f: CAGuard::WaitFor: thread %p waited on %s, owner: %p\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), pthread_self(), mName, mOwner);
208 #endif
209
210 theAnswer = theError == ETIMEDOUT;
211#elif TARGET_OS_WIN32
212 ThrowIf(GetCurrentThreadId() != mOwner, CAException(1), "CAGuard::WaitFor: A thread has to have locked a guard be for it can wait");
213
214 #if Log_TimedWaits
215 DebugMessageN1("CAGuard::WaitFor: waiting %.0f", (Float64)inNanos);
216 #endif
217
218 // the time out is specified in milliseconds(!)
219 UInt32 theWaitTime = static_cast<UInt32>(inNanos / 1000000ULL);
220
221 #if Log_TimedWaits || Log_Latency || Log_Average_Latency
222 UInt64 theStartNanos = CAHostTimeBase::GetCurrentTimeInNanos();
223 #endif
224
225 mOwner = 0;
226
227 #if Log_WaitOwnership
228 DebugPrintfRtn(DebugPrintfFile, "%lu %.4f: CAGuard::WaitFor: thread %lu is waiting on %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner);
229 #endif
230
231 ReleaseMutex(mMutex);
232 HANDLE theHandles[] = { mMutex, mEvent };
233 OSStatus theError = WaitForMultipleObjects(2, theHandles, true, theWaitTime);
234 ThrowIf((theError != WAIT_OBJECT_0) && (theError != WAIT_TIMEOUT), CAException(GetLastError()), "CAGuard::WaitFor: Wait got an error");
235 mOwner = GetCurrentThreadId();
236 ResetEvent(mEvent);
237
238 #if Log_TimedWaits || Log_Latency || Log_Average_Latency
239 UInt64 theEndNanos = CAHostTimeBase::GetCurrentTimeInNanos();
240 #endif
241
242 #if Log_TimedWaits
243 DebugMessageN1("CAGuard::WaitFor: waited %.0f", (Float64)(theEndNanos - theStartNanos));
244 #endif
245
246 #if Log_Latency
247 DebugMessageN1("CAGuard::WaitFor: latency %.0f", (Float64)((theEndNanos - theStartNanos) - inNanos));
248 #endif
249
250 #if Log_Average_Latency
251 ++mAverageLatencyCount;
252 mAverageLatencyAccumulator += (theEndNanos - theStartNanos) - inNanos;
253 if(mAverageLatencyCount >= 50)
254 {
255 DebugMessageN2("CAGuard::WaitFor: average latency %.3f ns over %ld waits", mAverageLatencyAccumulator / mAverageLatencyCount, mAverageLatencyCount);
256 mAverageLatencyCount = 0;
257 mAverageLatencyAccumulator = 0.0;
258 }
259 #endif
260
261 #if Log_WaitOwnership
262 DebugPrintfRtn(DebugPrintfFile, "%lu %.4f: CAGuard::WaitFor: thread %lu waited on %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner);
263 #endif
264
265 theAnswer = theError == WAIT_TIMEOUT;
266#endif
267
268 return theAnswer;
269}
270
271bool CAGuard::WaitUntil(UInt64 inNanos)
272{
273 bool theAnswer = false;
274 UInt64 theCurrentNanos = CAHostTimeBase::GetCurrentTimeInNanos();
275
276#if Log_TimedWaits
277 DebugMessageN2("CAGuard::WaitUntil: now: %.0f, requested: %.0f", (double)theCurrentNanos, (double)inNanos);
278#endif
279
280 if(inNanos > theCurrentNanos)
281 {
282#if Log_Errors
283 if((inNanos - theCurrentNanos) > 1000000000ULL)
284 {
285 DebugMessage("CAGuard::WaitUntil: about to wait for more than a second");
286 }
287#endif
288 theAnswer = WaitFor(inNanos - theCurrentNanos);
289 }
290#if Log_Errors
291 else
292 {
293 DebugMessageN2("CAGuard::WaitUntil: Time has expired before waiting, now: %.0f, requested: %.0f", (double)theCurrentNanos, (double)inNanos);
294 }
295#endif
296
297 return theAnswer;
298}
299
300void CAGuard::Notify()
301{
302#if TARGET_OS_MAC
303 #if Log_WaitOwnership
304 DebugPrintfRtn(DebugPrintfFile, "%p %.4f: CAGuard::Notify: thread %p is notifying %s, owner: %p\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), pthread_self(), mName, mOwner);
305 #endif
306
307 OSStatus theError = pthread_cond_signal(&mCondVar);
308 ThrowIf(theError != 0, CAException(theError), "CAGuard::Notify: failed");
309#elif TARGET_OS_WIN32
310 #if Log_WaitOwnership
311 DebugPrintfRtn(DebugPrintfFile, "%lu %.4f: CAGuard::Notify: thread %lu is notifying %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner);
312 #endif
313
314 SetEvent(mEvent);
315#endif
316}
317
318void CAGuard::NotifyAll()
319{
320#if TARGET_OS_MAC
321 #if Log_WaitOwnership
322 DebugPrintfRtn(DebugPrintfFile, "%p %.4f: CAGuard::NotifyAll: thread %p is notifying %s, owner: %p\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), pthread_self(), mName, mOwner);
323 #endif
324
325 OSStatus theError = pthread_cond_broadcast(&mCondVar);
326 ThrowIf(theError != 0, CAException(theError), "CAGuard::NotifyAll: failed");
327#elif TARGET_OS_WIN32
328 #if Log_WaitOwnership
329 DebugPrintfRtn(DebugPrintfFile, "%lu %.4f: CAGuard::NotifyAll: thread %lu is notifying %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner);
330 #endif
331
332 SetEvent(mEvent);
333#endif
334}