1 ////////////////////////////////////////////////////////////////////////////////
3 // LevelMutex facility for the Loki Library
4 // Copyright (c) 2008 Richard Sposato
5 // The copyright on this file is protected under the terms of the MIT license.
7 // Permission to use, copy, modify, distribute and sell this software for any
8 // purpose is hereby granted without fee, provided that the above copyright
9 // notice appear in all copies and that both that copyright notice and this
10 // permission notice appear in supporting documentation.
12 // The author makes no representations about the suitability of this software
13 // for any purpose. It is provided "as is" without express or implied warranty.
15 ////////////////////////////////////////////////////////////////////////////////
19 /// @file LevelMutex.cpp Contains functions needed by LevelMutex class.
21 // ----------------------------------------------------------------------------
23 #if (!defined(__CYGWIN__) || (defined(__CYGWIN__) && __GNUC__ > 3)) && !defined(__APPLE__)
25 #include <loki/LevelMutex.h>
31 using namespace ::std;
33 // define nullptr even though new compilers will have this keyword just so we
34 // have a consistent and easy way of identifying which uses of 0 mean null.
38 LOKI_THREAD_LOCAL volatile ::Loki::LevelMutexInfo *::Loki::LevelMutexInfo::s_currentMutex = nullptr;
40 unsigned int ::Loki::MutexSleepWaits::sleepTime = 1;
43 /// Anonymous namespace hides some functions which are implementation details.
47 // ----------------------------------------------------------------------------
49 /** Determines if the mutex at specific iterator location is unique within the
50 container of mutexes. It only checks mutexes at later locations in the
51 container instead of the entire container partly for efficiency sake. (Any
52 prior duplications would have gotten caught during earlier calls to this
53 function.) This should not throw exceptions. It requires O(m) operations
54 where m is the number of elements in the container after the iterator.
55 @param mutexes Container to check.
56 @param cit Location of mutex used for comparing.
57 @return True for uniqueness, false if a duplicate exists.
59 bool IsUniqueMutex( const ::Loki::LevelMutexInfo::MutexContainer &mutexes,
60 ::Loki::LevelMutexInfo::LevelMutexContainerCIter cit )
62 assert( mutexes.end() != cit );
64 const ::Loki::LevelMutexInfo::LevelMutexContainerCIter end = mutexes.end();
65 const volatile ::Loki::LevelMutexInfo *mutex = *cit;
66 for ( ++cit; cit != end; ++cit )
68 const volatile ::Loki::LevelMutexInfo *check = *cit;
75 // ----------------------------------------------------------------------------
77 /** Returns pointer to first mutex it finds in the container. This should not
78 throw, and takes O(1) most of the time. At worse, it takes O(m) operations
79 where m is the size of the container.
80 @param mutexes Container of mutexes.
81 @return Pointer to first mutex it finds, or nullptr if container is empty or
82 each element is a nullptr.
84 const volatile ::Loki::LevelMutexInfo *GetFirstMutex(
85 const ::Loki::LevelMutexInfo::MutexContainer &mutexes )
87 if ( mutexes.size() == 0 )
89 ::Loki::LevelMutexInfo::LevelMutexContainerCIter it( mutexes.begin() );
90 const volatile ::Loki::LevelMutexInfo *mutex = *it;
91 if ( nullptr != mutex )
94 const ::Loki::LevelMutexInfo::LevelMutexContainerCIter end( mutexes.end() );
98 if ( nullptr != mutex )
106 // ----------------------------------------------------------------------------
108 /** Gets the level number associated with the first mutex found in a container.
109 Usually takes O(1) operations, but take up to O(m) where m is the size of the
111 @return Level number of first mutex in container, or UnlockedLevel if no
112 mutexes were found in the container.
114 unsigned int GetLevel( const ::Loki::LevelMutexInfo::MutexContainer &mutexes )
116 const volatile ::Loki::LevelMutexInfo *mutex = GetFirstMutex( mutexes );
117 return ( nullptr == mutex ) ? ::Loki::LevelMutexInfo::UnlockedLevel : mutex->GetLevel();
120 // ----------------------------------------------------------------------------
122 } // end anonymous namespace
127 // ----------------------------------------------------------------------------
129 unsigned int GetCurrentThreadsLevel( void )
131 const volatile LevelMutexInfo *mutex = LevelMutexInfo::GetCurrentMutex();
132 return ( nullptr == mutex ) ? LevelMutexInfo::UnlockedLevel : mutex->GetLevel();
135 // ----------------------------------------------------------------------------
137 unsigned int CountMutexesInCurrentThread( void )
139 const volatile LevelMutexInfo *mutex = LevelMutexInfo::GetCurrentMutex();
140 unsigned int count = 0;
141 while ( nullptr != mutex )
144 mutex = mutex->GetPrevious();
149 // ----------------------------------------------------------------------------
151 unsigned int CountLocksInCurrentThread( void )
153 const volatile LevelMutexInfo *mutex = LevelMutexInfo::GetCurrentMutex();
154 unsigned int count = 0;
155 while ( nullptr != mutex )
157 count += mutex->GetLockCount();
158 mutex = mutex->GetPrevious();
163 // ----------------------------------------------------------------------------
165 unsigned int CountMutexesAtCurrentLevel( void )
167 const volatile LevelMutexInfo *mutex = LevelMutexInfo::GetCurrentMutex();
168 if ( nullptr == mutex )
170 unsigned int count = 0;
171 unsigned int level = mutex->GetLevel();
172 while ( nullptr != mutex )
174 if ( level != mutex->GetLevel() )
176 mutex = mutex->GetPrevious();
182 // ----------------------------------------------------------------------------
184 MutexErrors::Type DoMutexesMatchContainer( const LevelMutexInfo::MutexContainer &mutexes )
186 const unsigned int count = mutexes.size();
188 return MutexErrors::EmptyContainer;
189 unsigned int currentLevel = GetCurrentThreadsLevel();
190 const LevelMutexInfo::LevelMutexContainerCIter endSpot = mutexes.end();
192 for ( LevelMutexInfo::LevelMutexContainerCIter cit = mutexes.begin();
196 const volatile LevelMutexInfo *mutex = *cit;
197 if ( nullptr == mutex )
198 return MutexErrors::NullMutexPointer;
199 if ( currentLevel != mutex->GetLevel() )
201 return ( LevelMutexInfo::UnlockedLevel == currentLevel ) ?
202 MutexErrors::NotRecentLock : MutexErrors::WrongLevel;
204 if ( !mutex->IsRecentLock( count ) )
205 return MutexErrors::NotRecentLock;
206 if ( !IsUniqueMutex( mutexes, cit ) )
207 return MutexErrors::DuplicateMutex;
210 if ( count != CountMutexesAtCurrentLevel() )
211 return MutexErrors::LevelTooHigh;
213 return MutexErrors::Success;
216 // ----------------------------------------------------------------------------
218 LevelMutexInfo::MutexUndoer::MutexUndoer( MutexContainer &mutexes ) :
219 m_mutexes( mutexes ),
220 m_here( mutexes.end() )
222 assert( this != nullptr );
225 // ----------------------------------------------------------------------------
227 LevelMutexInfo::MutexUndoer::~MutexUndoer( void )
229 assert( this != nullptr );
232 if ( m_here == m_mutexes.end() )
234 LevelMutexContainerRIter rend( m_mutexes.rend() );
235 LevelMutexContainerRIter rit( m_here );
237 for ( ; rit != rend; ++rit )
239 volatile ::Loki::LevelMutexInfo *mutex = *rit;
240 assert( nullptr != mutex );
249 // ----------------------------------------------------------------------------
251 void LevelMutexInfo::MutexUndoer::SetPlace( LevelMutexContainerIter &here )
253 assert( this != nullptr );
257 // ----------------------------------------------------------------------------
259 void LevelMutexInfo::MutexUndoer::Cancel( void )
261 assert( this != nullptr );
262 m_here = m_mutexes.end();
265 // ----------------------------------------------------------------------------
267 const volatile LevelMutexInfo *LevelMutexInfo::GetCurrentMutex( void )
269 assert( IsValidList() );
270 return s_currentMutex;
273 // ----------------------------------------------------------------------------
275 bool LevelMutexInfo::IsValidList( void )
277 const volatile LevelMutexInfo *mutex1 = s_currentMutex;
278 const volatile LevelMutexInfo *mutex2 = s_currentMutex;
279 if ( nullptr == mutex1 )
282 while ( nullptr != mutex2 )
284 if ( nullptr == mutex2 )
286 mutex2 = mutex2->m_previous;
287 if ( mutex1 == mutex2 )
289 if ( nullptr == mutex2 )
291 mutex2 = mutex2->m_previous;
292 if ( mutex1 == mutex2 )
294 if ( nullptr == mutex2 )
296 mutex1 = mutex1->m_previous;
297 if ( nullptr == mutex1 )
301 mutex1 = s_currentMutex;
302 unsigned int level = mutex1->m_level;
303 while ( nullptr != mutex1 )
305 if ( level > mutex1->m_level )
307 level = mutex1->m_level;
308 mutex1 = mutex1->m_previous;
314 // ----------------------------------------------------------------------------
316 MutexErrors::Type LevelMutexInfo::MultiLock( MutexContainer &mutexes )
318 assert( IsValidList() );
320 const unsigned int count = mutexes.size();
322 return MutexErrors::EmptyContainer;
324 LevelMutexContainerIter it( mutexes.begin() );
325 volatile LevelMutexInfo *mutex = *it;
326 if ( nullptr == mutex )
327 return MutexErrors::NullMutexPointer;
328 // Since the pointer to the first mutex is not NULL, save it so we use it
329 // to call the derived class and check for errors.
330 const volatile LevelMutexInfo *const first = mutex;
331 if ( !IsUniqueMutex( mutexes, it ) )
332 return MutexErrors::DuplicateMutex;
333 const unsigned int checkLevel = mutex->GetLevel();
334 const unsigned int currentLevel = GetCurrentThreadsLevel();
335 if ( currentLevel < checkLevel )
337 return first->DoErrorCheck( MutexErrors::LevelTooHigh );
340 const LevelMutexContainerIter end( mutexes.end() );
341 if ( currentLevel == checkLevel )
343 MutexErrors::Type result = DoMutexesMatchContainer( mutexes );
344 if ( MutexErrors::Success != result )
346 if ( LevelMutexInfo::UnlockedLevel == currentLevel )
348 return first->DoErrorCheck( result );
350 return first->DoErrorCheck( MutexErrors::LevelTooHigh );
352 for ( it = mutexes.begin(); it != end; ++it )
355 mutex->IncrementCount();
357 return MutexErrors::Success;
359 assert( !mutex->IsRecentLock( count ) );
363 for ( ++it; it != end; ++it )
366 if ( nullptr == mutex )
367 return first->DoErrorCheck( MutexErrors::NullMutexPointer );
368 const unsigned int level = mutex->GetLevel();
369 if ( checkLevel != level )
370 return first->DoErrorCheck( MutexErrors::WrongLevel );
371 if ( !IsUniqueMutex( mutexes, it ) )
372 return first->DoErrorCheck( MutexErrors::DuplicateMutex );
373 assert( !mutex->IsRecentLock( count ) );
376 it = mutexes.begin();
377 ::std::sort( it, end );
380 MutexUndoer undoer( mutexes );
381 for ( ; it != end; ++it )
384 const MutexErrors::Type result = mutex->LockThis();
385 if ( MutexErrors::Success != result )
386 return first->DoErrorCheck( result );
387 undoer.SetPlace( it );
391 return MutexErrors::Success;
394 // ----------------------------------------------------------------------------
396 MutexErrors::Type LevelMutexInfo::MultiLock( MutexContainer &mutexes,
397 unsigned int milliSeconds )
399 assert( IsValidList() );
401 if ( 0 == milliSeconds )
402 return MultiLock( mutexes );
403 const unsigned int count = mutexes.size();
405 return MutexErrors::EmptyContainer;
407 LevelMutexContainerIter it( mutexes.begin() );
408 volatile LevelMutexInfo *mutex = *it;
409 if ( nullptr == mutex )
410 return MutexErrors::NullMutexPointer;
411 // Since the pointer to the first mutex is not NULL, save it so we use it
412 // to call the derived class and check for errors.
413 const volatile LevelMutexInfo *const first = mutex;
414 if ( !IsUniqueMutex( mutexes, it ) )
415 return first->DoErrorCheck( MutexErrors::DuplicateMutex );
416 const unsigned int checkLevel = mutex->GetLevel();
417 const unsigned int currentLevel = GetCurrentThreadsLevel();
418 if ( currentLevel < checkLevel )
420 return first->DoErrorCheck( MutexErrors::LevelTooHigh );
423 const LevelMutexContainerIter end( mutexes.end() );
424 if ( currentLevel == checkLevel )
426 MutexErrors::Type result = DoMutexesMatchContainer( mutexes );
427 if ( MutexErrors::Success != result )
429 if ( LevelMutexInfo::UnlockedLevel == currentLevel )
431 return first->DoErrorCheck( result );
433 return first->DoErrorCheck( MutexErrors::LevelTooHigh );
435 for ( it = mutexes.begin(); it != end; ++it )
438 mutex->IncrementCount();
440 return MutexErrors::Success;
442 assert( !mutex->IsRecentLock( count ) );
446 for ( ++it; it != end; ++it )
449 if ( nullptr == mutex )
450 return first->DoErrorCheck( MutexErrors::NullMutexPointer );
451 const unsigned int level = mutex->GetLevel();
452 if ( checkLevel != level )
453 return first->DoErrorCheck( MutexErrors::WrongLevel );
454 if ( !IsUniqueMutex( mutexes, it ) )
455 return first->DoErrorCheck( MutexErrors::DuplicateMutex );
456 assert( !mutex->IsRecentLock( count ) );
459 it = mutexes.begin();
460 ::std::sort( it, end );
463 MutexUndoer undoer( mutexes );
464 for ( ; it != end; ++it )
467 const MutexErrors::Type result = mutex->LockThis( milliSeconds );
468 if ( MutexErrors::Success != result )
469 return first->DoErrorCheck( result );
470 undoer.SetPlace( it );
474 return MutexErrors::Success;
477 // ----------------------------------------------------------------------------
479 MutexErrors::Type LevelMutexInfo::MultiUnlock( MutexContainer &mutexes )
481 assert( IsValidList() );
483 MutexErrors::Type result = DoMutexesMatchContainer( mutexes );
484 if ( result != MutexErrors::Success )
486 const volatile LevelMutexInfo *const mutex = GetFirstMutex( mutexes );
487 if ( nullptr != mutex )
488 return mutex->DoErrorCheck( result );
489 throw MutexException( "Unable to unlock mutexes in container.",
490 LevelMutexInfo::UnlockedLevel, result );
493 const unsigned int count = mutexes.size();
496 ::std::sort( mutexes.begin(), mutexes.end() );
500 LevelMutexContainerRIter rit( mutexes.rbegin() );
501 const LevelMutexContainerRIter rend( mutexes.rend() );
502 for ( ; rit != rend; ++rit )
506 volatile LevelMutexInfo *mutex = *rit;
507 result = mutex->UnlockThis();
508 if ( MutexErrors::Success != result )
514 // If one fails to unlock, keep trying to unlock the others.
515 // So don't just exit the for loop. This keeps going instead
516 // of trying to relock the mutex and exit since it is not
517 // safe to leave some locked, but not others.
521 return ( failed ) ? MutexErrors::MultiUnlockFailed : MutexErrors::Success;
524 // ----------------------------------------------------------------------------
526 LevelMutexInfo::LevelMutexInfo( unsigned int level ) :
529 m_previous( nullptr )
534 // ----------------------------------------------------------------------------
536 LevelMutexInfo::~LevelMutexInfo( void )
539 assert( 0 == m_count );
540 assert( nullptr == m_previous );
543 // ----------------------------------------------------------------------------
545 bool LevelMutexInfo::IsValid( void ) const volatile
547 assert( nullptr != this );
548 assert( LevelMutexInfo::UnlockedLevel != m_level );
549 assert( m_previous != this );
550 assert( ( nullptr == m_previous ) || ( 0 < m_count ) );
551 assert( IsValidList() );
555 // ----------------------------------------------------------------------------
557 void LevelMutexInfo::IncrementCount( void ) volatile
560 assert( 0 < m_count );
564 // ----------------------------------------------------------------------------
566 void LevelMutexInfo::DecrementCount( void ) volatile
569 assert( 0 < m_count );
573 // ----------------------------------------------------------------------------
575 bool LevelMutexInfo::IsLockedByCurrentThread( void ) const volatile
578 LOKI_MUTEX_DEBUG_CODE( Checker checker( this ); (void)checker; )
582 const volatile LevelMutexInfo *mutex = s_currentMutex;
583 while ( nullptr != mutex )
587 mutex = mutex->m_previous;
592 // ----------------------------------------------------------------------------
594 bool LevelMutexInfo::IsRecentLock( void ) const volatile
597 LOKI_MUTEX_DEBUG_CODE( Checker checker( this ); (void)checker; )
601 const volatile LevelMutexInfo *mutex = s_currentMutex;
602 while ( nullptr != mutex )
604 assert( m_level <= mutex->m_level );
607 if ( m_level != mutex->m_level )
609 mutex = mutex->m_previous;
614 // ----------------------------------------------------------------------------
616 bool LevelMutexInfo::IsRecentLock( unsigned int count ) const volatile
619 LOKI_MUTEX_DEBUG_CODE( Checker checker( this ); (void)checker; )
623 const volatile LevelMutexInfo *mutex = s_currentMutex;
624 for ( ; count > 0; count-- )
626 if ( nullptr == mutex )
630 mutex = mutex->m_previous;
635 // ----------------------------------------------------------------------------
637 bool LevelMutexInfo::IsLockedByAnotherThread( void ) const volatile
640 LOKI_MUTEX_DEBUG_CODE( Checker checker( this ); (void)checker; )
644 if ( IsLockedByCurrentThread() )
651 // ----------------------------------------------------------------------------
653 void LevelMutexInfo::PostLock( void ) volatile
656 assert( 0 == m_count );
657 assert( nullptr == m_previous );
658 assert( this != s_currentMutex );
659 assert( !IsLockedByCurrentThread() );
660 LOKI_MUTEX_DEBUG_CODE( Checker checker( this ); (void)checker; )
663 m_previous = s_currentMutex;
664 s_currentMutex = this;
667 // ----------------------------------------------------------------------------
669 void LevelMutexInfo::PreUnlock( void ) volatile
672 assert( 1 == m_count );
673 assert( nullptr != s_currentMutex );
674 assert( this == s_currentMutex );
675 assert( IsLockedByCurrentThread() );
676 LOKI_MUTEX_DEBUG_CODE( Checker checker( this ); (void)checker; )
678 s_currentMutex = m_previous;
679 m_previous = nullptr;
683 // ----------------------------------------------------------------------------
685 MutexErrors::Type LevelMutexInfo::PreLockCheck( bool forTryLock ) volatile
688 LOKI_MUTEX_DEBUG_CODE( Checker checker( this ); (void)checker; )
690 const unsigned int currentLevel = GetCurrentThreadsLevel();
691 if ( currentLevel < LevelMutexInfo::GetLevel() )
692 return MutexErrors::LevelTooHigh;
693 const bool lockedByThisThread = IsLockedByCurrentThread();
694 if ( !lockedByThisThread && forTryLock && IsLocked() )
695 return MutexErrors::AlreadyLocked;
696 if ( currentLevel == LevelMutexInfo::GetLevel() )
698 // If this mutex has the same level as the current level,
699 // and was locked by the current thread, then assume it
700 // was locked with the MultiLock function. Which means it
701 // is safe to relock this. If this checked if it equals
702 // s_currentMutex that would defeat re-entrancy for all
703 // multi-locked mutexes.
704 if ( lockedByThisThread )
707 return MutexErrors::Success;
711 return MutexErrors::LevelTooHigh;
715 return MutexErrors::NoProblem;
718 // ----------------------------------------------------------------------------
720 MutexErrors::Type LevelMutexInfo::PreUnlockCheck( void ) volatile
723 LOKI_MUTEX_DEBUG_CODE( Checker checker( this ); (void)checker; )
726 return MutexErrors::WasntLocked;
727 const unsigned int currentLevel = GetCurrentThreadsLevel();
728 if ( currentLevel > m_level )
729 return MutexErrors::LevelTooLow;
730 if ( currentLevel < m_level )
731 return MutexErrors::LevelTooHigh;
732 const bool lockedByThisThread = IsLockedByCurrentThread();
733 if ( !lockedByThisThread )
734 return MutexErrors::NotLockedByThread;
738 return MutexErrors::Success;
741 return MutexErrors::NoProblem;
744 // ----------------------------------------------------------------------------
746 MutexErrors::Type ThrowOnAnyMutexError::CheckError( MutexErrors::Type error,
749 if ( ( error != MutexErrors::Success )
750 && ( error != MutexErrors::NoProblem ) )
752 throw MutexException( "Error occurred using mutex.", level, error );
757 // ----------------------------------------------------------------------------
759 MutexErrors::Type ThrowOnBadDesignMutexError::CheckError( MutexErrors::Type error,
762 if ( ( error == MutexErrors::LevelTooHigh )
763 && ( error == MutexErrors::LevelTooLow ) )
765 throw MutexException( "Error occurred using mutex.", level, error );
770 // ----------------------------------------------------------------------------
772 void MutexSleepWaits::Wait( void )
774 #if defined( _MSC_VER )
775 ::SleepEx( sleepTime, true );
777 ::sleep( sleepTime );
781 // ----------------------------------------------------------------------------
783 SpinLevelMutex::SpinLevelMutex( unsigned int level ) :
787 #if defined( _MSC_VER )
788 ::InitializeCriticalSection( &m_mutex );
790 const int result = ::pthread_mutex_init( &m_mutex, 0 );
796 throw MutexException( "pthread mutex already initialized!",
797 level, MutexErrors::AlreadyInitialized );
800 throw MutexException( "pthread mutex has an invalid attribute!",
801 level, MutexErrors::InvalidAttribute );
803 throw MutexException( "pthread mutex has an invalid address!",
804 level, MutexErrors::InvalidAddress );
809 // ----------------------------------------------------------------------------
811 SpinLevelMutex::~SpinLevelMutex( void )
815 #if defined( _MSC_VER )
816 ::DeleteCriticalSection( &m_mutex );
818 ::pthread_mutex_destroy( &m_mutex );
823 // Not much we can do after catching an exception inside a destructor!
827 // ----------------------------------------------------------------------------
829 MutexErrors::Type SpinLevelMutex::Lock( void ) volatile
831 // Have to cast away volatile since Windows CriticalSection class does not
832 // use volatile qualifier.
833 SpinLevelMutex *pThis = const_cast< SpinLevelMutex * >( this );
834 #if defined( _MSC_VER )
835 ::EnterCriticalSection( &pThis->m_mutex );
837 const int result = ::pthread_mutex_lock( &pThis->m_mutex );
844 throw MutexException( "pthread mutex not initialized properly!",
845 GetLevel(), MutexErrors::NotInitialized );
847 throw MutexException( "pthread mutex is not valid!",
848 GetLevel(), MutexErrors::InvalidAddress );
850 throw MutexException( "locking this pthread mutex may cause a deadlock!",
851 GetLevel(), MutexErrors::MayDeadlock );
854 return MutexErrors::Success;
857 // ----------------------------------------------------------------------------
859 MutexErrors::Type SpinLevelMutex::TryLock( void ) volatile
861 // Have to cast away volatile since Windows CriticalSection class does not
862 // use volatile qualifier.
863 SpinLevelMutex *pThis = const_cast< SpinLevelMutex * >( this );
864 #if defined( _MSC_VER )
865 const bool locked = ( 0 != ::TryEnterCriticalSection( &pThis->m_mutex ) );
866 return ( locked ) ? MutexErrors::Success : MutexErrors::TryFailed;
868 const int result = ::pthread_mutex_trylock( &pThis->m_mutex );
872 return MutexErrors::Success;
877 throw MutexException( "pthread mutex reached recursion limit!",
878 GetLevel(), MutexErrors::TooMuchRecursion );
880 return MutexErrors::TryFailed;
884 // ----------------------------------------------------------------------------
886 MutexErrors::Type SpinLevelMutex::Unlock( void ) volatile
888 // Have to cast away volatile since Windows CriticalSection class does not
889 // use volatile qualifier.
890 SpinLevelMutex *pThis = const_cast< SpinLevelMutex * >( this );
891 #if defined( _MSC_VER )
892 ::LeaveCriticalSection( &pThis->m_mutex );
894 const int result = ::pthread_mutex_unlock( &pThis->m_mutex );
895 if ( EPERM == result )
896 throw MutexException( "current thread did not lock this pthread mutex!",
897 GetLevel(), MutexErrors::NotLockedByThread );
899 return MutexErrors::Success;
902 // ----------------------------------------------------------------------------
904 #if defined( _MSC_VER )
906 SleepLevelMutex::SleepLevelMutex( unsigned int level ) :
907 SpinLevelMutex( level ),
913 // ----------------------------------------------------------------------------
917 SleepLevelMutex::SleepLevelMutex( unsigned int level, unsigned int sleepTime ) :
918 SpinLevelMutex( level ),
919 m_sleepTime( sleepTime / 1000 )
921 if ( 0 == m_sleepTime )
922 m_sleepTime = 1; // Can't have a resolution less than 1 second.
927 // ----------------------------------------------------------------------------
929 SleepLevelMutex::~SleepLevelMutex( void )
933 // ----------------------------------------------------------------------------
935 MutexErrors::Type SleepLevelMutex::Lock( void ) volatile
940 locked = ( MutexErrors::Success == TryLock() );
943 #if defined( _MSC_VER )
944 ::SleepEx( m_sleepTime, m_wakable );
946 ::sleep( m_sleepTime );
949 return MutexErrors::Success;
952 // ----------------------------------------------------------------------------
954 MutexException::MutexException( const char *message,
955 unsigned int level, MutexErrors::Type reason ) :
956 m_message( message ),
962 // ----------------------------------------------------------------------------
964 MutexException::MutexException( const MutexException &that ) throw () :
965 ::std::exception( that ),
966 m_message( that.m_message ),
967 m_level( that.m_level ),
968 m_reason( that.m_reason )
972 // ----------------------------------------------------------------------------
974 MutexException &MutexException::operator = ( const MutexException &that ) throw ()
976 m_message = that.m_message;
977 m_level = that.m_level;
978 m_reason = that.m_reason;
982 // ----------------------------------------------------------------------------
984 MutexException::~MutexException( void ) throw ()
988 // ----------------------------------------------------------------------------
990 const char *MutexException::what( void ) const throw ()
995 // ----------------------------------------------------------------------------
997 MutexLocker::MutexLocker( volatile LevelMutexInfo &mutex, bool lock ) :
1001 assert( nullptr != this );
1004 const MutexErrors::Type result = mutex.Lock();
1005 m_locked = ( MutexErrors::Success == result );
1007 throw MutexException( "Unable to lock mutex.", mutex.GetLevel(), result );
1010 // ----------------------------------------------------------------------------
1012 MutexLocker::MutexLocker( volatile LevelMutexInfo &mutex, unsigned int milliSeconds,
1017 assert( nullptr != this );
1020 const MutexErrors::Type result = mutex.Lock( milliSeconds );
1021 m_locked = ( MutexErrors::Success == result );
1023 throw MutexException( "Unable to lock mutex.", mutex.GetLevel(), result );
1026 // ----------------------------------------------------------------------------
1028 MutexLocker::~MutexLocker( void )
1030 assert( nullptr != this );
1039 // Not much we can do when catching an exception inside a destructor.
1043 // ----------------------------------------------------------------------------
1045 bool MutexLocker::Lock( void )
1047 assert( nullptr != this );
1050 const MutexErrors::Type result = m_mutex.Lock();
1051 if ( MutexErrors::Success != result )
1057 // ----------------------------------------------------------------------------
1059 bool MutexLocker::Unlock( void )
1061 assert( nullptr != this );
1064 const MutexErrors::Type result = m_mutex.Unlock();
1065 if ( MutexErrors::Success != result )
1071 // ----------------------------------------------------------------------------
1073 MultiMutexLocker::MultiMutexLocker( LevelMutexInfo::MutexContainer &mutexes,
1076 m_mutexes( mutexes )
1078 assert( nullptr != this );
1081 const MutexErrors::Type result = LevelMutexInfo::MultiLock( mutexes );
1082 m_locked = ( MutexErrors::Success == result );
1084 throw MutexException( "Unable to lock multiple mutexes.",
1085 GetLevel( mutexes ), result );
1088 // ----------------------------------------------------------------------------
1090 MultiMutexLocker::MultiMutexLocker( LevelMutexInfo::MutexContainer &mutexes,
1091 unsigned int milliSeconds, bool lock ) :
1093 m_mutexes( mutexes )
1095 assert( nullptr != this );
1098 const MutexErrors::Type result = LevelMutexInfo::MultiLock( mutexes, milliSeconds );
1099 m_locked = ( MutexErrors::Success == result );
1101 throw MutexException( "Unable to lock multiple mutexes.",
1102 GetLevel( mutexes ), result );
1105 // ----------------------------------------------------------------------------
1107 MultiMutexLocker::~MultiMutexLocker( void )
1109 assert( nullptr != this );
1114 LevelMutexInfo::MultiUnlock( m_mutexes );
1118 // Not much we can do when catching an exception inside a destructor.
1122 // ----------------------------------------------------------------------------
1124 bool MultiMutexLocker::Lock( void )
1126 assert( nullptr != this );
1129 const MutexErrors::Type result = LevelMutexInfo::MultiLock( m_mutexes );
1130 if ( MutexErrors::Success != result )
1136 // ----------------------------------------------------------------------------
1138 bool MultiMutexLocker::Unlock( void )
1140 assert( nullptr != this );
1143 const MutexErrors::Type result = LevelMutexInfo::MultiUnlock( m_mutexes );
1144 if ( MutexErrors::Success != result )
1150 // ----------------------------------------------------------------------------
1152 } // end namespace Loki