File indexing completed on 2025-01-19 03:55:07
0001 /*****************************************************************************/ 0002 // Copyright 2006-2019 Adobe Systems Incorporated 0003 // All Rights Reserved. 0004 // 0005 // NOTICE: Adobe permits you to use, modify, and distribute this file in 0006 // accordance with the terms of the Adobe license agreement accompanying it. 0007 /*****************************************************************************/ 0008 0009 #include "dng_abort_sniffer.h" 0010 #include "dng_mutex.h" 0011 0012 #include "dng_assertions.h" 0013 #include "dng_exceptions.h" 0014 0015 #include <stdlib.h> 0016 0017 /*****************************************************************************/ 0018 0019 // do mutex lock level tracking, asserts stripped in non-debug so don't track there 0020 #ifndef qDNGThreadTestMutexLevels 0021 #define qDNGThreadTestMutexLevels (qDNGThreadSafe && qDNGDebug) 0022 #endif 0023 0024 #if qDNGThreadTestMutexLevels 0025 namespace 0026 { 0027 0028 class InnermostMutexHolder 0029 { 0030 0031 private: 0032 0033 pthread_key_t fInnermostMutexKey; 0034 0035 public: 0036 0037 InnermostMutexHolder () 0038 0039 : fInnermostMutexKey () 0040 0041 { 0042 0043 int result = pthread_key_create (&fInnermostMutexKey, NULL); 0044 0045 DNG_ASSERT (result == 0, "pthread_key_create failed."); 0046 0047 if (result != 0) 0048 ThrowProgramError (); 0049 0050 } 0051 0052 ~InnermostMutexHolder () 0053 { 0054 0055 pthread_key_delete (fInnermostMutexKey); 0056 0057 } 0058 0059 void SetInnermostMutex (dng_mutex *mutex) 0060 { 0061 0062 int result; 0063 0064 result = pthread_setspecific (fInnermostMutexKey, (void *)mutex); 0065 0066 DNG_ASSERT (result == 0, "pthread_setspecific failed."); 0067 0068 (void) result; 0069 0070 #if 0 // Hard failure here was causing crash on quit. 0071 0072 if (result != 0) 0073 ThrowProgramError (); 0074 0075 #endif 0076 0077 } 0078 0079 dng_mutex *GetInnermostMutex () 0080 { 0081 0082 void *result = pthread_getspecific (fInnermostMutexKey); 0083 0084 return reinterpret_cast<dng_mutex *> (result); 0085 0086 } 0087 0088 }; 0089 0090 InnermostMutexHolder gInnermostMutexHolder; 0091 0092 } 0093 0094 #endif 0095 0096 /*****************************************************************************/ 0097 0098 dng_mutex::dng_mutex (const char *mutexName, uint32 mutexLevel) 0099 0100 #if qDNGThreadSafe 0101 0102 : fPthreadMutex () 0103 , fMutexLevel (mutexLevel) 0104 , fRecursiveLockCount (0) 0105 , fPrevHeldMutex (NULL) 0106 , fMutexName (mutexName) 0107 0108 #endif 0109 0110 { 0111 0112 #if qDNGThreadSafe 0113 0114 #if qWinOS 0115 0116 // Win is already a recursive mutex by default 0117 if (pthread_mutex_init (&fPthreadMutex, NULL) != 0) 0118 { 0119 ThrowMemoryFull (); 0120 } 0121 0122 #else 0123 0124 // make recursive mutex, can lock within itself 0125 pthread_mutexattr_t mta; 0126 pthread_mutexattr_init(&mta); 0127 pthread_mutexattr_settype(&mta, PTHREAD_MUTEX_RECURSIVE); 0128 0129 if (pthread_mutex_init (&fPthreadMutex, &mta) != 0) 0130 { 0131 ThrowMemoryFull (); 0132 } 0133 #endif 0134 0135 #endif 0136 0137 } 0138 0139 /*****************************************************************************/ 0140 0141 dng_mutex::~dng_mutex () 0142 { 0143 0144 #if qDNGThreadSafe 0145 0146 pthread_mutex_destroy (&fPthreadMutex); 0147 0148 #endif 0149 0150 } 0151 0152 /*****************************************************************************/ 0153 0154 void dng_mutex::Lock () 0155 { 0156 0157 #if qDNGThreadSafe 0158 #if qDNGThreadTestMutexLevels 0159 0160 dng_mutex *innermostMutex = gInnermostMutexHolder.GetInnermostMutex (); 0161 0162 if (innermostMutex != NULL) 0163 { 0164 0165 if (innermostMutex == this) 0166 { 0167 0168 int result = pthread_mutex_lock (&fPthreadMutex); 0169 0170 if (result != 0) 0171 { 0172 0173 DNG_ASSERT (result == 0, "pthread_mutex_lock failed."); 0174 0175 ThrowProgramError (); 0176 0177 } 0178 0179 fRecursiveLockCount++; 0180 0181 return; 0182 0183 } 0184 0185 bool lockOrderPreserved = fMutexLevel > innermostMutex->fMutexLevel; 0186 0187 // to allow cloning of class internals both with a dng_mutex and get closer to the C++ mutex, 0188 // test for MutexLevelIgnore and don't generate level violations 0189 if (!lockOrderPreserved) 0190 { 0191 0192 if ((fMutexLevel == kDNGMutexLevelIgnore) || (innermostMutex->fMutexLevel == kDNGMutexLevelIgnore)) 0193 lockOrderPreserved = true; 0194 0195 } 0196 0197 if (!lockOrderPreserved) 0198 { 0199 0200 char msg[1024]; 0201 0202 sprintf(msg, 0203 "Lock order violation: This mutex: %s v Innermost mutex: %s", 0204 this->MutexName (), 0205 innermostMutex->MutexName ()); 0206 0207 DNG_REPORT(msg); // asserts inside of mutex lock, any locks within that must be lower 0208 0209 } 0210 0211 } 0212 0213 int result = pthread_mutex_lock (&fPthreadMutex); 0214 0215 if (result != 0) 0216 { 0217 0218 DNG_ASSERT (result == 0, "pthread_mutex_lock failed."); 0219 0220 ThrowProgramError (); 0221 0222 } 0223 0224 fPrevHeldMutex = innermostMutex; 0225 0226 gInnermostMutexHolder.SetInnermostMutex (this); 0227 0228 #else 0229 0230 // Register the fact that we're trying to lock this mutex. 0231 0232 int result = pthread_mutex_lock (&fPthreadMutex); 0233 0234 if (result != 0) 0235 { 0236 0237 DNG_REPORT ("pthread_mutex_lock failed"); 0238 0239 ThrowProgramError (); 0240 0241 } 0242 0243 // Register the fact that we've now successfully acquired the mutex. 0244 0245 #endif 0246 #endif 0247 0248 } 0249 0250 /*****************************************************************************/ 0251 0252 void dng_mutex::Unlock () 0253 { 0254 0255 #if qDNGThreadSafe 0256 #if qDNGThreadTestMutexLevels 0257 0258 DNG_ASSERT (gInnermostMutexHolder.GetInnermostMutex () == this, "Mutexes unlocked out of order!!!"); 0259 0260 if (fRecursiveLockCount > 0) 0261 { 0262 0263 fRecursiveLockCount--; 0264 0265 pthread_mutex_unlock (&fPthreadMutex); 0266 0267 return; 0268 0269 } 0270 0271 gInnermostMutexHolder.SetInnermostMutex (fPrevHeldMutex); 0272 0273 fPrevHeldMutex = NULL; 0274 0275 #endif 0276 0277 pthread_mutex_unlock (&fPthreadMutex); 0278 0279 #endif 0280 0281 } 0282 0283 /*****************************************************************************/ 0284 0285 const char *dng_mutex::MutexName () const 0286 { 0287 0288 #if qDNGThreadSafe 0289 0290 if (fMutexName) 0291 return fMutexName; 0292 0293 #endif 0294 0295 return "< unknown >"; 0296 0297 } 0298 0299 /*****************************************************************************/ 0300 0301 dng_lock_mutex::dng_lock_mutex (dng_mutex *mutex) 0302 0303 : fMutex (mutex) 0304 0305 { 0306 0307 if (fMutex) 0308 fMutex->Lock (); 0309 0310 } 0311 0312 /*****************************************************************************/ 0313 0314 dng_lock_mutex::dng_lock_mutex (dng_mutex &mutex) 0315 0316 : fMutex (&mutex) 0317 0318 { 0319 0320 if (fMutex) 0321 fMutex->Lock (); 0322 0323 } 0324 0325 /*****************************************************************************/ 0326 0327 dng_lock_mutex::~dng_lock_mutex () 0328 { 0329 0330 if (fMutex) 0331 fMutex->Unlock (); 0332 0333 } 0334 0335 /*****************************************************************************/ 0336 0337 dng_unlock_mutex::dng_unlock_mutex (dng_mutex *mutex) 0338 0339 : fMutex (mutex) 0340 0341 { 0342 0343 if (fMutex) 0344 fMutex->Unlock (); 0345 0346 } 0347 0348 /*****************************************************************************/ 0349 0350 dng_unlock_mutex::dng_unlock_mutex (dng_mutex &mutex) 0351 0352 : fMutex (&mutex) 0353 0354 { 0355 0356 if (fMutex) 0357 fMutex->Unlock (); 0358 0359 } 0360 0361 /*****************************************************************************/ 0362 0363 dng_unlock_mutex::~dng_unlock_mutex () 0364 { 0365 0366 if (fMutex) 0367 fMutex->Lock (); 0368 0369 } 0370 0371 /*****************************************************************************/ 0372 0373 dng_condition::dng_condition () 0374 0375 #if qDNGThreadSafe 0376 : fPthreadCondition () 0377 #endif 0378 0379 { 0380 0381 #if qDNGThreadSafe 0382 int result; 0383 0384 result = pthread_cond_init (&fPthreadCondition, NULL); 0385 0386 DNG_ASSERT (result == 0, "pthread_cond_init failed."); 0387 0388 if (result != 0) 0389 { 0390 ThrowProgramError (); 0391 } 0392 #endif 0393 0394 } 0395 0396 /*****************************************************************************/ 0397 0398 dng_condition::~dng_condition () 0399 { 0400 #if qDNGThreadSafe 0401 pthread_cond_destroy (&fPthreadCondition); 0402 #endif 0403 } 0404 0405 /*****************************************************************************/ 0406 0407 bool dng_condition::Wait (dng_mutex &mutex, double timeoutSecs) 0408 { 0409 0410 #if qDNGThreadSafe 0411 bool timedOut = false; 0412 0413 #if qDNGThreadTestMutexLevels 0414 0415 dng_mutex *innermostMutex = gInnermostMutexHolder.GetInnermostMutex (); 0416 0417 DNG_ASSERT (innermostMutex == &mutex, "Attempt to wait on non-innermost mutex."); 0418 0419 (void) innermostMutex; 0420 0421 innermostMutex = mutex.fPrevHeldMutex; 0422 0423 gInnermostMutexHolder.SetInnermostMutex (innermostMutex); 0424 0425 mutex.fPrevHeldMutex = NULL; 0426 0427 #endif 0428 0429 if (timeoutSecs < 0) 0430 { 0431 0432 pthread_cond_wait (&fPthreadCondition, &mutex.fPthreadMutex); 0433 0434 } 0435 0436 else 0437 { 0438 0439 struct timespec now; 0440 0441 dng_pthread_now (&now); 0442 0443 timeoutSecs += now.tv_sec; 0444 timeoutSecs += now.tv_nsec / 1000000000.0; 0445 0446 now.tv_sec = (long) timeoutSecs; 0447 now.tv_nsec = (long) ((timeoutSecs - now.tv_sec) * 1000000000); 0448 0449 #if defined(_MSC_VER) && _MSC_VER >= 1900 0450 0451 struct dng_timespec tempNow; 0452 0453 tempNow.tv_sec = (long) now.tv_sec; 0454 tempNow.tv_nsec = now.tv_nsec; 0455 0456 timedOut = (pthread_cond_timedwait (&fPthreadCondition, &mutex.fPthreadMutex, &tempNow) == ETIMEDOUT); 0457 0458 #else 0459 0460 timedOut = (pthread_cond_timedwait (&fPthreadCondition, &mutex.fPthreadMutex, &now) == ETIMEDOUT); 0461 0462 #endif 0463 0464 } 0465 0466 #if qDNGThreadTestMutexLevels 0467 0468 mutex.fPrevHeldMutex = innermostMutex; 0469 0470 gInnermostMutexHolder.SetInnermostMutex (&mutex); 0471 0472 #endif 0473 0474 return !timedOut; 0475 #else 0476 return true; 0477 #endif 0478 0479 } 0480 0481 /*****************************************************************************/ 0482 0483 void dng_condition::Signal () 0484 { 0485 0486 #if qDNGThreadSafe 0487 int result; 0488 0489 result = pthread_cond_signal (&fPthreadCondition); 0490 0491 DNG_ASSERT (result == 0, "pthread_cond_signal failed."); 0492 0493 if (result != 0) 0494 ThrowProgramError (); 0495 #endif 0496 0497 } 0498 0499 /*****************************************************************************/ 0500 0501 void dng_condition::Broadcast () 0502 { 0503 #if qDNGThreadSafe 0504 0505 int result; 0506 0507 result = pthread_cond_broadcast (&fPthreadCondition); 0508 0509 DNG_ASSERT (result == 0, "pthread_cond_broadcast failed."); 0510 0511 if (result != 0) 0512 ThrowProgramError (); 0513 #endif 0514 } 0515 0516 /*****************************************************************************/