this repo has no description
at fixPythonPipStalling 334 lines 13 kB view raw
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}