/src/dng_sdk/source/dng_mutex.cpp
Line | Count | Source (jump to first uncovered line) |
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 | | |
37 | | InnermostMutexHolder () |
38 | | |
39 | | : fInnermostMutexKey () |
40 | | |
41 | 10 | { |
42 | | |
43 | 10 | int result = pthread_key_create (&fInnermostMutexKey, NULL); |
44 | | |
45 | 10 | DNG_ASSERT (result == 0, "pthread_key_create failed."); |
46 | | |
47 | 10 | if (result != 0) |
48 | 0 | ThrowProgramError (); |
49 | | |
50 | 10 | } |
51 | | |
52 | | ~InnermostMutexHolder () |
53 | 0 | { |
54 | | |
55 | 0 | pthread_key_delete (fInnermostMutexKey); |
56 | | |
57 | 0 | } |
58 | | |
59 | | void SetInnermostMutex (dng_mutex *mutex) |
60 | 16.1M | { |
61 | | |
62 | 16.1M | int result; |
63 | | |
64 | 16.1M | result = pthread_setspecific (fInnermostMutexKey, (void *)mutex); |
65 | | |
66 | 16.1M | 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 | 16.1M | } |
76 | | |
77 | | dng_mutex *GetInnermostMutex () |
78 | 8.08M | { |
79 | | |
80 | 8.08M | void *result = pthread_getspecific (fInnermostMutexKey); |
81 | | |
82 | 8.08M | return reinterpret_cast<dng_mutex *> (result); |
83 | | |
84 | 8.08M | } |
85 | | |
86 | | }; |
87 | | |
88 | | InnermostMutexHolder gInnermostMutexHolder; |
89 | | |
90 | | } |
91 | | |
92 | | #endif |
93 | | |
94 | | /*****************************************************************************/ |
95 | | |
96 | | dng_mutex::dng_mutex (const char *mutexName, uint32 mutexLevel) |
97 | | |
98 | | #if qDNGThreadSafe |
99 | | |
100 | 19.7k | : fPthreadMutex () |
101 | 19.7k | , fMutexLevel (mutexLevel) |
102 | 19.7k | , fRecursiveLockCount (0) |
103 | | , fPrevHeldMutex (NULL) |
104 | 19.7k | , fMutexName (mutexName) |
105 | | |
106 | | #endif |
107 | | |
108 | 19.7k | { |
109 | | |
110 | 19.7k | #if qDNGThreadSafe |
111 | | |
112 | 19.7k | if (pthread_mutex_init (&fPthreadMutex, NULL) != 0) |
113 | 0 | { |
114 | 0 | ThrowMemoryFull (); |
115 | 0 | } |
116 | | |
117 | 19.7k | #endif |
118 | | |
119 | 19.7k | } |
120 | | |
121 | | /*****************************************************************************/ |
122 | | |
123 | | dng_mutex::~dng_mutex () |
124 | 19.7k | { |
125 | | |
126 | 19.7k | #if qDNGThreadSafe |
127 | | |
128 | 19.7k | pthread_mutex_destroy (&fPthreadMutex); |
129 | | |
130 | 19.7k | #endif |
131 | | |
132 | 19.7k | } |
133 | | |
134 | | /*****************************************************************************/ |
135 | | |
136 | | void dng_mutex::Lock () |
137 | 8.08M | { |
138 | | |
139 | 8.08M | #if qDNGThreadSafe |
140 | | |
141 | 8.08M | dng_mutex *innermostMutex = gInnermostMutexHolder.GetInnermostMutex (); |
142 | | |
143 | 8.08M | if (innermostMutex != NULL) |
144 | 0 | { |
145 | |
|
146 | 0 | if (innermostMutex == this) |
147 | 0 | { |
148 | |
|
149 | 0 | fRecursiveLockCount++; |
150 | |
|
151 | 0 | return; |
152 | |
|
153 | 0 | } |
154 | | |
155 | 0 | bool lockOrderPreserved = fMutexLevel > innermostMutex->fMutexLevel /* || |
156 | 0 | (fMutexLevel == innermostMutex->fMutexLevel && innermostMutex < this) */; |
157 | |
|
158 | 0 | if (!lockOrderPreserved) |
159 | 0 | { |
160 | | |
161 | 0 | 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 | 0 | } |
172 | |
|
173 | 0 | } |
174 | | |
175 | 8.08M | pthread_mutex_lock (&fPthreadMutex); |
176 | | |
177 | 8.08M | fPrevHeldMutex = innermostMutex; |
178 | | |
179 | 8.08M | gInnermostMutexHolder.SetInnermostMutex (this); |
180 | | |
181 | 8.08M | #endif |
182 | | |
183 | 8.08M | } |
184 | | |
185 | | /*****************************************************************************/ |
186 | | |
187 | | void dng_mutex::Unlock () |
188 | 8.08M | { |
189 | | |
190 | 8.08M | #if qDNGThreadSafe |
191 | | |
192 | 8.08M | DNG_ASSERT (gInnermostMutexHolder.GetInnermostMutex () == this, "Mutexes unlocked out of order!!!"); |
193 | | |
194 | 8.08M | if (fRecursiveLockCount > 0) |
195 | 0 | { |
196 | |
|
197 | 0 | fRecursiveLockCount--; |
198 | |
|
199 | 0 | return; |
200 | |
|
201 | 0 | } |
202 | | |
203 | 8.08M | gInnermostMutexHolder.SetInnermostMutex (fPrevHeldMutex); |
204 | | |
205 | 8.08M | fPrevHeldMutex = NULL; |
206 | | |
207 | 8.08M | pthread_mutex_unlock (&fPthreadMutex); |
208 | | |
209 | 8.08M | #endif |
210 | | |
211 | 8.08M | } |
212 | | |
213 | | /*****************************************************************************/ |
214 | | |
215 | | const char *dng_mutex::MutexName () const |
216 | 0 | { |
217 | | |
218 | 0 | #if qDNGThreadSafe |
219 | | |
220 | 0 | if (fMutexName) |
221 | 0 | return fMutexName; |
222 | | |
223 | 0 | #endif |
224 | | |
225 | 0 | return "< unknown >"; |
226 | | |
227 | 0 | } |
228 | | |
229 | | /*****************************************************************************/ |
230 | | |
231 | | dng_lock_mutex::dng_lock_mutex (dng_mutex *mutex) |
232 | | |
233 | 8.08M | : fMutex (mutex) |
234 | | |
235 | 8.08M | { |
236 | | |
237 | 8.08M | if (fMutex) |
238 | 8.08M | fMutex->Lock (); |
239 | | |
240 | 8.08M | } |
241 | | |
242 | | /*****************************************************************************/ |
243 | | |
244 | | dng_lock_mutex::~dng_lock_mutex () |
245 | 8.08M | { |
246 | | |
247 | 8.08M | if (fMutex) |
248 | 8.08M | fMutex->Unlock (); |
249 | | |
250 | 8.08M | } |
251 | | |
252 | | /*****************************************************************************/ |
253 | | |
254 | | dng_unlock_mutex::dng_unlock_mutex (dng_mutex *mutex) |
255 | | |
256 | 0 | : fMutex (mutex) |
257 | | |
258 | 0 | { |
259 | | |
260 | 0 | if (fMutex) |
261 | 0 | fMutex->Unlock (); |
262 | | |
263 | 0 | } |
264 | | |
265 | | /*****************************************************************************/ |
266 | | |
267 | | dng_unlock_mutex::~dng_unlock_mutex () |
268 | 0 | { |
269 | | |
270 | 0 | if (fMutex) |
271 | 0 | fMutex->Lock (); |
272 | | |
273 | 0 | } |
274 | | |
275 | | /*****************************************************************************/ |
276 | | |
277 | | #if qDNGThreadSafe |
278 | | |
279 | | /*****************************************************************************/ |
280 | | |
281 | | dng_condition::dng_condition () |
282 | | |
283 | 10 | : fPthreadCondition () |
284 | | |
285 | 10 | { |
286 | | |
287 | 10 | int result; |
288 | | |
289 | 10 | result = pthread_cond_init (&fPthreadCondition, NULL); |
290 | | |
291 | 10 | DNG_ASSERT (result == 0, "pthread_cond_init failed."); |
292 | | |
293 | 10 | if (result != 0) |
294 | 0 | { |
295 | 0 | ThrowProgramError (); |
296 | 0 | } |
297 | | |
298 | 10 | } |
299 | | |
300 | | /*****************************************************************************/ |
301 | | |
302 | | dng_condition::~dng_condition () |
303 | 0 | { |
304 | | |
305 | 0 | pthread_cond_destroy (&fPthreadCondition); |
306 | | |
307 | 0 | } |
308 | | |
309 | | /*****************************************************************************/ |
310 | | |
311 | | bool dng_condition::Wait (dng_mutex &mutex, double timeoutSecs) |
312 | 0 | { |
313 | |
|
314 | 0 | bool timedOut = false; |
315 | |
|
316 | 0 | dng_mutex *innermostMutex = gInnermostMutexHolder.GetInnermostMutex (); |
317 | |
|
318 | 0 | DNG_ASSERT (innermostMutex == &mutex, "Attempt to wait on non-innermost mutex."); |
319 | |
|
320 | 0 | innermostMutex = mutex.fPrevHeldMutex; |
321 | |
|
322 | 0 | gInnermostMutexHolder.SetInnermostMutex (innermostMutex); |
323 | |
|
324 | 0 | mutex.fPrevHeldMutex = NULL; |
325 | |
|
326 | 0 | if (timeoutSecs < 0) |
327 | 0 | { |
328 | | |
329 | 0 | pthread_cond_wait (&fPthreadCondition, &mutex.fPthreadMutex); |
330 | | |
331 | 0 | } |
332 | | |
333 | 0 | else |
334 | 0 | { |
335 | | |
336 | 0 | struct timespec now; |
337 | |
|
338 | 0 | dng_pthread_now (&now); |
339 | |
|
340 | 0 | timeoutSecs += now.tv_sec; |
341 | 0 | timeoutSecs += now.tv_nsec / 1000000000.0; |
342 | |
|
343 | 0 | now.tv_sec = (long) timeoutSecs; |
344 | 0 | now.tv_nsec = (long) ((timeoutSecs - now.tv_sec) * 1000000000); |
345 | |
|
346 | 0 | timedOut = (pthread_cond_timedwait (&fPthreadCondition, &mutex.fPthreadMutex, &now) == ETIMEDOUT); |
347 | | |
348 | 0 | } |
349 | |
|
350 | 0 | mutex.fPrevHeldMutex = innermostMutex; |
351 | |
|
352 | 0 | gInnermostMutexHolder.SetInnermostMutex (&mutex); |
353 | |
|
354 | 0 | return !timedOut; |
355 | |
|
356 | 0 | } |
357 | | |
358 | | /*****************************************************************************/ |
359 | | |
360 | | void dng_condition::Signal () |
361 | 0 | { |
362 | |
|
363 | 0 | int result; |
364 | |
|
365 | 0 | result = pthread_cond_signal (&fPthreadCondition); |
366 | |
|
367 | 0 | DNG_ASSERT (result == 0, "pthread_cond_signal failed."); |
368 | |
|
369 | 0 | if (result != 0) |
370 | 0 | ThrowProgramError (); |
371 | |
|
372 | 0 | } |
373 | | |
374 | | /*****************************************************************************/ |
375 | | |
376 | | void dng_condition::Broadcast () |
377 | 0 | { |
378 | |
|
379 | 0 | int result; |
380 | |
|
381 | 0 | result = pthread_cond_broadcast (&fPthreadCondition); |
382 | |
|
383 | 0 | DNG_ASSERT (result == 0, "pthread_cond_broadcast failed."); |
384 | |
|
385 | 0 | if (result != 0) |
386 | 0 | ThrowProgramError (); |
387 | |
|
388 | 0 | } |
389 | | |
390 | | /*****************************************************************************/ |
391 | | |
392 | | #endif // qDNGThreadSafe |
393 | | |
394 | | /*****************************************************************************/ |