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
25namespace
26 {
27
28 class InnermostMutexHolder
29 {
30
31 private:
32
33 pthread_key_t fInnermostMutexKey;
34
35 public:
36
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
52 ~InnermostMutexHolder ()
53 {
54
55 pthread_key_delete (fInnermostMutexKey);
56
57 }
58
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
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
96dng_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
123dng_mutex::~dng_mutex ()
124 {
125
126 #if qDNGThreadSafe
127
128 pthread_mutex_destroy (&fPthreadMutex);
129
130 #endif
131
132 }
133
134/*****************************************************************************/
135
136void 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
187void 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
215const 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
231dng_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
244dng_lock_mutex::~dng_lock_mutex ()
245 {
246
247 if (fMutex)
248 fMutex->Unlock ();
249
250 }
251
252/*****************************************************************************/
253
254dng_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
267dng_unlock_mutex::~dng_unlock_mutex ()
268 {
269
270 if (fMutex)
271 fMutex->Lock ();
272
273 }
274
275/*****************************************************************************/
276
277#if qDNGThreadSafe
278
279/*****************************************************************************/
280
281dng_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
302dng_condition::~dng_condition ()
303 {
304
305 pthread_cond_destroy (&fPthreadCondition);
306
307 }
308
309/*****************************************************************************/
310
311bool 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
360void 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
376void 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