root/trunk/PublicUtility/CAMutex.cpp

Revision 1, 12.1 kB (checked in by gbooker, 3 years ago)

Initial Import

Line 
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         CAMutex.cpp
40        
41 ==================================================================================================*/
42
43 //==================================================================================================
44 //      Includes
45 //==================================================================================================
46
47 //      Self Include
48 #include "CAMutex.h"
49
50 #if TARGET_OS_MAC
51         #include <errno.h>
52 #endif
53
54 //      PublicUtility Includes
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_Errors                      1
66 //      #define Log_LongLatencies       1
67 //      #define LongLatencyThreshholdNS 1000000ULL      // nanoseconds
68 #endif
69
70 //==================================================================================================
71 //      CAMutex
72 //==================================================================================================
73
74 CAMutex::CAMutex(const char* inName)
75 :
76         mName(inName),
77         mOwner(0)
78 {
79 #if TARGET_OS_MAC
80         OSStatus theError = pthread_mutex_init(&mMutex, NULL);
81         ThrowIf(theError != 0, CAException(theError), "CAMutex::CAMutex: Could not init the mutex");
82        
83         #if     Log_Ownership
84                 DebugPrintfRtn(DebugPrintfFile, "%p %.4f: CAMutex::CAMutex: creating %s, owner: %p\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), mName, mOwner);
85         #endif
86 #elif TARGET_OS_WIN32
87         mMutex = CreateMutex(NULL, false, NULL);
88         ThrowIfNULL(mMutex, CAException(GetLastError()), "CAMutex::CAMutex: could not create the mutex.");
89        
90         #if     Log_Ownership
91                 DebugPrintfRtn(DebugPrintfFile, "%lu %.4f: CAMutex::CAMutex: creating %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), mName, mOwner);
92         #endif
93 #endif
94 }
95
96 CAMutex::~CAMutex()
97 {
98 #if TARGET_OS_MAC
99         #if     Log_Ownership
100                 DebugPrintfRtn(DebugPrintfFile, "%p %.4f: CAMutex::~CAMutex: destroying %s, owner: %p\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), mName, mOwner);
101         #endif
102         pthread_mutex_destroy(&mMutex);
103 #elif TARGET_OS_WIN32
104         #if     Log_Ownership
105                 DebugPrintfRtn(DebugPrintfFile, "%lu %.4f: CAMutex::~CAMutex: destroying %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), mName, mOwner);
106         #endif
107         if(mMutex != NULL)
108         {
109                 CloseHandle(mMutex);
110         }
111 #endif
112 }
113
114 bool    CAMutex::Lock()
115 {
116         bool theAnswer = false;
117        
118 #if TARGET_OS_MAC
119         pthread_t theCurrentThread = pthread_self();
120         if(!pthread_equal(theCurrentThread, mOwner))
121         {
122                 #if     Log_Ownership
123                         DebugPrintfRtn(DebugPrintfFile, "%p %.4f: CAMutex::Lock: thread %p is locking %s, owner: %p\n", theCurrentThread, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), theCurrentThread, mName, mOwner);
124                 #endif
125                
126                 #if Log_LongLatencies
127                         UInt64 lockTryTime = CAHostTimeBase::GetCurrentTimeInNanos();
128                 #endif
129                
130                 OSStatus theError = pthread_mutex_lock(&mMutex);
131                 ThrowIf(theError != 0, CAException(theError), "CAMutex::Lock: Could not lock the mutex");
132                 mOwner = theCurrentThread;
133                 theAnswer = true;
134        
135                 #if Log_LongLatencies
136                         UInt64 lockAcquireTime = CAHostTimeBase::GetCurrentTimeInNanos();
137                         if (lockAcquireTime - lockTryTime >= LongLatencyThresholdNS)
138                                 DebugPrintfRtn(DebugPrintfFile, "Thread %p took %.6fs to acquire the lock %s\n", theCurrentThread, (lockAcquireTime - lockTryTime) * 1.0e-9 /* nanos to seconds */, mName);
139                 #endif
140                
141                 #if     Log_Ownership
142                         DebugPrintfRtn(DebugPrintfFile, "%p %.4f: CAMutex::Lock: thread %p has locked %s, owner: %p\n", pthread_self(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), pthread_self(), mName, mOwner);
143                 #endif
144         }
145 #elif TARGET_OS_WIN32
146         if(mOwner != GetCurrentThreadId())
147         {
148                 #if     Log_Ownership
149                         DebugPrintfRtn(DebugPrintfFile, "%lu %.4f: CAMutex::Lock: thread %lu is locking %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner);
150                 #endif
151
152                 OSStatus theError = WaitForSingleObject(mMutex, INFINITE);
153                 ThrowIfError(theError, CAException(theError), "CAMutex::Lock: could not lock the mutex");
154                 mOwner = GetCurrentThreadId();
155                 theAnswer = true;
156        
157                 #if     Log_Ownership
158                         DebugPrintfRtn(DebugPrintfFile, "%lu %.4f: CAMutex::Lock: thread %lu has locked %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner);
159                 #endif
160         }
161 #endif
162
163         return theAnswer;
164 }
165
166 void    CAMutex::Unlock()
167 {
168 #if TARGET_OS_MAC
169         if(pthread_equal(pthread_self(), mOwner))
170         {
171                 #if     Log_Ownership
172                         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);
173                 #endif
174
175                 mOwner = 0;
176                 OSStatus theError = pthread_mutex_unlock(&mMutex);
177                 ThrowIf(theError != 0, CAException(theError), "CAMutex::Unlock: Could not unlock the mutex");
178        
179                 #if     Log_Ownership
180                         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);
181                 #endif
182         }
183         else
184         {
185                 DebugMessage("CAMutex::Unlock: A thread is attempting to unlock a Mutex it doesn't own");
186         }
187 #elif TARGET_OS_WIN32
188         if(mOwner == GetCurrentThreadId())
189         {
190                 #if     Log_Ownership
191                         DebugPrintfRtn(DebugPrintfFile, "%lu %.4f: CAMutex::Unlock: thread %lu is unlocking %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner);
192                 #endif
193
194                 mOwner = 0;
195                 bool wasReleased = ReleaseMutex(mMutex);
196                 ThrowIf(!wasReleased, CAException(GetLastError()), "CAMutex::Unlock: Could not unlock the mutex");
197        
198                 #if     Log_Ownership
199                         DebugPrintfRtn(DebugPrintfFile, "%lu %.4f: CAMutex::Unlock: thread %lu has unlocked %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner);
200                 #endif
201         }
202         else
203         {
204                 DebugMessage("CAMutex::Unlock: A thread is attempting to unlock a Mutex it doesn't own");
205         }
206 #endif
207 }
208
209 bool    CAMutex::Try(bool& outWasLocked)
210 {
211         bool theAnswer = false;
212         outWasLocked = false;
213
214 #if TARGET_OS_MAC
215         pthread_t theCurrentThread = pthread_self();
216         if(!pthread_equal(theCurrentThread, mOwner))
217         {
218                 //      this means the current thread doesn't already own the lock
219                 #if     Log_Ownership
220                         DebugPrintfRtn(DebugPrintfFile, "%p %.4f: CAMutex::Try: thread %p is try-locking %s, owner: %p\n", theCurrentThread, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), theCurrentThread, mName, mOwner);
221                 #endif
222
223                 //      go ahead and call trylock to see if we can lock it.
224                 int theError = pthread_mutex_trylock(&mMutex);
225                 if(theError == 0)
226                 {
227                         //      return value of 0 means we successfully locked the lock
228                         mOwner = theCurrentThread;
229                         theAnswer = true;
230                         outWasLocked = true;
231        
232                         #if     Log_Ownership
233                                 DebugPrintfRtn(DebugPrintfFile, "%p %.4f: CAMutex::Try: thread %p has locked %s, owner: %p\n", theCurrentThread, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), theCurrentThread, mName, mOwner);
234                         #endif
235                 }
236                 else if(theError == EBUSY)
237                 {
238                         //      return value of EBUSY means that the lock was already locked by another thread
239                         theAnswer = false;
240                         outWasLocked = false;
241        
242                         #if     Log_Ownership
243                                 DebugPrintfRtn(DebugPrintfFile, "%p %.4f: CAMutex::Try: thread %p failed to lock %s, owner: %p\n", theCurrentThread, ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), theCurrentThread, mName, mOwner);
244                         #endif
245                 }
246                 else
247                 {
248                         //      any other return value means something really bad happenned
249                         ThrowIfError(theError, CAException(theError), "CAMutex::Try: call to pthread_mutex_trylock failed");
250                 }
251         }
252         else
253         {
254                 //      this means the current thread already owns the lock
255                 theAnswer = true;
256                 outWasLocked = false;
257         }
258 #elif TARGET_OS_WIN32
259         if(mOwner != GetCurrentThreadId())
260         {
261                 //      this means the current thread doesn't own the lock
262                 #if     Log_Ownership
263                         DebugPrintfRtn(DebugPrintfFile, "%lu %.4f: CAMutex::Try: thread %lu is try-locking %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner);
264                 #endif
265                
266                 //      try to acquire the mutex
267                 OSStatus theError = WaitForSingleObject(mMutex, 0);
268                 if(theError == WAIT_OBJECT_0)
269                 {
270                         //      this means we successfully locked the lock
271                         mOwner = GetCurrentThreadId();
272                         theAnswer = true;
273                         outWasLocked = true;
274        
275                         #if     Log_Ownership
276                                 DebugPrintfRtn(DebugPrintfFile, "%lu %.4f: CAMutex::Try: thread %lu has locked %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner);
277                         #endif
278                 }
279                 else if(theError == WAIT_TIMEOUT)
280                 {
281                         //      this means that the lock was already locked by another thread
282                         theAnswer = false;
283                         outWasLocked = false;
284        
285                         #if     Log_Ownership
286                                 DebugPrintfRtn(DebugPrintfFile, "%lu %.4f: CAMutex::Try: thread %lu failed to lock %s, owner: %lu\n", GetCurrentThreadId(), ((Float64)(CAHostTimeBase::GetCurrentTimeInNanos()) / 1000000.0), GetCurrentThreadId(), mName, mOwner);
287                         #endif
288                 }
289                 else
290                 {
291                         //      any other return value means something really bad happenned
292                         ThrowIfError(theError, CAException(GetLastError()), "CAMutex::Try: call to lock the mutex failed");
293                 }
294         }
295         else
296         {
297                 //      this means the current thread already owns the lock
298                 theAnswer = true;
299                 outWasLocked = false;
300         }
301 #endif
302        
303         return theAnswer;
304 }
305
306
Note: See TracBrowser for help on using the browser.