1 /*****************************************************************************/
2 // Copyright 2006-2008 Adobe Systems Incorporated
3 // All Rights Reserved.
4 //
5 // NOTICE: Adobe permits you to use, modify, and distribute this file in
6 // accordance with the terms of the Adobe license agreement accompanying it.
7 /*****************************************************************************/
8
9 /* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_mutex.cpp#3 $ */
10 /* $DateTime: 2012/09/05 12:31:51 $ */
11 /* $Change: 847652 $ */
12 /* $Author: tknoll $ */
13
14 #include "dng_mutex.h"
15
16 #include "dng_assertions.h"
17 #include "dng_exceptions.h"
18
19 #include <stdlib.h>
20
21 /*****************************************************************************/
22
23 #if qDNGThreadSafe
24
25 namespace
26 {
27
28 class InnermostMutexHolder
29 {
30
31 private:
32
33 pthread_key_t fInnermostMutexKey;
34
35 public:
36
InnermostMutexHolder()37 InnermostMutexHolder ()
38
39 : fInnermostMutexKey ()
40
41 {
42
43 int result = pthread_key_create (&fInnermostMutexKey, NULL);
44
45 DNG_ASSERT (result == 0, "pthread_key_create failed.");
46
47 if (result != 0)
48 ThrowProgramError ();
49
50 }
51
~InnermostMutexHolder()52 ~InnermostMutexHolder ()
53 {
54
55 pthread_key_delete (fInnermostMutexKey);
56
57 }
58
SetInnermostMutex(dng_mutex * mutex)59 void SetInnermostMutex (dng_mutex *mutex)
60 {
61
62 int result;
63
64 result = pthread_setspecific (fInnermostMutexKey, (void *)mutex);
65
66 DNG_ASSERT (result == 0, "pthread_setspecific failed.");
67
68 #if 0 // Hard failure here was causing crash on quit.
69
70 if (result != 0)
71 ThrowProgramError ();
72
73 #endif
74
75 }
76
GetInnermostMutex()77 dng_mutex *GetInnermostMutex ()
78 {
79
80 void *result = pthread_getspecific (fInnermostMutexKey);
81
82 return reinterpret_cast<dng_mutex *> (result);
83
84 }
85
86 };
87
88 InnermostMutexHolder gInnermostMutexHolder;
89
90 }
91
92 #endif
93
94 /*****************************************************************************/
95
dng_mutex(const char * mutexName,uint32 mutexLevel)96 dng_mutex::dng_mutex (const char *mutexName, uint32 mutexLevel)
97
98 #if qDNGThreadSafe
99
100 : fPthreadMutex ()
101 , fMutexLevel (mutexLevel)
102 , fRecursiveLockCount (0)
103 , fPrevHeldMutex (NULL)
104 , fMutexName (mutexName)
105
106 #endif
107
108 {
109
110 #if qDNGThreadSafe
111
112 if (pthread_mutex_init (&fPthreadMutex, NULL) != 0)
113 {
114 ThrowMemoryFull ();
115 }
116
117 #endif
118
119 }
120
121 /*****************************************************************************/
122
~dng_mutex()123 dng_mutex::~dng_mutex ()
124 {
125
126 #if qDNGThreadSafe
127
128 pthread_mutex_destroy (&fPthreadMutex);
129
130 #endif
131
132 }
133
134 /*****************************************************************************/
135
Lock()136 void dng_mutex::Lock ()
137 {
138
139 #if qDNGThreadSafe
140
141 dng_mutex *innermostMutex = gInnermostMutexHolder.GetInnermostMutex ();
142
143 if (innermostMutex != NULL)
144 {
145
146 if (innermostMutex == this)
147 {
148
149 fRecursiveLockCount++;
150
151 return;
152
153 }
154
155 bool lockOrderPreserved = fMutexLevel > innermostMutex->fMutexLevel /* ||
156 (fMutexLevel == innermostMutex->fMutexLevel && innermostMutex < this) */;
157
158 if (!lockOrderPreserved)
159 {
160
161 DNG_REPORT ("Lock ordering violation.");
162
163 #if qDNGDebug
164
165 dng_show_message_f ("This mutex: %s v Innermost mutex: %s",
166 this->MutexName (),
167 innermostMutex->MutexName ());
168
169 #endif
170
171 }
172
173 }
174
175 pthread_mutex_lock (&fPthreadMutex);
176
177 fPrevHeldMutex = innermostMutex;
178
179 gInnermostMutexHolder.SetInnermostMutex (this);
180
181 #endif
182
183 }
184
185 /*****************************************************************************/
186
Unlock()187 void dng_mutex::Unlock ()
188 {
189
190 #if qDNGThreadSafe
191
192 DNG_ASSERT (gInnermostMutexHolder.GetInnermostMutex () == this, "Mutexes unlocked out of order!!!");
193
194 if (fRecursiveLockCount > 0)
195 {
196
197 fRecursiveLockCount--;
198
199 return;
200
201 }
202
203 gInnermostMutexHolder.SetInnermostMutex (fPrevHeldMutex);
204
205 fPrevHeldMutex = NULL;
206
207 pthread_mutex_unlock (&fPthreadMutex);
208
209 #endif
210
211 }
212
213 /*****************************************************************************/
214
MutexName() const215 const char *dng_mutex::MutexName () const
216 {
217
218 #if qDNGThreadSafe
219
220 if (fMutexName)
221 return fMutexName;
222
223 #endif
224
225 return "< unknown >";
226
227 }
228
229 /*****************************************************************************/
230
dng_lock_mutex(dng_mutex * mutex)231 dng_lock_mutex::dng_lock_mutex (dng_mutex *mutex)
232
233 : fMutex (mutex)
234
235 {
236
237 if (fMutex)
238 fMutex->Lock ();
239
240 }
241
242 /*****************************************************************************/
243
~dng_lock_mutex()244 dng_lock_mutex::~dng_lock_mutex ()
245 {
246
247 if (fMutex)
248 fMutex->Unlock ();
249
250 }
251
252 /*****************************************************************************/
253
dng_unlock_mutex(dng_mutex * mutex)254 dng_unlock_mutex::dng_unlock_mutex (dng_mutex *mutex)
255
256 : fMutex (mutex)
257
258 {
259
260 if (fMutex)
261 fMutex->Unlock ();
262
263 }
264
265 /*****************************************************************************/
266
~dng_unlock_mutex()267 dng_unlock_mutex::~dng_unlock_mutex ()
268 {
269
270 if (fMutex)
271 fMutex->Lock ();
272
273 }
274
275 /*****************************************************************************/
276
277 #if qDNGThreadSafe
278
279 /*****************************************************************************/
280
dng_condition()281 dng_condition::dng_condition ()
282
283 : fPthreadCondition ()
284
285 {
286
287 int result;
288
289 result = pthread_cond_init (&fPthreadCondition, NULL);
290
291 DNG_ASSERT (result == 0, "pthread_cond_init failed.");
292
293 if (result != 0)
294 {
295 ThrowProgramError ();
296 }
297
298 }
299
300 /*****************************************************************************/
301
~dng_condition()302 dng_condition::~dng_condition ()
303 {
304
305 pthread_cond_destroy (&fPthreadCondition);
306
307 }
308
309 /*****************************************************************************/
310
Wait(dng_mutex & mutex,double timeoutSecs)311 bool dng_condition::Wait (dng_mutex &mutex, double timeoutSecs)
312 {
313
314 bool timedOut = false;
315
316 dng_mutex *innermostMutex = gInnermostMutexHolder.GetInnermostMutex ();
317
318 DNG_ASSERT (innermostMutex == &mutex, "Attempt to wait on non-innermost mutex.");
319
320 innermostMutex = mutex.fPrevHeldMutex;
321
322 gInnermostMutexHolder.SetInnermostMutex (innermostMutex);
323
324 mutex.fPrevHeldMutex = NULL;
325
326 if (timeoutSecs < 0)
327 {
328
329 pthread_cond_wait (&fPthreadCondition, &mutex.fPthreadMutex);
330
331 }
332
333 else
334 {
335
336 struct timespec now;
337
338 dng_pthread_now (&now);
339
340 timeoutSecs += now.tv_sec;
341 timeoutSecs += now.tv_nsec / 1000000000.0;
342
343 now.tv_sec = (long) timeoutSecs;
344 now.tv_nsec = (long) ((timeoutSecs - now.tv_sec) * 1000000000);
345
346 timedOut = (pthread_cond_timedwait (&fPthreadCondition, &mutex.fPthreadMutex, &now) == ETIMEDOUT);
347
348 }
349
350 mutex.fPrevHeldMutex = innermostMutex;
351
352 gInnermostMutexHolder.SetInnermostMutex (&mutex);
353
354 return !timedOut;
355
356 }
357
358 /*****************************************************************************/
359
Signal()360 void dng_condition::Signal ()
361 {
362
363 int result;
364
365 result = pthread_cond_signal (&fPthreadCondition);
366
367 DNG_ASSERT (result == 0, "pthread_cond_signal failed.");
368
369 if (result != 0)
370 ThrowProgramError ();
371
372 }
373
374 /*****************************************************************************/
375
Broadcast()376 void dng_condition::Broadcast ()
377 {
378
379 int result;
380
381 result = pthread_cond_broadcast (&fPthreadCondition);
382
383 DNG_ASSERT (result == 0, "pthread_cond_broadcast failed.");
384
385 if (result != 0)
386 ThrowProgramError ();
387
388 }
389
390 /*****************************************************************************/
391
392 #endif // qDNGThreadSafe
393
394 /*****************************************************************************/
395