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 /*****************************************************************************/