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 { 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 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 123 dng_mutex::~dng_mutex () 124 { 125 126 #if qDNGThreadSafe 127 128 pthread_mutex_destroy (&fPthreadMutex); 129 130 #endif 131 132 } 133 134 /*****************************************************************************/ 135 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 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 215 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 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 244 dng_lock_mutex::~dng_lock_mutex () 245 { 246 247 if (fMutex) 248 fMutex->Unlock (); 249 250 } 251 252 /*****************************************************************************/ 253 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 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 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 302 dng_condition::~dng_condition () 303 { 304 305 pthread_cond_destroy (&fPthreadCondition); 306 307 } 308 309 /*****************************************************************************/ 310 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 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 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