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