]> git.cworth.org Git - vogl/blob - src/extlib/loki/include/loki/LevelMutex.h
Initial vogl checkin
[vogl] / src / extlib / loki / include / loki / LevelMutex.h
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.h Defines classes and functions for LevelMutex facility.
20
21 #ifndef LOKI_LEVEL_MUTEX_H_INCLUDED
22 #define LOKI_LEVEL_MUTEX_H_INCLUDED
23
24
25 // ----------------------------------------------------------------------------
26
27 #include <vector>
28 #include <assert.h>
29 #include <time.h>
30
31 #if defined( _MSC_VER )
32 #include <Windows.h>
33 #else
34 #include <pthread.h>
35 #endif
36
37 #if !defined(_WIN32) && !defined(_WIN64)
38 #include <unistd.h> // declares sleep under Linux
39 #endif
40
41 /** @par thread_local Keyword
42  The mutexes require compilers to provide thread local storage - meaning each
43  thread gets its own copy of the data.  The next version of C++ will have a
44  new keyword, thread_local for that purpose.  Some existing compilers already
45  provide thread local storage using different syntax, so these lines use
46  thread_local to mimic that syntax.  If your compiler provides thread local
47  storage but using different syntax besides "thread_local", you may want to
48  modify these lines.  If your compiler does not support thread local storage,
49  you can't use LevelMutex.
50  */
51 #ifndef LOKI_THREAD_LOCAL
52 #if defined( _MSC_VER )
53 #if ( _MSC_VER >= 1300 )
54 #define LOKI_THREAD_LOCAL __declspec( thread )
55 #else
56 #error "Only Visual Studio versions 7.0 and after supported."
57 #endif
58
59 #elif ( __GNUC__ )
60 #define LOKI_THREAD_LOCAL __thread
61
62 #else
63 #warning "Check if your compiler provides thread local storage."
64 #define LOKI_THREAD_LOCAL thread_local
65 #endif
66 #endif
67
68 #if defined( DEBUG ) || defined( _DEBUG )
69 #define LOKI_MUTEX_DEBUG_CODE( x ) x
70 #else
71 #define LOKI_MUTEX_DEBUG_CODE( x )
72 #endif
73
74
75 namespace Loki
76 {
77
78
79 // ----------------------------------------------------------------------------
80
81 class MutexErrors
82 {
83 public:
84
85         /// @enum Type Possible error conditions detected by LevelMutex functions.
86         enum Type
87         {
88                 Success = 0,        ///< Operation occurred correctly.
89                 NoProblem,          ///< Pre-lock and pre-unlock checks passed.
90                 WrongLevel,         ///< All mutexes in container must have same level.
91                 LevelTooLow,        ///< Trying to unlock a mutex lower than current level.
92                 LevelTooHigh,       ///< Trying to lock a mutex higher than current level.
93                 TryFailed,          ///< TryLock call failed to lock mutex.
94                 NullMutexPointer,   ///< Container has a NULL pointer in it.
95                 DuplicateMutex,     ///< Container must have unique pointers - no duplicates.
96                 EmptyContainer,     ///< Container must have at least 1 pointer in it.
97                 AlreadyLocked,      ///< TryLock call failed because mutex already locked.
98                 WasntLocked,        ///< Unlock failed because mutex was not even locked.
99                 NotRecentLock,      ///< Mutex in container was not recently locked by this thread.
100                 NotLockedByThread,  ///< Can't unlock a mutex not locked by this thread.
101                 MultiUnlockFailed,  ///< MultiUnlock can't unlock at least 1 mutex in container.
102                 TimedOut,           ///< Wait time elapsed without locking mutex.
103                 TooMuchRecursion,   ///< Tried to relock a PThread mutex which is not re-entrant.
104                 NotInitialized,     ///< Tried to lock a PThread mutex which did not get setup.
105                 AlreadyInitialized, ///< PThread mutex initialized before ctor called.
106                 InvalidAttribute,   ///< PThread mutex improperly initialized.
107                 InvalidAddress,     ///< Bad pointer used to initialize a PThread mutex.
108                 ExceptionThrown,    ///< Exception caught in mutex operation.
109                 MayDeadlock,        ///< Locking this mutex may cause a deadlock.
110                 OtherError          ///< Unknown error occurred.
111         };
112 };
113
114 // ----------------------------------------------------------------------------
115
116 /** @class LevelMutexInfo
117  This monolithic base class stores common info for a template class used to
118  control mutexes.  The template class, LevelMutex, is policy-based class.
119
120  @par Implementation
121  Each thread has a list of mutexes it locked.  When a mutex first gets locked, it
122  gets added to the head of the list.  If locked again, LevelMutex merely increments
123  a count.  When unlocked, the count gets decremented until it reaches zero, and
124  then it gets removed from the list.  Each mutex has a pointer to the mutex most
125  recently locked by the current thread.  The current level of a thread is always
126  the level of the most recently locked mutex, or UnlockedLevel if the thread does
127  not have any mutexes locked now.  A mutex is considered "recently" locked if it is at
128  the head of the list, or the same level as the current mutex and also locked by the
129  current thread.
130
131  @par Class Invariants
132  This class maintains invariants for each LevelMutexInfo so that no function
133  calls corrupt a mutex.  Each function makes a call to IsValid at the start so
134  that LevelMutex knows it acts on valid internal data.  Many functions call
135  IsValid again when they return to insure the function did not leave any data in
136  an invalid state.  The exit call to IsValid occurs through a tiny helper class
137  called Checker to insure all data remain valid even when exceptions occur.
138  Another helper class, MutexUndoer, unlocks mutexes in a container if an
139  exception occurs during calls to MultiLock.
140
141  @par Error Results
142  Many functions return an enum value to indicate an error status.  Many enum values
143  indicate errors detected within LevelMutex, but some indicate errors found in policy
144  classes, SpinLevelMutex and SleepLevelMutex.
145  */
146
147 class LevelMutexInfo
148 {
149 public:
150
151         /** Level for thread that has not locked any mutex. Maximum possible level
152          for a mutex is UnlockedLevel-1;  No mutex may have a level of UnlockedLevel.
153          */
154         static const unsigned int UnlockedLevel = 0xFFFFFFFF;
155
156         /// Container for locking multiple mutexes at once.
157         typedef ::std::vector< volatile LevelMutexInfo * > MutexContainer;
158         typedef MutexContainer::iterator LevelMutexContainerIter;
159         typedef MutexContainer::const_iterator LevelMutexContainerCIter;
160         typedef MutexContainer::reverse_iterator LevelMutexContainerRIter;
161         typedef MutexContainer::const_reverse_iterator LevelMutexContainerCRIter;
162
163         /** Locks several mutexes at once.  Requires O(m + n*n) actions where m is the
164          number of mutexes currently locked by the thread and n is the number of mutexes
165          in the container. This provides strong exception safety. If an exception occurs,
166          any mutexes that were locked during this call will get unlocked.
167          @param mutexes Container of pointers to mutexes.  Container must have at
168           least 1 mutex, all mutexes must have the same level, no NULL pointers, and all
169           mutexes must not exceed the thread's current level.  This sorts the container
170           by address order.
171          @return Enum value indicating success or error.
172          */
173         static MutexErrors::Type MultiLock( MutexContainer &mutexes );
174
175         /** Locks several mutexes at once.  Requires O(m + n*n + n*t) actions where m is
176          the number of mutexes currently locked by the thread, n is the number of mutexes
177          in the container, and t is the wait time for each mutex. This provides strong
178          exception safety.  If an exception occurs, any mutexes that were locked during
179          this call will ge unlocked.
180          @param mutexes Container of pointers to mutexes.  Container must have at
181           least 1 mutex, all mutexes must have the same level, no NULL pointers, and all
182           mutexes must not exceed the thread's current level.  This sorts the container
183           by address order.
184          @param milliSeconds Amount of time to wait for each mutex.
185          @return Enum value indicating success or error.
186          */
187         static MutexErrors::Type MultiLock( MutexContainer &mutexes,
188                                             unsigned int milliSeconds );
189
190         /** Unlocks several mutexes at once.  Requires O(m) actions where m is the number of
191          mutexes in the container. This provides strong exception safety. If an exception
192          occurs when unlocking one mutex, other mutexes in the container get unlocked anyway.
193          @param mutexes Container of pointers to mutexes.  Container must have at least 1
194           mutex, all mutexes must have the same level, no NULL pointers, and all mutexes must
195           be locked by the current thread.  This sorts the container dby address order.
196          @return Enum value indicating success or error.
197          */
198         static MutexErrors::Type MultiUnlock( MutexContainer &mutexes );
199
200         /** Gives pointer to most recently locked mutex, or NULL if nothing locked.
201          The pointer is for a const mutex so the mutex can't be modified inappropriately.
202          The pointer is for a volatile mutex so callers can call volatile member
203          functions to get info about the mutex.
204          */
205         static const volatile LevelMutexInfo *GetCurrentMutex( void );
206
207         /// Returns the level of this mutex.
208         inline unsigned int GetLevel( void ) const volatile
209         {
210                 return m_level;
211         }
212
213         /// Returns true if this mutex was locked at least once.
214         inline bool IsLocked( void ) const volatile
215         {
216                 return ( 0 < m_count );
217         }
218
219         /// Returns count of how many times this mutex got locked.
220         inline unsigned int GetLockCount( void ) const volatile
221         {
222                 return m_count;
223         }
224
225         /// Returns pointer to mutex previously locked by the thread which locked this.
226         inline const volatile LevelMutexInfo *GetPrevious( void ) const volatile
227         {
228                 return m_previous;
229         }
230
231         /** Tries to lock mutex, and returns immediately if mutex already locked by
232          another thread.  It will return immediately with a value of AlreadyLocked
233          if the mutex was locked by a different thread.  It may throw an exception
234          or assert when errors occur if the ErrorPolicy class implements that behavior.
235          @return An error condition if any occurred, else Success.
236          */
237         virtual MutexErrors::Type TryLock( void ) volatile = 0;
238
239         /** Blocking call will attempt to lock mutex and wait until it can lock.
240          This may throw an exception if the lock failed or an error occurred - if
241          that is what the error policy specifies.
242          @return An error condition if any occurred, else Success.
243          */
244         virtual MutexErrors::Type Lock( void ) volatile = 0;
245
246         /** Attempts to lock mutex, but only waits for a limited amount of time
247          before it gives up.  Will return quickly if an error occurs before any
248          attempt to lock.  This may throw an exception if the lock failed or an
249          error occurred - if that is what the error policy specifies.
250          @param milliSeconds How long to wait.
251          @return An error condition if any occurred, else Success.
252          */
253         virtual MutexErrors::Type Lock( unsigned int milliSeconds ) volatile = 0;
254
255         /** Unlocks the mutex, or returns an error condition.  This may throw an
256          exception if the lock failed or an error occurred - if that is what the
257          error policy specifies.
258          @return An error condition if any occurred, else Success.
259          */
260         virtual MutexErrors::Type Unlock( void ) volatile = 0;
261
262         /** Returns true if this mutex was locked by current thread, and level is the same
263          as the current thread's level.  Which means this was the most recently locked
264          mutex, or it was locked along with several others of the same level recently.
265          */
266         bool IsRecentLock( void ) const volatile;
267
268         /** Returns true if this mutex was locked within the last count mutexes.
269          @param count How many recent mutexes to look through to find this mutex.
270          */
271         bool IsRecentLock( unsigned int count ) const volatile;
272
273         /// Returns true if this was locked by current thread.
274         bool IsLockedByCurrentThread( void ) const volatile;
275
276         /// Returns true if this was locked by another thread.
277         bool IsLockedByAnotherThread( void ) const volatile;
278
279 protected:
280
281         /** @class Checker Performs validity check on mutex to insure no class invariants
282          were violated inside any member function.  This class only gets used in debug
283          builds, and any instance of it gets optimized away in release builds.  A checker
284          is created inside many of member functions so that it's destructor gets called
285          when the function exits.  It determines if any class invariants were violated
286          during the function call.
287          */
288         class Checker
289         {
290         public:
291                 inline explicit Checker( const volatile LevelMutexInfo *mutex ) :
292                         m_mutex( mutex ) {}
293                 inline ~Checker( void )
294                 {
295                         m_mutex->IsValid();
296                 }
297         private:
298                 Checker( void );
299                 Checker( const Checker & );
300                 Checker &operator = ( const Checker & );
301                 const volatile LevelMutexInfo *m_mutex;
302         };
303
304         /** @class MutexUndoer
305          Undoes actions by MultiLock if an exception occurs.  It keeps track of
306          which mutexes in a container got locked, and if an exception occurs, then
307          the destructor unlocks them.  If MultiLock succeeds, then it cancels the
308          undoer so nothing gets unlocked inadvertently.
309          */
310         class MutexUndoer
311         {
312         public:
313
314                 explicit MutexUndoer( MutexContainer &mutexes );
315                 ~MutexUndoer( void );
316                 void SetPlace( LevelMutexContainerIter &here );
317                 void Cancel( void );
318
319         private:
320
321                 MutexUndoer( void );
322                 MutexUndoer( const MutexUndoer & );
323                 MutexUndoer &operator = ( const MutexUndoer & );
324
325                 MutexContainer &m_mutexes;
326                 LevelMutexContainerIter m_here;
327         };
328
329         /** Returns true if linked-list of locked mutexes in this thread is valid.
330          Which means the list has no loops, and each previous mutex on the list has a
331          higher or same level as the current mutex.  Called by IsValid.
332          */
333         static bool IsValidList( void );
334
335         /** This is the only available constructor, and it forces any derived class to set
336          a level for each mutex.
337          */
338         explicit LevelMutexInfo( unsigned int level );
339
340         /// The destructor only gets called by the derived class.
341         virtual ~LevelMutexInfo( void );
342
343         MutexErrors::Type PreLockCheck( bool forTryLock ) volatile;
344
345         MutexErrors::Type PreUnlockCheck( void ) volatile;
346
347         /** This gets called after each call to DoLock and DoTryLock to make sure the data
348          members in this object get set correctly.
349          */
350         void PostLock( void ) volatile;
351
352         /// Gets called just before an attempt to unlock a mutex.
353         void PreUnlock( void ) volatile;
354
355         /// Called to relock a mutex already locked by the current thread.
356         void IncrementCount( void ) volatile;
357
358         /// Called to unlock a mutex locked multiple times by the current thread.
359         void DecrementCount( void ) volatile;
360
361         /** Returns true if no class invariant broken, otherwise asserts.  This function
362         only gets called in debug builds.
363          */
364         bool IsValid( void ) const volatile;
365
366 private:
367
368         /// Copy constructor is not implemented.
369         LevelMutexInfo( const LevelMutexInfo & );
370         /// Copy-assignment operator is not implemented.
371         LevelMutexInfo &operator = ( const LevelMutexInfo & );
372
373         /** Called only by MultiLock & MultiUnlock to pass a result through an
374          error checking policy.
375          @param result What error condition to check.
376          @return Result or assertion or an exception - depending on error policy.
377          */
378         virtual MutexErrors::Type DoErrorCheck( MutexErrors::Type result ) const volatile = 0;
379
380         /// Called only by MultiLock to Lock each particular mutex within a container.
381         virtual MutexErrors::Type LockThis( void ) volatile = 0;
382
383         /** Called only by MultiLock to lock each particular mutex within a container.
384          @param milliSeconds How much time to wait before giving up on locking a mutex.
385          */
386         virtual MutexErrors::Type LockThis( unsigned int milliSeconds ) volatile = 0;
387
388         /// Called only by MultiUnlock to unlock each particular mutex within a container.
389         virtual MutexErrors::Type UnlockThis( void ) volatile = 0;
390
391         /// Pointer to singly-linked list of mutexes locked by the current thread.
392         static LOKI_THREAD_LOCAL volatile LevelMutexInfo *s_currentMutex;
393
394         /// Level of this mutex.
395         const unsigned int m_level;
396
397         /// How many times this mutex got locked.
398         unsigned int m_count;
399
400         /// Pointer to mutex locked before this one.
401         volatile LevelMutexInfo *m_previous;
402
403 };
404
405 // ----------------------------------------------------------------------------
406
407 /** @class ThrowOnAnyMutexError
408  Implements the ErrorPolicy for LevelMutex and throws an exception for any
409  error condition.  Only allows MutexErrors::Success and MutexErrors::NoProblem
410  to get through.  Useful for release builds.
411  */
412 class ThrowOnAnyMutexError
413 {
414 public:
415         static MutexErrors::Type CheckError( MutexErrors::Type error,
416                                              unsigned int level );
417 };
418
419 // ----------------------------------------------------------------------------
420
421 /** @class ThrowOnBadDesignMutexError
422  Implements the ErrorPolicy for LevelMutex and throws an exception if the error
423  indicates the programmer did not levelize the calls to mutexes.  Otherwise
424  returns the error result.  Useful for release builds.
425  */
426 class ThrowOnBadDesignMutexError
427 {
428 public:
429         static MutexErrors::Type CheckError( MutexErrors::Type error,
430                                              unsigned int level );
431 };
432
433 // ----------------------------------------------------------------------------
434
435 /** @class AssertAnyMutexError
436  Implements the ErrorPolicy for LevelMutex and asserts for any error condition.
437  Only allows MutexErrors::Success and MutexErrors::NoProblem to get through.
438  Useful for testing mutexes in debug builds.
439  */
440 class AssertAnyMutexError
441 {
442 public:
443         static inline MutexErrors::Type CheckError( MutexErrors::Type error,
444                 unsigned int level )
445         {
446                 (void)level;
447                 assert( ( error == MutexErrors::Success )
448                         || ( error == MutexErrors::NoProblem ) );
449                 return error;
450         }
451 };
452
453 // ----------------------------------------------------------------------------
454
455 /** @class AssertBadDesignMutexError
456  Implements the ErrorPolicy for LevelMutex and asserts if the error
457  indicates the programmer did not levelize the calls to mutexes.  Otherwise
458  returns the error result.  Useful for testing mutexes in debug builds.
459  */
460 class AssertBadDesignMutexError
461 {
462 public:
463         static inline MutexErrors::Type CheckError( MutexErrors::Type error,
464                 unsigned int level )
465         {
466                 (void)level;
467                 assert( ( error != MutexErrors::LevelTooHigh )
468                         && ( error != MutexErrors::LevelTooLow  ) );
469                 return error;
470         }
471 };
472
473 // ----------------------------------------------------------------------------
474
475 /** @class JustReturnMutexError
476  Implements the ErrorPolicy for LevelMutex and does nothing no matter how bad
477  the error condition.  Only recommended use is for automated unit-testing of
478  mutex policies.
479  */
480 class JustReturnMutexError
481 {
482 public:
483         static inline MutexErrors::Type CheckError( MutexErrors::Type error,
484                 unsigned int level )
485         {
486                 (void)level;
487                 return error;
488         }
489 };
490
491 // ----------------------------------------------------------------------------
492
493 /** @class NoMutexWait
494  Implements the WaitPolicy for LevelMutex.  Does nothing at all so it turns
495  all wait loops into spin loops.  Useful for low-level mutexes.
496  */
497 class NoMutexWait
498 {
499 public:
500         static inline void Wait( void ) {}
501 };
502
503 // ----------------------------------------------------------------------------
504
505 /** @class MutexSleepWaits
506  Implements the WaitPolicy for LevelMutex.  Sleeps for a moment so thread won't
507  consume idle CPU cycles.  Useful for high-level mutexes.
508  */
509 class MutexSleepWaits
510 {
511 public:
512         static void Wait( void );
513         static unsigned int sleepTime;
514 };
515
516 // ----------------------------------------------------------------------------
517
518 /** @class SpinLevelMutex
519  Implements a spin-loop to wait for the mutex to unlock.  Since this class makes
520  the thread wait in a tight spin-loop, it can cause the thread to remain busy
521  while waiting and thus consume CPU cycles.  For that reason, this mutex is best
522  used only for very low-level resources - especially resources which do not
523  require much CPU time to exercise.  Rule of thumb: Use this only if all actions
524  on the resource consume a very small number of CPU cycles.  Otherwise, use the
525  SleepLevelMutex instead.
526  */
527 class SpinLevelMutex
528 {
529 public:
530
531         /// Constructs a spin-level mutex.
532         explicit SpinLevelMutex( unsigned int level );
533
534         /// Destructs the mutex.
535         virtual ~SpinLevelMutex( void );
536
537         virtual MutexErrors::Type Lock( void ) volatile;
538
539         virtual MutexErrors::Type TryLock( void ) volatile;
540
541         virtual MutexErrors::Type Unlock( void ) volatile;
542
543         inline unsigned int GetLevel( void ) const volatile
544         {
545                 return m_level;
546         }
547
548 private:
549
550         /// Copy constructor is not implemented.
551         SpinLevelMutex( const SpinLevelMutex & );
552         /// Copy-assignment operator is not implemented.
553         SpinLevelMutex &operator = ( const SpinLevelMutex & );
554
555 #if defined( _MSC_VER )
556 #if ( _MSC_VER >= 1300 )
557         /// The actual mutex.
558         CRITICAL_SECTION m_mutex;
559 #else
560 #error "Only Visual Studio versions 7.0 and after supported."
561 #endif
562
563 #elif ( __GNUC__ )
564         /// The actual mutex.
565         pthread_mutex_t m_mutex;
566
567 #else
568 #error "Check if any mutex libraries are compatible with your compiler."
569 #endif
570
571         /// Keep a copy of the mutex level around for error reporting.
572         const unsigned int m_level;
573
574 }; // end class SpinLevelMutex
575
576 // ----------------------------------------------------------------------------
577
578 /** @class SleepLevelMutex
579  Implements a sleeping loop to wait for the mutex to unlock.
580
581  @par Purpose
582  Since this class puts the thread to sleep for short intervals, you can use this
583  class for most of your mutexes. Especially for locking any high level resources
584  where any one operation on the resouce consumes many CPU cycles.  The purpose of
585  this mutex is to reduce the number of CPU cycles spent in idle loops.  All
586  SleepLevelMutex's should have higher levels than all your SpinLevelMutex's.
587
588  @par Dependence on SpinLevelMutex
589  This utilizes SpinLevelMutex so it does not have to re-implement the DoTryLock
590  and DoUnlock functions the same way.  All it really needs is a DoLock function
591  and the amount of time it should sleep if an attempt to lock a function fails.
592  */
593 class SleepLevelMutex : public SpinLevelMutex
594 {
595 public:
596
597         /** Constructs a levelized mutex that puts threads to sleep while they wait
598          for another thread to unlock the mutex.
599          @param level Level of this mutex.
600          */
601         explicit SleepLevelMutex( unsigned int level );
602
603         SleepLevelMutex( unsigned int level, unsigned int sleepTime );
604
605         /// Destructs the mutex.
606         virtual ~SleepLevelMutex( void );
607
608         inline unsigned int GetSleepTime( void ) const volatile
609         {
610                 return m_sleepTime;
611         }
612
613         inline void SetSleepTime( unsigned int sleepTime ) volatile
614         {
615                 if ( 0 != sleepTime )
616                         m_sleepTime = sleepTime;
617         }
618
619 #if defined( _MSC_VER )
620         inline bool GetWakable( void ) const volatile
621         {
622                 return m_wakable;
623         }
624         inline void SetWakable( bool wakable ) volatile { m_wakable = wakable; }
625 #endif
626
627         /** Attempts to lock a mutex, and if it fails, then sleeps for a while
628          before attempting again.
629          */
630         virtual MutexErrors::Type Lock( void ) volatile;
631
632 private:
633
634         /// Default constructor is not implemented.
635         SleepLevelMutex( void );
636         /// Copy constructor is not implemented.
637         SleepLevelMutex( const SleepLevelMutex & );
638         /// Copy-assignment operator is not implemented.
639         SleepLevelMutex &operator = ( const SleepLevelMutex & );
640
641 #if defined( _MSC_VER )
642 #if ( _MSC_VER >= 1300 )
643         /// True if operating system may wake thread to respond to events.
644         bool m_wakable;
645 #else
646 #error "Only Visual Studio versions 7.0 and after supported."
647 #endif
648 #endif
649
650         /// How many milli-seconds to sleep before trying to lock mutex again.
651         unsigned int m_sleepTime;
652
653 }; // end class SleepLevelMutex
654
655 // ----------------------------------------------------------------------------
656
657 /** @class LevelMutex
658  Levelized mutex class prevents deadlocks by requiring programs to lock mutexes in
659  the same order, and unlock them in reverse order.  This is accomplished by forcing
660  each mutex to have a level and forcing code to lock mutexes with higher levels
661  before locking mutexes at lower levels.  If you want to lock several mutexes, they
662  must be locked in decreasing order by level, or if they are all of the same level,
663  then locked by LevelMutex::MultiLock.
664
665  @par Features
666  - Immune: Very unlikely to deadlock since all mutexes are locked in the same
667    order and unlocked in reverse order.
668  - Scalable: Can handle any number of mutexes.
669  - Efficient: Many operations occur in constant time, and most operations require
670    no more than O(m) steps.
671  - Exception safe: All operations provide strong safety or don't throw.
672  - Extendable: Can work with existing mutexes through policy-based design.
673  - Easily Extended: Derived classes only need to implement 5 functions and a mutex
674    to get all the features of this class.
675  - Re-Entrant: Allows for re-entrancy even if mutexes in policy classes don't.
676  - Cost-Free: No resource allocations occur in LevelMutex - although user-defined
677    policy classes may allocate resources.
678  - Compact: Each LevelMutex object is small.
679  - Portable: As long as your compiler and libraries can meet the requirements.
680  - Robust: Maintains data integrity even if exceptions occur in policy classes.
681  - Affording: Several functions provide information about a mutex which allows
682    client code to easily choose correct actions.
683
684  @par Requirements
685  - Your compiler must allow for thread-specific data.
686  - You must have a threading or mutex library.
687
688  @par Policy-Based Design
689  This class hosts 3 policies and a default level.  The policy-based design allows
690  users to write their own policies to extend the behaviors of LevelMutex.  The
691  paragraphs below say how to design a class for each policy.
692  - MutexPolicy The mutex policy class.
693  - defaultLevel A level for existing client code that calls a default constructor.
694  - ErrorPolicy How the mutex should handle error conditions.
695  - WaitPolicy Whether a thread should wait, and how long in some internal loops.
696
697  @par MutexPolicy
698  A policy class that wraps a low-level mutex. Loki provides two policy classes
699  for the actual mutex (SpinLevelMutex and SleepLevelMutex), both of which wrap
700  either pthreads or the Windows CRITICAL_SECTION. If you want to use a mutex
701  mechanism besides one of those, then all you have to do is provide a class
702  which wraps the mutex and implements these functions.
703     explicit SpinLevelMutex( unsigned int level );
704     virtual ~SpinLevelMutex( void );
705     virtual MutexErrors::Type Lock( void ) volatile;
706     virtual MutexErrors::Type TryLock( void ) volatile;
707     virtual MutexErrors::Type Unlock( void ) volatile;
708  Indeed, since the base class does most of the work, and provides all the interace
709  and functionality to client classes, a derived class has very few requirements.
710  It only needs to implement a single constructor, the destructor, some virtual
711  functions, and whatever data members it requires.  You don't actually need to
712  declare those functions as virtual if the policy class is not a base or child
713  class.  In the parlance of design patterns, LevelMutex is a Template, and the
714  MutexPolicy is a Strategy.
715
716  @par DefaultLevel
717  The template class requires a default level to use inside the default constructor.
718  Some existing code calls instantiates mutexes with a default constructor, so the
719  mutex must know what level to use there.  Please do not use zero or UnlockedLevel
720  as the default level.
721
722  @par ErrorPolicy
723  This policy specifies how to handle error conditions.  The mutexes can return
724  errors, assert, or throw exceptions.  I recommend that debug code use asserts,
725  release code use exceptions, and unit-testing code just return errors.  The
726  error policy class only needs to implement one function:
727    static MutexErrors::Type CheckError( MutexErrors::Type error, unsigned int level );
728
729  @par WaitPolicy
730  This states whether the mutex should wait within some tight internal loops,
731  how the waiting is done, and for how long.  A wait policy class could sleep,
732  do nothing, check if other objects need attention, or check if the program
733  received events or notices from the operating system.  It only needs to
734  implement one function:
735    static void Wait( void );
736
737  @par Per-Function Usage
738  If you implement a function with a static local mutex, then you have to insure
739  the function is not called from a lower level via call-backs, virtual functions in
740  interface classes.  If the function does get called from a lower level, you are
741  setting up a potential deadlock.  LevelMutex will detect that by checking the
742  current level and the local mutex's level, so it will refuse to lock the local mutex.
743
744  @par Per-Object Usage
745  If you use a mutex as a data member of an object to protect that object, then I
746  recommend specifying which functions are volatile and which are not, and then only
747  use the mutex within the volatile functions.  You may also want to provide accessor
748  functions so that client code can lock and unlock the mutex either to allow for
749  calling multiple operations without having to lock and unlock before and after each
750  operation, or so they can lock it along with several other objects at the same
751  level.
752
753  @par Per-Class Usage
754  If you make a static data member within a class, you can use that to lock any
755  resources shared by those objects, or to require threads to act on only one object
756  at a time.  You may also want to provide static accessor functions so that client
757  code can lock several other resources at the same level.
758  */
759
760 template
761 <
762 class MutexPolicy,
763       unsigned int DefaultLevel,
764       class ErrorPolicy = ::Loki::ThrowOnBadDesignMutexError,
765       class WaitPolicy  = ::Loki::NoMutexWait
766       >
767 class LevelMutex : public LevelMutexInfo
768 {
769 public:
770
771         typedef ErrorPolicy EP;
772         typedef WaitPolicy  WP;
773         typedef MutexPolicy MP;
774
775         /** This constructor allows callers to replace the default level with another
776          value.  It also acts as the default constructor for existing code which uses
777          default construction for mutexes.  This is the only time the DefaultLevel
778          template parameter gets used.
779          */
780         explicit LevelMutex( unsigned int level = DefaultLevel ) :
781                 LevelMutexInfo( level ),
782                 m_mutex( level )
783         {
784                 assert( IsValid() );
785         }
786
787         /// The destructor.
788         ~LevelMutex( void )
789         {
790                 assert( IsValid() );
791         }
792
793         /** These functions allow callers to access the mutex in case they need to
794          modify specific values in the MutexPolicy (e.g. - sleep time, functors to
795          call as tasks, etc...)  There is one function for every combination of
796          const and volatile qualifiers so callers get a reference to a MutexPolicy
797          with the proper qualifiers.
798          */
799         inline const volatile MutexPolicy &GetMutexPolicy( void ) const volatile
800         {
801                 return m_mutex;
802         }
803         inline       volatile MutexPolicy &GetMutexPolicy( void )       volatile { return m_mutex; }
804         inline const          MutexPolicy &GetMutexPolicy( void ) const
805         {
806                 return m_mutex;
807         }
808         inline                MutexPolicy &GetMutexPolicy( void )
809         {
810                 return m_mutex;
811         }
812
813         virtual MutexErrors::Type TryLock( void ) volatile
814         {
815                 assert( IsValid() );
816                 LOKI_MUTEX_DEBUG_CODE( Checker checker( this ); (void)checker; )
817
818                 MutexErrors::Type result = LevelMutexInfo::PreLockCheck( true );
819                 if ( MutexErrors::Success == result )
820                         return MutexErrors::Success;
821                 else if ( MutexErrors::AlreadyLocked == result )
822                         return result;
823                 else if ( MutexErrors::NoProblem != result )
824                         return EP::CheckError( result, GetLevel() );
825
826                 assert( 0 == LevelMutexInfo::GetLockCount() );
827                 result = m_mutex.TryLock();
828                 if ( MutexErrors::Success != result )
829                         return EP::CheckError( result, GetLevel() );
830                 LevelMutexInfo::PostLock();
831
832                 return MutexErrors::Success;
833         }
834
835         virtual MutexErrors::Type Lock( void ) volatile
836         {
837                 assert( IsValid() );
838                 LOKI_MUTEX_DEBUG_CODE( Checker checker( this ); (void)checker; )
839
840                 MutexErrors::Type result = LevelMutexInfo::PreLockCheck( false );
841                 if ( MutexErrors::Success == result )
842                         return MutexErrors::Success;
843                 else if ( MutexErrors::NoProblem != result )
844                         return EP::CheckError( result, GetLevel() );
845
846                 assert( !LevelMutexInfo::IsLockedByCurrentThread() );
847                 result = m_mutex.Lock();
848                 if ( MutexErrors::Success != result )
849                         return EP::CheckError( result, GetLevel() );
850                 PostLock();
851
852                 return MutexErrors::Success;
853         }
854
855         virtual MutexErrors::Type Lock( unsigned int milliSeconds ) volatile
856         {
857                 assert( IsValid() );
858                 LOKI_MUTEX_DEBUG_CODE( Checker checker( this ); (void)checker; )
859
860                 MutexErrors::Type result = LevelMutexInfo::PreLockCheck( false );
861                 if ( MutexErrors::Success == result )
862                         return MutexErrors::Success;
863                 else if ( MutexErrors::NoProblem != result )
864                         return EP::CheckError( result, GetLevel() );
865
866                 assert( !LevelMutexInfo::IsLockedByCurrentThread() );
867                 clock_t timeOut = clock() + milliSeconds;
868                 while ( clock() < timeOut )
869                 {
870                         WP::Wait();
871                         result = m_mutex.TryLock();
872                         switch ( result )
873                         {
874                         case MutexErrors::Success:
875                         {
876                                 PostLock();
877                                 return MutexErrors::Success;
878                         }
879                         case MutexErrors::AlreadyLocked:
880                                 return MutexErrors::AlreadyLocked;
881                         case MutexErrors::TryFailed:
882                                 break;
883                         default:
884                                 return EP::CheckError( result, GetLevel() );
885                         }
886                 }
887
888                 return MutexErrors::TimedOut;
889         }
890
891         virtual MutexErrors::Type Unlock( void ) volatile
892         {
893                 assert( IsValid() );
894                 LOKI_MUTEX_DEBUG_CODE( Checker checker( this ); (void)checker; )
895
896                 MutexErrors::Type result = LevelMutexInfo::PreUnlockCheck();
897                 if ( MutexErrors::Success == result )
898                         return MutexErrors::Success;
899                 else if ( MutexErrors::NoProblem != result )
900                         return EP::CheckError( result, GetLevel() );
901
902                 LevelMutexInfo::PreUnlock();
903                 result = MutexErrors::OtherError;
904                 try
905                 {
906                         result = m_mutex.Unlock();
907                         if ( MutexErrors::Success != result )
908                                 PostLock();
909                 }
910                 catch ( ... )
911                 {
912                         PostLock();
913                         result = MutexErrors::ExceptionThrown;
914                 }
915
916                 return result;
917         }
918
919 private:
920
921         /// Copy constructor is not implemented since mutexes don't get copied.
922         LevelMutex( const LevelMutex & );
923         /// Copy-assignment operator is not implemented since mutexes don't get copied.
924         LevelMutex &operator = ( const LevelMutex & );
925
926         virtual MutexErrors::Type DoErrorCheck( MutexErrors::Type result ) const volatile
927         {
928                 return EP::CheckError( result, GetLevel() );
929         }
930
931         /** Called only by MultiLock to lock each particular mutex within a container.
932          This does not do pre-lock error checking since MultiLock does that.  Since
933          this skips the error checking, that means that callers of LevelMutex should
934          not call this function directly, and so this will not be publicly available.
935          @return Error status indicating success or reason for failure.
936          */
937         virtual MutexErrors::Type LockThis( void ) volatile
938         {
939                 assert( IsValid() );
940                 LOKI_MUTEX_DEBUG_CODE( Checker checker( this ); (void)checker; )
941                 assert( this != LevelMutexInfo::GetCurrentMutex() );
942
943                 const MutexErrors::Type result = m_mutex.Lock();
944                 if ( MutexErrors::Success != result )
945                         return result;
946                 PostLock();
947
948                 return MutexErrors::Success;
949         }
950
951         /** Called only by MultiLock to lock each particular mutex within a container.
952          This does not do pre-lock error checking since MultiLock does that.  Since
953          this skips the error checking, callers of LevelMutex should not call this
954          function directly, and so this will not be publicly available.
955          @param milliSeconds How much time to wait before giving up on locking a mutex.
956          @return Error status indicating success or reason for failure.
957          */
958         virtual MutexErrors::Type LockThis( unsigned int milliSeconds ) volatile
959         {
960                 assert( IsValid() );
961                 LOKI_MUTEX_DEBUG_CODE( Checker checker( this ); (void)checker; )
962
963                 clock_t timeOut = clock() + milliSeconds;
964                 while ( clock() < timeOut )
965                 {
966                         WP::Wait();
967                         const bool locked = ( MutexErrors::Success == m_mutex.TryLock() );
968                         if ( locked )
969                         {
970                                 PostLock();
971                                 return MutexErrors::Success;
972                         }
973                 }
974
975                 return MutexErrors::TimedOut;
976         }
977
978         /** Called only by MultiUnlock to unlock each mutex within a container.
979          This does not do pre-unlock error checking since MultiLock does that.  Since
980          this skips the error checking, callers of LevelMutex should not call this
981          function directly, and so this will not be publicly available.
982          @return Error status indicating success or reason for failure.
983          */
984         virtual MutexErrors::Type UnlockThis( void ) volatile
985         {
986                 assert( IsValid() );
987                 assert( NULL != LevelMutexInfo::GetCurrentMutex() );
988                 LOKI_MUTEX_DEBUG_CODE( Checker checker( this ); (void)checker; )
989
990                 if ( 1 < LevelMutexInfo::GetLockCount() )
991                 {
992                         LevelMutexInfo::DecrementCount();
993                         return MutexErrors::Success;
994                 }
995
996                 LevelMutexInfo::PreUnlock();
997                 MutexErrors::Type result = m_mutex.Unlock();
998
999                 return result;
1000         }
1001
1002         /// An instance of an unleveled mutex wrapped to match LevelMutex's needs.
1003         MutexPolicy m_mutex;
1004
1005 }; // end class LevelMutex
1006
1007 // ----------------------------------------------------------------------------
1008
1009 /** Returns level of most recently locked mutex by this thread, or UnlockedLevel
1010  if no mutexes are locked.  Runs in constant time, and never throws exceptions.
1011  */
1012 unsigned int GetCurrentThreadsLevel( void );
1013
1014 /** Returns count of how mutexes the current thread locked.  Requires O(m)
1015  actions where m is the number of mutexes in the thread.  Never throws exceptions.
1016  */
1017 unsigned int CountMutexesInCurrentThread( void );
1018
1019 /** Returns count of how mutexes the current thread locked.  The lock count
1020  exceeds the number of mutexes locked by current thread if any mutex got locked
1021  more than once.  Requires O(m) actions where m is the number of mutexes in the
1022  thread.  Never throws exceptions.
1023  */
1024 unsigned int CountLocksInCurrentThread( void );
1025
1026 /** Returns count of mutexes locked by current thread which have the same level
1027  as GetCurrentThreadsLevel.  Requires O(m) actions where m is the number of
1028  mutexes in the thread at current level.  Never throws exceptions.
1029  */
1030 unsigned int CountMutexesAtCurrentLevel( void );
1031
1032 /** Determines if container of mutexes matches the recently locked mutexes.
1033  If they do match, it returns success, otherwise an error condition.
1034  */
1035 MutexErrors::Type DoMutexesMatchContainer( const LevelMutexInfo::MutexContainer &mutexes );
1036
1037 // ----------------------------------------------------------------------------
1038
1039 /** @class MutexException
1040  Exception class used to throw error statuses about LevelMutex's up to code that
1041  can respond to mutex problems.  This class exists because it conveys more info
1042  about the error condition than just ::std::exception.
1043  */
1044 class MutexException : public ::std::exception
1045 {
1046 public:
1047
1048         /** Constructs an exception which stores information about a mutex and the
1049          reason an attempt to use a mutex failed.
1050          */
1051         MutexException( const char *message, unsigned int level, MutexErrors::Type reason );
1052
1053         /// Copy constructor performs a member-by-member copy of an exception.
1054         MutexException( const MutexException &that ) throw ();
1055
1056         /// Copy-assignment operator performs a member-by-member copy of an exception.
1057         MutexException &operator = ( const MutexException &that ) throw ();
1058
1059         /// Destroys the exception.
1060         virtual ~MutexException( void ) throw();
1061
1062         /// Returns a simple message about which operation failed.
1063         virtual const char *what( void ) const throw();
1064
1065         /// Returns level of mutex(es) used when problem occurred.
1066         unsigned int GetLevel( void ) const
1067         {
1068                 return m_level;
1069         }
1070
1071         /// Returns an error status for why operation failed.
1072         MutexErrors::Type GetReason( void ) const
1073         {
1074                 return m_reason;
1075         }
1076
1077 private:
1078
1079         /// Default constructor is not implemented.
1080         MutexException( void ) throw ();
1081
1082         /// Simple message about operation that failed.
1083         const char *m_message;
1084         /// Level of mutex(es) used when problem occurred.
1085         unsigned int m_level;
1086         /// Error status for why operation failed.
1087         MutexErrors::Type m_reason;
1088
1089 }; // end class MutexException
1090
1091 // ----------------------------------------------------------------------------
1092
1093 /** @class MutexLocker
1094  You can place an instance of this as a local variable inside a function to lock
1095  a single mutex.  It will lock the mutex if no error occurs, or throw if one
1096  does happen.  When the function ends, the destructor will determine if it needs
1097  to unlock the mutex.  This RAII technique insures the mutex gets unlocked even
1098  when exceptions occur.
1099  */
1100 class MutexLocker
1101 {
1102 public:
1103
1104         /** Creates an object to lock an unlock a mutex for a function.  This
1105          will throw if an attempt to lock the mutex fails.
1106          @param mutex Reference to the mutex.
1107          @param lock True if function wants to lock the mutex as this gets
1108           constructed.
1109          */
1110         explicit MutexLocker( volatile LevelMutexInfo &mutex, bool lock = true );
1111
1112         /** Creates an object to lock an unlock a mutex for a function.  This waits
1113          a specified amount of time for another thread to unlock the mutex if it is
1114          locked.  This will throw if an attempt to lock the mutex fails.
1115          @param mutex Reference to the mutex.
1116          @param milliSeconds Amount of time to wait for another thread to unlock
1117           the mutex.
1118          @param lock True if function wants to lock the mutex as this gets
1119           constructed.
1120          */
1121         MutexLocker( volatile LevelMutexInfo &mutex, unsigned int milliSeconds,
1122                      bool lock = true );
1123
1124         /// Destructs the locker, and determines if it needs to unlock the mutex.
1125         ~MutexLocker( void );
1126
1127         /** You can call this to lock (or relock) a mutex.  In theory, you can lock
1128          and unlock a mutex several times within a function in order to give other
1129          threads access to a resource while this function does not need it.
1130          @return True if mutex is locked by this, else false if not locked.
1131          */
1132         bool Lock( void );
1133
1134         /** You can call this to unlock a mutex before the destructor does it.
1135          By unlocking the mutexes before returning, the function can do other
1136          operations without making other threads wait too long.
1137          @return True if unlocked by this, else false if not unlocked by this.
1138          (Which is not the same as whether the mutex itself is locked or not by
1139          another thread.)
1140          */
1141         bool Unlock( void );
1142
1143         /// Returns true if the mutex is locked by this object.
1144         inline bool IsLocked( void ) const
1145         {
1146                 return m_locked;
1147         }
1148
1149         /// Provides access to mutex controlled by this.
1150         const volatile LevelMutexInfo &GetMutex( void ) const
1151         {
1152                 return m_mutex;
1153         }
1154
1155 private:
1156
1157         /// Default constructor is not implemented.
1158         MutexLocker( void );
1159         /// Copy constructor is not implemented.
1160         MutexLocker( const MutexLocker & );
1161         /// Copy-assignment operator is not implemented.
1162         MutexLocker &operator = ( const MutexLocker & );
1163
1164         /// True if mutex got locked.
1165         bool m_locked;
1166
1167         /// Reference to mutex.
1168         volatile LevelMutexInfo &m_mutex;
1169 };
1170
1171 // ----------------------------------------------------------------------------
1172
1173 /** @class MultiMutexLocker
1174  You can place an instance of this as a local variable inside a function to lock
1175  a collection of mutexes.  It locks them if no error occurs, or throws an
1176  exception if one does happen.  When the function ends, the destructor determines
1177  if it needs to unlock the mutexes.  This RAII technique insures the mutexes get
1178  unlocked even when exceptions occur.  You will also have to construct a
1179  MutexContainer as a local object within the same function.
1180  */
1181 class MultiMutexLocker
1182 {
1183 public:
1184
1185         /** Creates an object to lock and unlock a collection of mutexes for a function.
1186          This will throw if an attempt to lock any mutex fails. If an exception occurs,
1187          it unlocks mutexes it previously locked.
1188          @param mutex Reference to a collection of mutexes.
1189          @param lock True if function wants to lock the mutex as this gets
1190           constructed.
1191          */
1192         explicit MultiMutexLocker( LevelMutexInfo::MutexContainer &mutexes,
1193                                    bool lock = true );
1194
1195         /** Creates an object to lock and unlock a collection of mutexes for a function.
1196          This waits a specified amount of time for other threads to unlock each mutex
1197          that is locked.  This will throw if an attempt to lock any mutex fails. If an
1198          exception occurs, it unlocks mutexes it previously locked.
1199          @param mutexes Reference to a collection of mutexes.
1200          @param milliSeconds Amount of time to wait for another thread to unlock
1201           the mutex.
1202          @param lock True if function wants to lock the mutexes as this gets
1203           constructed.
1204          */
1205         MultiMutexLocker( LevelMutexInfo::MutexContainer &mutexes,
1206                           unsigned int milliSeconds, bool lock = true );
1207
1208         /// Destructs the locker, and determines if it needs to unlock the mutexes.
1209         ~MultiMutexLocker( void );
1210
1211         /** You can call this to lock (or relock) the mutexes.  In theory, you can lock
1212          and unlock mutexes several times within a function in order to give other
1213          threads access to resources while this function does not need them.
1214          @return True if mutex is locked by this, else false if not locked.
1215          */
1216         bool Lock( void );
1217
1218         /** You can call this to unlock the mutexes before the destructor does it.
1219          By unlocking the mutexes before returning, the function can do other
1220          operations without making other threads wait too long.
1221          @return True if unlocked by this, else false if not unlocked by this.
1222          (Which is not the same as whether the mutex itself is locked or not by
1223          another thread.)
1224          */
1225         bool Unlock( void );
1226
1227         /// Returns true if the mutexes are locked by this object.
1228         inline bool IsLocked( void ) const
1229         {
1230                 return m_locked;
1231         }
1232
1233         /// Provides access to the collection of mutexes controlled by this.
1234         const LevelMutexInfo::MutexContainer &GetMutexes( void ) const
1235         {
1236                 return m_mutexes;
1237         }
1238
1239 private:
1240
1241         /// Default constructor is not implemented.
1242         MultiMutexLocker( void );
1243         /// Copy constructor is not implemented.
1244         MultiMutexLocker( const MultiMutexLocker & );
1245         /// Copy-assignment operator is not implemented.
1246         MultiMutexLocker &operator = ( const MultiMutexLocker & );
1247
1248         /// True if mutexes got locked.
1249         bool m_locked;
1250
1251         /// Reference to external container of mutexes;
1252         LevelMutexInfo::MutexContainer &m_mutexes;
1253 };
1254
1255 // ----------------------------------------------------------------------------
1256
1257 } // end namespace Loki
1258
1259 #endif  // end file guardian