]> git.cworth.org Git - vogl/blob - src/extlib/loki/src/LevelMutex.cpp
Initial vogl checkin
[vogl] / src / extlib / loki / src / LevelMutex.cpp
1 ////////////////////////////////////////////////////////////////////////////////
2 //
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.
6 //
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.
11 //
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.
14 //
15 ////////////////////////////////////////////////////////////////////////////////
16
17 // $Id$
18
19 /// @file LevelMutex.cpp Contains functions needed by LevelMutex class.
20
21 // ----------------------------------------------------------------------------
22
23 #if (!defined(__CYGWIN__) || (defined(__CYGWIN__) && __GNUC__ > 3)) && !defined(__APPLE__)
24
25 #include <loki/LevelMutex.h>
26
27 #include <algorithm>
28 #include <cerrno>
29
30
31 using namespace ::std;
32
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.
35 #define nullptr 0
36
37
38 LOKI_THREAD_LOCAL volatile ::Loki::LevelMutexInfo *::Loki::LevelMutexInfo::s_currentMutex = nullptr;
39
40 unsigned int ::Loki::MutexSleepWaits::sleepTime = 1;
41
42
43 /// Anonymous namespace hides some functions which are implementation details.
44 namespace
45 {
46
47 // ----------------------------------------------------------------------------
48
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.
58  */
59 bool IsUniqueMutex( const ::Loki::LevelMutexInfo::MutexContainer &mutexes,
60                     ::Loki::LevelMutexInfo::LevelMutexContainerCIter cit )
61 {
62         assert( mutexes.end() != cit );
63
64         const ::Loki::LevelMutexInfo::LevelMutexContainerCIter end = mutexes.end();
65         const volatile ::Loki::LevelMutexInfo *mutex = *cit;
66         for ( ++cit; cit != end; ++cit )
67         {
68                 const volatile ::Loki::LevelMutexInfo *check = *cit;
69                 if ( check == mutex )
70                         return false;
71         }
72         return true;
73 }
74
75 // ----------------------------------------------------------------------------
76
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.
83  */
84 const volatile ::Loki::LevelMutexInfo *GetFirstMutex(
85     const ::Loki::LevelMutexInfo::MutexContainer &mutexes )
86 {
87         if ( mutexes.size() == 0 )
88                 return nullptr;
89         ::Loki::LevelMutexInfo::LevelMutexContainerCIter it( mutexes.begin() );
90         const volatile ::Loki::LevelMutexInfo *mutex = *it;
91         if ( nullptr != mutex )
92                 return mutex;
93
94         const ::Loki::LevelMutexInfo::LevelMutexContainerCIter end( mutexes.end() );
95         while ( it != end )
96         {
97                 mutex = *it;
98                 if ( nullptr != mutex )
99                         return mutex;
100                 ++it;
101         }
102
103         return nullptr;
104 }
105
106 // ----------------------------------------------------------------------------
107
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
110  container.
111  @return Level number of first mutex in container, or UnlockedLevel if no
112   mutexes were found in the container.
113  */
114 unsigned int GetLevel( const ::Loki::LevelMutexInfo::MutexContainer &mutexes )
115 {
116         const volatile ::Loki::LevelMutexInfo *mutex = GetFirstMutex( mutexes );
117         return ( nullptr == mutex ) ? ::Loki::LevelMutexInfo::UnlockedLevel : mutex->GetLevel();
118 }
119
120 // ----------------------------------------------------------------------------
121
122 } // end anonymous namespace
123
124 namespace Loki
125 {
126
127 // ----------------------------------------------------------------------------
128
129 unsigned int GetCurrentThreadsLevel( void )
130 {
131         const volatile LevelMutexInfo *mutex = LevelMutexInfo::GetCurrentMutex();
132         return ( nullptr == mutex ) ? LevelMutexInfo::UnlockedLevel : mutex->GetLevel();
133 }
134
135 // ----------------------------------------------------------------------------
136
137 unsigned int CountMutexesInCurrentThread( void )
138 {
139         const volatile LevelMutexInfo *mutex = LevelMutexInfo::GetCurrentMutex();
140         unsigned int count = 0;
141         while ( nullptr != mutex )
142         {
143                 count++;
144                 mutex = mutex->GetPrevious();
145         }
146         return count;
147 }
148
149 // ----------------------------------------------------------------------------
150
151 unsigned int CountLocksInCurrentThread( void )
152 {
153         const volatile LevelMutexInfo *mutex = LevelMutexInfo::GetCurrentMutex();
154         unsigned int count = 0;
155         while ( nullptr != mutex )
156         {
157                 count += mutex->GetLockCount();
158                 mutex = mutex->GetPrevious();
159         }
160         return count;
161 }
162
163 // ----------------------------------------------------------------------------
164
165 unsigned int CountMutexesAtCurrentLevel( void )
166 {
167         const volatile LevelMutexInfo *mutex = LevelMutexInfo::GetCurrentMutex();
168         if ( nullptr == mutex )
169                 return 0;
170         unsigned int count = 0;
171         unsigned int level = mutex->GetLevel();
172         while ( nullptr != mutex )
173         {
174                 if ( level != mutex->GetLevel() )
175                         break;
176                 mutex = mutex->GetPrevious();
177                 count++;
178         }
179         return count;
180 }
181
182 // ----------------------------------------------------------------------------
183
184 MutexErrors::Type DoMutexesMatchContainer( const LevelMutexInfo::MutexContainer &mutexes )
185 {
186         const unsigned int count = mutexes.size();
187         if ( 0 == count )
188                 return MutexErrors::EmptyContainer;
189         unsigned int currentLevel = GetCurrentThreadsLevel();
190         const LevelMutexInfo::LevelMutexContainerCIter endSpot = mutexes.end();
191
192         for ( LevelMutexInfo::LevelMutexContainerCIter cit = mutexes.begin();
193                 cit != endSpot;
194                 ++cit )
195         {
196                 const volatile LevelMutexInfo *mutex = *cit;
197                 if ( nullptr == mutex )
198                         return MutexErrors::NullMutexPointer;
199                 if ( currentLevel != mutex->GetLevel() )
200                 {
201                         return ( LevelMutexInfo::UnlockedLevel == currentLevel ) ?
202                                MutexErrors::NotRecentLock : MutexErrors::WrongLevel;
203                 }
204                 if ( !mutex->IsRecentLock( count ) )
205                         return MutexErrors::NotRecentLock;
206                 if ( !IsUniqueMutex( mutexes, cit ) )
207                         return MutexErrors::DuplicateMutex;
208         }
209
210         if ( count != CountMutexesAtCurrentLevel() )
211                 return MutexErrors::LevelTooHigh;
212
213         return MutexErrors::Success;
214 }
215
216 // ----------------------------------------------------------------------------
217
218 LevelMutexInfo::MutexUndoer::MutexUndoer( MutexContainer &mutexes ) :
219         m_mutexes( mutexes ),
220         m_here( mutexes.end() )
221 {
222         assert( this != nullptr );
223 }
224
225 // ----------------------------------------------------------------------------
226
227 LevelMutexInfo::MutexUndoer::~MutexUndoer( void )
228 {
229         assert( this != nullptr );
230         try
231         {
232                 if ( m_here == m_mutexes.end() )
233                         return;
234                 LevelMutexContainerRIter rend( m_mutexes.rend() );
235                 LevelMutexContainerRIter rit( m_here );
236                 --rit;
237                 for ( ; rit != rend; ++rit )
238                 {
239                         volatile ::Loki::LevelMutexInfo *mutex = *rit;
240                         assert( nullptr != mutex );
241                         mutex->UnlockThis();
242                 }
243         }
244         catch ( ... )
245         {
246         }
247 }
248
249 // ----------------------------------------------------------------------------
250
251 void LevelMutexInfo::MutexUndoer::SetPlace( LevelMutexContainerIter &here )
252 {
253         assert( this != nullptr );
254         m_here = here;
255 }
256
257 // ----------------------------------------------------------------------------
258
259 void LevelMutexInfo::MutexUndoer::Cancel( void )
260 {
261         assert( this != nullptr );
262         m_here = m_mutexes.end();
263 }
264
265 // ----------------------------------------------------------------------------
266
267 const volatile LevelMutexInfo *LevelMutexInfo::GetCurrentMutex( void )
268 {
269         assert( IsValidList() );
270         return s_currentMutex;
271 }
272
273 // ----------------------------------------------------------------------------
274
275 bool LevelMutexInfo::IsValidList( void )
276 {
277         const volatile LevelMutexInfo *mutex1 = s_currentMutex;
278         const volatile LevelMutexInfo *mutex2 = s_currentMutex;
279         if ( nullptr == mutex1 )
280                 return true;
281
282         while ( nullptr != mutex2 )
283         {
284                 if ( nullptr == mutex2 )
285                         break;
286                 mutex2 = mutex2->m_previous;
287                 if ( mutex1 == mutex2 )
288                         return false;
289                 if ( nullptr == mutex2 )
290                         break;
291                 mutex2 = mutex2->m_previous;
292                 if ( mutex1 == mutex2 )
293                         return false;
294                 if ( nullptr == mutex2 )
295                         break;
296                 mutex1 = mutex1->m_previous;
297                 if ( nullptr == mutex1 )
298                         break;
299         }
300
301         mutex1 = s_currentMutex;
302         unsigned int level = mutex1->m_level;
303         while ( nullptr != mutex1 )
304         {
305                 if ( level > mutex1->m_level )
306                         return false;
307                 level = mutex1->m_level;
308                 mutex1 = mutex1->m_previous;
309         }
310
311         return true;
312 }
313
314 // ----------------------------------------------------------------------------
315
316 MutexErrors::Type LevelMutexInfo::MultiLock( MutexContainer &mutexes )
317 {
318         assert( IsValidList() );
319
320         const unsigned int count = mutexes.size();
321         if ( count == 0 )
322                 return MutexErrors::EmptyContainer;
323
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 )
336         {
337                 return first->DoErrorCheck( MutexErrors::LevelTooHigh );
338         }
339
340         const LevelMutexContainerIter end( mutexes.end() );
341         if ( currentLevel == checkLevel )
342         {
343                 MutexErrors::Type result = DoMutexesMatchContainer( mutexes );
344                 if ( MutexErrors::Success != result )
345                 {
346                         if ( LevelMutexInfo::UnlockedLevel == currentLevel )
347                         {
348                                 return first->DoErrorCheck( result );
349                         }
350                         return first->DoErrorCheck( MutexErrors::LevelTooHigh );
351                 }
352                 for ( it = mutexes.begin(); it != end; ++it )
353                 {
354                         mutex = *it;
355                         mutex->IncrementCount();
356                 }
357                 return MutexErrors::Success;
358         }
359         assert( !mutex->IsRecentLock( count ) );
360
361         if ( 1 < count )
362         {
363                 for ( ++it; it != end; ++it )
364                 {
365                         mutex = *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 ) );
374                 }
375
376                 it = mutexes.begin();
377                 ::std::sort( it, end );
378         }
379
380         MutexUndoer undoer( mutexes );
381         for ( ; it != end; ++it )
382         {
383                 mutex = *it;
384                 const MutexErrors::Type result = mutex->LockThis();
385                 if ( MutexErrors::Success != result )
386                         return first->DoErrorCheck( result );
387                 undoer.SetPlace( it );
388         }
389         undoer.Cancel();
390
391         return MutexErrors::Success;
392 }
393
394 // ----------------------------------------------------------------------------
395
396 MutexErrors::Type LevelMutexInfo::MultiLock( MutexContainer &mutexes,
397         unsigned int milliSeconds )
398 {
399         assert( IsValidList() );
400
401         if ( 0 == milliSeconds )
402                 return MultiLock( mutexes );
403         const unsigned int count = mutexes.size();
404         if ( 0 == count )
405                 return MutexErrors::EmptyContainer;
406
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 )
419         {
420                 return first->DoErrorCheck( MutexErrors::LevelTooHigh );
421         }
422
423         const LevelMutexContainerIter end( mutexes.end() );
424         if ( currentLevel == checkLevel )
425         {
426                 MutexErrors::Type result = DoMutexesMatchContainer( mutexes );
427                 if ( MutexErrors::Success != result )
428                 {
429                         if ( LevelMutexInfo::UnlockedLevel == currentLevel )
430                         {
431                                 return first->DoErrorCheck( result );
432                         }
433                         return first->DoErrorCheck( MutexErrors::LevelTooHigh );
434                 }
435                 for ( it = mutexes.begin(); it != end; ++it )
436                 {
437                         mutex = *it;
438                         mutex->IncrementCount();
439                 }
440                 return MutexErrors::Success;
441         }
442         assert( !mutex->IsRecentLock( count ) );
443
444         if ( 1 < count )
445         {
446                 for ( ++it; it != end; ++it )
447                 {
448                         mutex = *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 ) );
457                 }
458
459                 it = mutexes.begin();
460                 ::std::sort( it, end );
461         }
462
463         MutexUndoer undoer( mutexes );
464         for ( ; it != end; ++it )
465         {
466                 mutex = *it;
467                 const MutexErrors::Type result = mutex->LockThis( milliSeconds );
468                 if ( MutexErrors::Success != result )
469                         return first->DoErrorCheck( result );
470                 undoer.SetPlace( it );
471         }
472         undoer.Cancel();
473
474         return MutexErrors::Success;
475 }
476
477 // ----------------------------------------------------------------------------
478
479 MutexErrors::Type LevelMutexInfo::MultiUnlock( MutexContainer &mutexes )
480 {
481         assert( IsValidList() );
482
483         MutexErrors::Type result = DoMutexesMatchContainer( mutexes );
484         if ( result != MutexErrors::Success )
485         {
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 );
491         }
492
493         const unsigned int count = mutexes.size();
494         if ( 1 < count )
495         {
496                 ::std::sort( mutexes.begin(), mutexes.end() );
497         }
498
499         bool failed = false;
500         LevelMutexContainerRIter rit( mutexes.rbegin() );
501         const LevelMutexContainerRIter rend( mutexes.rend() );
502         for ( ; rit != rend; ++rit )
503         {
504                 try
505                 {
506                         volatile LevelMutexInfo *mutex = *rit;
507                         result = mutex->UnlockThis();
508                         if ( MutexErrors::Success != result )
509                                 failed = true;
510                 }
511                 catch ( ... )
512                 {
513                         failed = true;
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.
518                 }
519         }
520
521         return ( failed ) ? MutexErrors::MultiUnlockFailed : MutexErrors::Success;
522 }
523
524 // ----------------------------------------------------------------------------
525
526 LevelMutexInfo::LevelMutexInfo( unsigned int level ) :
527         m_level( level ),
528         m_count( 0 ),
529         m_previous( nullptr )
530 {
531         assert( IsValid() );
532 }
533
534 // ----------------------------------------------------------------------------
535
536 LevelMutexInfo::~LevelMutexInfo( void )
537 {
538         assert( IsValid() );
539         assert( 0 == m_count );
540         assert( nullptr == m_previous );
541 }
542
543 // ----------------------------------------------------------------------------
544
545 bool LevelMutexInfo::IsValid( void ) const volatile
546 {
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() );
552         return true;
553 }
554
555 // ----------------------------------------------------------------------------
556
557 void LevelMutexInfo::IncrementCount( void ) volatile
558 {
559         assert( IsValid() );
560         assert( 0 < m_count );
561         ++m_count;
562 }
563
564 // ----------------------------------------------------------------------------
565
566 void LevelMutexInfo::DecrementCount( void ) volatile
567 {
568         assert( IsValid() );
569         assert( 0 < m_count );
570         --m_count;
571 }
572
573 // ----------------------------------------------------------------------------
574
575 bool LevelMutexInfo::IsLockedByCurrentThread( void ) const volatile
576 {
577         assert( IsValid() );
578         LOKI_MUTEX_DEBUG_CODE( Checker checker( this ); (void)checker; )
579
580         if ( !IsLocked() )
581                 return false;
582         const volatile LevelMutexInfo *mutex = s_currentMutex;
583         while ( nullptr != mutex )
584         {
585                 if ( this == mutex )
586                         return true;
587                 mutex = mutex->m_previous;
588         }
589         return false;
590 }
591
592 // ----------------------------------------------------------------------------
593
594 bool LevelMutexInfo::IsRecentLock( void ) const volatile
595 {
596         assert( IsValid() );
597         LOKI_MUTEX_DEBUG_CODE( Checker checker( this ); (void)checker; )
598
599         if ( 0 == m_count )
600                 return false;
601         const volatile LevelMutexInfo *mutex = s_currentMutex;
602         while ( nullptr != mutex )
603         {
604                 assert( m_level <= mutex->m_level );
605                 if ( this == mutex )
606                         return true;
607                 if ( m_level != mutex->m_level )
608                         return false;
609                 mutex = mutex->m_previous;
610         }
611         return false;
612 }
613
614 // ----------------------------------------------------------------------------
615
616 bool LevelMutexInfo::IsRecentLock( unsigned int count ) const volatile
617 {
618         assert( IsValid() );
619         LOKI_MUTEX_DEBUG_CODE( Checker checker( this ); (void)checker; )
620
621         if ( 0 == count )
622                 return false;
623         const volatile LevelMutexInfo *mutex = s_currentMutex;
624         for ( ; count > 0; count-- )
625         {
626                 if ( nullptr == mutex )
627                         return false;
628                 if ( this == mutex )
629                         return true;
630                 mutex = mutex->m_previous;
631         }
632         return false;
633 }
634
635 // ----------------------------------------------------------------------------
636
637 bool LevelMutexInfo::IsLockedByAnotherThread( void ) const volatile
638 {
639         assert( IsValid() );
640         LOKI_MUTEX_DEBUG_CODE( Checker checker( this ); (void)checker; )
641
642         if ( !IsLocked() )
643                 return false;
644         if ( IsLockedByCurrentThread() )
645                 return false;
646         if ( !IsLocked() )
647                 return false;
648         return true;
649 }
650
651 // ----------------------------------------------------------------------------
652
653 void LevelMutexInfo::PostLock( void ) volatile
654 {
655         assert( IsValid() );
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; )
661
662         m_count = 1;
663         m_previous = s_currentMutex;
664         s_currentMutex = this;
665 }
666
667 // ----------------------------------------------------------------------------
668
669 void LevelMutexInfo::PreUnlock( void ) volatile
670 {
671         assert( IsValid() );
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; )
677
678         s_currentMutex = m_previous;
679         m_previous = nullptr;
680         m_count = 0;
681 }
682
683 // ----------------------------------------------------------------------------
684
685 MutexErrors::Type LevelMutexInfo::PreLockCheck( bool forTryLock ) volatile
686 {
687         assert( IsValid() );
688         LOKI_MUTEX_DEBUG_CODE( Checker checker( this ); (void)checker; )
689
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() )
697         {
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 )
705                 {
706                         m_count++;
707                         return MutexErrors::Success;
708                 }
709                 else
710                 {
711                         return MutexErrors::LevelTooHigh;
712                 }
713         }
714
715         return MutexErrors::NoProblem;
716 }
717
718 // ----------------------------------------------------------------------------
719
720 MutexErrors::Type LevelMutexInfo::PreUnlockCheck( void ) volatile
721 {
722         assert( IsValid() );
723         LOKI_MUTEX_DEBUG_CODE( Checker checker( this ); (void)checker; )
724
725         if ( 0 == m_count )
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;
735         if ( 1 < m_count )
736         {
737                 m_count--;
738                 return MutexErrors::Success;
739         }
740
741         return MutexErrors::NoProblem;
742 }
743
744 // ----------------------------------------------------------------------------
745
746 MutexErrors::Type ThrowOnAnyMutexError::CheckError( MutexErrors::Type error,
747         unsigned int level )
748 {
749         if ( ( error != MutexErrors::Success )
750                 && ( error != MutexErrors::NoProblem ) )
751         {
752                 throw MutexException( "Error occurred using mutex.", level, error );
753         }
754         return error;
755 }
756
757 // ----------------------------------------------------------------------------
758
759 MutexErrors::Type ThrowOnBadDesignMutexError::CheckError( MutexErrors::Type error,
760         unsigned int level )
761 {
762         if ( ( error == MutexErrors::LevelTooHigh )
763                 && ( error == MutexErrors::LevelTooLow ) )
764         {
765                 throw MutexException( "Error occurred using mutex.", level, error );
766         }
767         return error;
768 }
769
770 // ----------------------------------------------------------------------------
771
772 void MutexSleepWaits::Wait( void )
773 {
774 #if defined( _MSC_VER )
775         ::SleepEx( sleepTime, true );
776 #else
777         ::sleep( sleepTime );
778 #endif
779 }
780
781 // ----------------------------------------------------------------------------
782
783 SpinLevelMutex::SpinLevelMutex( unsigned int level ) :
784         m_mutex(),
785         m_level( level )
786 {
787 #if defined( _MSC_VER )
788         ::InitializeCriticalSection( &m_mutex );
789 #else
790         const int result = ::pthread_mutex_init( &m_mutex, 0 );
791         switch ( result )
792         {
793         case 0:
794                 return;
795         case EBUSY:
796                 throw MutexException( "pthread mutex already initialized!",
797                                       level, MutexErrors::AlreadyInitialized );
798         default:
799         case EINVAL:
800                 throw MutexException( "pthread mutex has an invalid attribute!",
801                                       level, MutexErrors::InvalidAttribute );
802         case EFAULT:
803                 throw MutexException( "pthread mutex has an invalid address!",
804                                       level, MutexErrors::InvalidAddress );
805         }
806 #endif
807 }
808
809 // ----------------------------------------------------------------------------
810
811 SpinLevelMutex::~SpinLevelMutex( void )
812 {
813         try
814         {
815 #if defined( _MSC_VER )
816                 ::DeleteCriticalSection( &m_mutex );
817 #else
818                 ::pthread_mutex_destroy( &m_mutex );
819 #endif
820         }
821         catch ( ... )
822         {
823                 // Not much we can do after catching an exception inside a destructor!
824         }
825 }
826
827 // ----------------------------------------------------------------------------
828
829 MutexErrors::Type SpinLevelMutex::Lock( void ) volatile
830 {
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 );
836 #else
837         const int result = ::pthread_mutex_lock( &pThis->m_mutex );
838         switch ( result )
839         {
840         case 0:
841                 break;
842         default:
843         case EINVAL:
844                 throw MutexException( "pthread mutex not initialized properly!",
845                 GetLevel(), MutexErrors::NotInitialized );
846         case EFAULT :
847                 throw MutexException( "pthread mutex is not valid!",
848                 GetLevel(), MutexErrors::InvalidAddress );
849         case EDEADLK:
850                 throw MutexException( "locking this pthread mutex may cause a deadlock!",
851                 GetLevel(), MutexErrors::MayDeadlock );
852         }
853 #endif
854         return MutexErrors::Success;
855 }
856
857 // ----------------------------------------------------------------------------
858
859 MutexErrors::Type SpinLevelMutex::TryLock( void ) volatile
860 {
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;
867 #else
868         const int result = ::pthread_mutex_trylock( &pThis->m_mutex );
869         switch ( result )
870         {
871         case 0:
872                 return MutexErrors::Success;
873         default:
874         case EBUSY:
875                 break;
876         case EAGAIN:
877                 throw MutexException( "pthread mutex reached recursion limit!",
878                 GetLevel(), MutexErrors::TooMuchRecursion );
879         }
880         return MutexErrors::TryFailed;
881 #endif
882 }
883
884 // ----------------------------------------------------------------------------
885
886 MutexErrors::Type SpinLevelMutex::Unlock( void ) volatile
887 {
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 );
893 #else
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 );
898 #endif
899         return MutexErrors::Success;
900 }
901
902 // ----------------------------------------------------------------------------
903
904 #if defined( _MSC_VER )
905
906 SleepLevelMutex::SleepLevelMutex( unsigned int level ) :
907         SpinLevelMutex( level ),
908         m_sleepTime( 1 ),
909         m_wakable( true )
910 {
911 }
912
913 // ----------------------------------------------------------------------------
914
915 #else
916
917 SleepLevelMutex::SleepLevelMutex( unsigned int level, unsigned int sleepTime ) :
918         SpinLevelMutex( level ),
919         m_sleepTime( sleepTime / 1000 )
920 {
921         if ( 0 == m_sleepTime )
922                 m_sleepTime = 1; // Can't have a resolution less than 1 second.
923 }
924
925 #endif
926
927 // ----------------------------------------------------------------------------
928
929 SleepLevelMutex::~SleepLevelMutex( void )
930 {
931 }
932
933 // ----------------------------------------------------------------------------
934
935 MutexErrors::Type SleepLevelMutex::Lock( void ) volatile
936 {
937         bool locked = false;
938         while ( !locked )
939         {
940                 locked = ( MutexErrors::Success == TryLock() );
941                 if ( locked )
942                         break;
943 #if defined( _MSC_VER )
944                 ::SleepEx( m_sleepTime, m_wakable );
945 #else
946                 ::sleep( m_sleepTime );
947 #endif
948         }
949         return MutexErrors::Success;
950 }
951
952 // ----------------------------------------------------------------------------
953
954 MutexException::MutexException( const char *message,
955                                 unsigned int level, MutexErrors::Type reason ) :
956         m_message( message ),
957         m_level( level ),
958         m_reason( reason )
959 {
960 }
961
962 // ----------------------------------------------------------------------------
963
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 )
969 {
970 }
971
972 // ----------------------------------------------------------------------------
973
974 MutexException &MutexException::operator = ( const MutexException &that ) throw ()
975 {
976         m_message = that.m_message;
977         m_level = that.m_level;
978         m_reason = that.m_reason;
979         return *this;
980 }
981
982 // ----------------------------------------------------------------------------
983
984 MutexException::~MutexException( void ) throw ()
985 {
986 }
987
988 // ----------------------------------------------------------------------------
989
990 const char *MutexException::what( void ) const throw ()
991 {
992         return m_message;
993 }
994
995 // ----------------------------------------------------------------------------
996
997 MutexLocker::MutexLocker( volatile LevelMutexInfo &mutex, bool lock ) :
998         m_locked( false ),
999         m_mutex( mutex )
1000 {
1001         assert( nullptr != this );
1002         if ( !lock )
1003                 return;
1004         const MutexErrors::Type result = mutex.Lock();
1005         m_locked = ( MutexErrors::Success == result );
1006         if ( !m_locked )
1007                 throw MutexException( "Unable to lock mutex.", mutex.GetLevel(), result );
1008 }
1009
1010 // ----------------------------------------------------------------------------
1011
1012 MutexLocker::MutexLocker( volatile LevelMutexInfo &mutex, unsigned int milliSeconds,
1013                           bool lock ) :
1014         m_locked( false ),
1015         m_mutex( mutex )
1016 {
1017         assert( nullptr != this );
1018         if ( !lock )
1019                 return;
1020         const MutexErrors::Type result = mutex.Lock( milliSeconds );
1021         m_locked = ( MutexErrors::Success == result );
1022         if ( !m_locked )
1023                 throw MutexException( "Unable to lock mutex.", mutex.GetLevel(), result );
1024 }
1025
1026 // ----------------------------------------------------------------------------
1027
1028 MutexLocker::~MutexLocker( void )
1029 {
1030         assert( nullptr != this );
1031         if ( !m_locked )
1032                 return;
1033         try
1034         {
1035                 m_mutex.Unlock();
1036         }
1037         catch ( ... )
1038         {
1039                 // Not much we can do when catching an exception inside a destructor.
1040         }
1041 }
1042
1043 // ----------------------------------------------------------------------------
1044
1045 bool MutexLocker::Lock( void )
1046 {
1047         assert( nullptr != this );
1048         if ( m_locked )
1049                 return true;
1050         const MutexErrors::Type result = m_mutex.Lock();
1051         if ( MutexErrors::Success != result )
1052                 return false;
1053         m_locked = true;
1054         return true;
1055 }
1056
1057 // ----------------------------------------------------------------------------
1058
1059 bool MutexLocker::Unlock( void )
1060 {
1061         assert( nullptr != this );
1062         if ( !m_locked )
1063                 return true;
1064         const MutexErrors::Type result = m_mutex.Unlock();
1065         if ( MutexErrors::Success != result )
1066                 return false;
1067         m_locked = false;
1068         return true;
1069 }
1070
1071 // ----------------------------------------------------------------------------
1072
1073 MultiMutexLocker::MultiMutexLocker( LevelMutexInfo::MutexContainer &mutexes,
1074                                     bool lock ) :
1075         m_locked( false ),
1076         m_mutexes( mutexes )
1077 {
1078         assert( nullptr != this );
1079         if ( !lock )
1080                 return;
1081         const MutexErrors::Type result = LevelMutexInfo::MultiLock( mutexes );
1082         m_locked = ( MutexErrors::Success == result );
1083         if ( !m_locked )
1084                 throw MutexException( "Unable to lock multiple mutexes.",
1085                                       GetLevel( mutexes ), result );
1086 }
1087
1088 // ----------------------------------------------------------------------------
1089
1090 MultiMutexLocker::MultiMutexLocker( LevelMutexInfo::MutexContainer &mutexes,
1091                                     unsigned int milliSeconds, bool lock ) :
1092         m_locked( false ),
1093         m_mutexes( mutexes )
1094 {
1095         assert( nullptr != this );
1096         if ( !lock )
1097                 return;
1098         const MutexErrors::Type result = LevelMutexInfo::MultiLock( mutexes, milliSeconds );
1099         m_locked = ( MutexErrors::Success == result );
1100         if ( !m_locked )
1101                 throw MutexException( "Unable to lock multiple mutexes.",
1102                                       GetLevel( mutexes ), result );
1103 }
1104
1105 // ----------------------------------------------------------------------------
1106
1107 MultiMutexLocker::~MultiMutexLocker( void )
1108 {
1109         assert( nullptr != this );
1110         if ( !m_locked )
1111                 return;
1112         try
1113         {
1114                 LevelMutexInfo::MultiUnlock( m_mutexes );
1115         }
1116         catch ( ... )
1117         {
1118                 // Not much we can do when catching an exception inside a destructor.
1119         }
1120 }
1121
1122 // ----------------------------------------------------------------------------
1123
1124 bool MultiMutexLocker::Lock( void )
1125 {
1126         assert( nullptr != this );
1127         if ( m_locked )
1128                 return true;
1129         const MutexErrors::Type result = LevelMutexInfo::MultiLock( m_mutexes );
1130         if ( MutexErrors::Success != result )
1131                 return false;
1132         m_locked = true;
1133         return true;
1134 }
1135
1136 // ----------------------------------------------------------------------------
1137
1138 bool MultiMutexLocker::Unlock( void )
1139 {
1140         assert( nullptr != this );
1141         if ( !m_locked )
1142                 return true;
1143         const MutexErrors::Type result = LevelMutexInfo::MultiUnlock( m_mutexes );
1144         if ( MutexErrors::Success != result )
1145                 return false;
1146         m_locked = false;
1147         return true;
1148 }
1149
1150 // ----------------------------------------------------------------------------
1151
1152 } // end namespace Loki
1153
1154
1155 #endif
1156