From f16c81d265c77982344f593d8dc005566dc9d54e Mon Sep 17 00:00:00 2001 From: rich_sposato Date: Mon, 2 Nov 2009 05:48:02 +0000 Subject: [PATCH] Moved thread_local macro code to separate header file. Added more error values to enum family. git-svn-id: svn://svn.code.sf.net/p/loki-lib/code/trunk@1048 7ec92016-0320-0410-acc4-a06ded1c099a --- include/loki/LevelMutex.h | 53 ++++++++++----------------- src/LevelMutex.cpp | 75 ++++++++++++++++++++++++++------------- 2 files changed, 69 insertions(+), 59 deletions(-) diff --git a/include/loki/LevelMutex.h b/include/loki/LevelMutex.h index 9afb4ca..23ff86d 100644 --- a/include/loki/LevelMutex.h +++ b/include/loki/LevelMutex.h @@ -1,12 +1,12 @@ //////////////////////////////////////////////////////////////////////////////// // // LevelMutex facility for the Loki Library -// Copyright (c) 2008 Richard Sposato +// Copyright (c) 2008, 2009 Richard Sposato // The copyright on this file is protected under the terms of the MIT license. // -// Permission to use, copy, modify, distribute and sell this software for any -// purpose is hereby granted without fee, provided that the above copyright -// notice appear in all copies and that both that copyright notice and this +// Permission to use, copy, modify, distribute and sell this software for any +// purpose is hereby granted without fee, provided that the above copyright +// notice appear in all copies and that both that copyright notice and this // permission notice appear in supporting documentation. // // The author makes no representations about the suitability of this software @@ -35,35 +35,14 @@ #endif #if !defined(_WIN32) && !defined(_WIN64) - #include // declares sleep under Linux + #include // declares usleep under Linux #endif -/** @par thread_local Keyword - The mutexes require compilers to provide thread local storage - meaning each - thread gets its own copy of the data. The next version of C++ will have a - new keyword, thread_local for that purpose. Some existing compilers already - provide thread local storage using different syntax, so these lines use - thread_local to mimic that syntax. If your compiler provides thread local - storage but using different syntax besides "thread_local", you may want to - modify these lines. If your compiler does not support thread local storage, - you can't use LevelMutex. - */ -#ifndef LOKI_THREAD_LOCAL - #if defined( _MSC_VER ) - #if ( _MSC_VER >= 1300 ) - #define LOKI_THREAD_LOCAL __declspec( thread ) - #else - #error "Only Visual Studio versions 7.0 and after supported." - #endif +#include // Include Loki's form of thread_local declaration. - #elif ( __GNUC__ ) - #define LOKI_THREAD_LOCAL __thread - - #else - #warning "Check if your compiler provides thread local storage." - #define LOKI_THREAD_LOCAL thread_local - #endif -#endif +#if !defined( LOKI_THREAD_LOCAL ) + #warning "Your compiler will not allow Loki::LevelMutex." +#else #if defined( DEBUG ) || defined( _DEBUG ) #define LOKI_MUTEX_DEBUG_CODE( x ) x @@ -106,7 +85,11 @@ public: InvalidAttribute, ///< PThread mutex improperly initialized. InvalidAddress, ///< Bad pointer used to initialize a PThread mutex. ExceptionThrown, ///< Exception caught in mutex operation. + InvertedPriority, ///< Mutex already locked by thread with lower priority. MayDeadlock, ///< Locking this mutex may cause a deadlock. + NotPrivileged, ///< Program does not have privilege to initialize mutexes. + NotEnoughMemory, ///< Program does not have enough memory to initialize mutex. + NotEnoughResources, ///< Program does not have enough resources to initialize mutex. OtherError ///< Unknown error occurred. }; }; @@ -374,7 +357,7 @@ private: */ virtual MutexErrors::Type LockThis( unsigned int milliSeconds ) volatile = 0; - /// Called only by MultiUnlock to unlock each particular mutex within a container. + /// Called only by MultiUnlock to unlock each particular mutex within a container. virtual MutexErrors::Type UnlockThis( void ) volatile = 0; /// Pointer to singly-linked list of mutexes locked by the current thread. @@ -565,7 +548,7 @@ private: Implements a sleeping loop to wait for the mutex to unlock. @par Purpose - Since this class puts the thread to sleep for short intervals, you can use this + Since this class puts the thread to sleep for short intervals, you can use this class for most of your mutexes. Especially for locking any high level resources where any one operation on the resouce consumes many CPU cycles. The purpose of this mutex is to reduce the number of CPU cycles spent in idle loops. All @@ -1101,7 +1084,7 @@ public: /// Returns true if the mutex is locked by this object. inline bool IsLocked( void ) const { return m_locked; } - /// Provides access to mutex controlled by this. + /// Provides access to mutex controlled by this. const volatile LevelMutexInfo & GetMutex( void ) const { return m_mutex; } private: @@ -1179,7 +1162,7 @@ public: /// Returns true if the mutexes are locked by this object. inline bool IsLocked( void ) const { return m_locked; } - /// Provides access to the collection of mutexes controlled by this. + /// Provides access to the collection of mutexes controlled by this. const LevelMutexInfo::MutexContainer & GetMutexes( void ) const { return m_mutexes; } private: @@ -1202,4 +1185,6 @@ private: } // end namespace Loki +#endif // end else if compiler allows thread_local storage + #endif // end file guardian diff --git a/src/LevelMutex.cpp b/src/LevelMutex.cpp index ae08f14..15df5ec 100644 --- a/src/LevelMutex.cpp +++ b/src/LevelMutex.cpp @@ -1,7 +1,7 @@ //////////////////////////////////////////////////////////////////////////////// // // LevelMutex facility for the Loki Library -// Copyright (c) 2008 Richard Sposato +// Copyright (c) 2008, 2009 Richard Sposato // The copyright on this file is protected under the terms of the MIT license. // // Permission to use, copy, modify, distribute and sell this software for any @@ -18,36 +18,22 @@ /// @file LevelMutex.cpp Contains functions needed by LevelMutex class. + // ---------------------------------------------------------------------------- -// First assume the compiler does allow thread-local storage by #defining the -// macro which allows compiler to see the code inside this file. -// Then #undefine the macro for compilers which are known for not supporting -// thread-local storage. -#define COMPILER_ALLOWS_THREAD_LOCAL_STORAGE 1 - -// The __APPLE__ macro does not refer to a compiler, but to the Apple OSX operating system. -#if defined( __APPLE__ ) - #warning "GCC for Apple does not allow thread_local storage, so you can not use Loki::LevelMutex." - #undef COMPILER_ALLOWS_THREAD_LOCAL_STORAGE -#endif - -#if ( defined( __CYGWIN__ ) && ( __GNUC__ <= 3 ) ) - #warning "Older versions of GCC for Cygwin do not allow thread_local storage, so you can not use Loki::LevelMutex." - #undef COMPILER_ALLOWS_THREAD_LOCAL_STORAGE -#endif - -#if defined( COMPILER_ALLOWS_THREAD_LOCAL_STORAGE ) - - #include "../include/loki/LevelMutex.h" +#if defined( LOKI_THREAD_LOCAL ) + #if !defined( _MSC_VER ) #include // needed for usleep function. #endif #include #include - +#if defined( DEBUG ) || defined( _DEBUG ) + #define DEBUG_LOKI_LEVEL_MUTEX 1 + #include +#endif using namespace ::std; @@ -806,6 +792,9 @@ SpinLevelMutex::SpinLevelMutex( unsigned int level ) : switch ( result ) { case 0: +//#if defined( DEBUG_LOKI_LEVEL_MUTEX ) +// cout << __FUNCTION__ << '\t' << __LINE__ << endl; +//#endif return; case EBUSY: throw MutexException( "pthread mutex already initialized!", @@ -817,6 +806,18 @@ SpinLevelMutex::SpinLevelMutex( unsigned int level ) : case EFAULT: throw MutexException( "pthread mutex has an invalid address!", level, MutexErrors::InvalidAddress ); + case ENOMEM: + throw MutexException( + "System does not have enough memory to initialize a pthread mutex.", + level, MutexErrors::NotEnoughMemory ); + case EPERM: + throw MutexException( + "Program does not have privilege to initialize a pthread mutex.", + level, MutexErrors::NotPrivileged ); + case EAGAIN: + throw MutexException( + "Program does not have resources to initialize another pthread mutex.", + level, MutexErrors::NotEnoughResources ); } #endif } @@ -830,6 +831,9 @@ SpinLevelMutex::~SpinLevelMutex( void ) #if defined( _MSC_VER ) ::DeleteCriticalSection( &m_mutex ); #else +//#if defined( DEBUG_LOKI_LEVEL_MUTEX ) +// cout << __FUNCTION__ << '\t' << __LINE__ << endl; +//#endif ::pthread_mutex_destroy( &m_mutex ); #endif } @@ -853,17 +857,29 @@ MutexErrors::Type SpinLevelMutex::Lock( void ) volatile switch ( result ) { case 0: +//#if defined( DEBUG_LOKI_LEVEL_MUTEX ) +// cout << __FUNCTION__ << '\t' << __LINE__ << endl; +//#endif break; default: case EINVAL: - throw MutexException( "pthread mutex not initialized properly!", - GetLevel(), MutexErrors::NotInitialized ); + throw MutexException( "pthread mutex locked by thread with lower priority!", + GetLevel(), MutexErrors::InvertedPriority ); case EFAULT : throw MutexException( "pthread mutex is not valid!", GetLevel(), MutexErrors::InvalidAddress ); case EDEADLK: throw MutexException( "locking this pthread mutex may cause a deadlock!", GetLevel(), MutexErrors::MayDeadlock ); + case EBUSY: + throw MutexException( "Mutex is already locked by this thread.", + GetLevel(), MutexErrors::AlreadyLocked ); + case EAGAIN: + throw MutexException( "Mutex already locked too many times by this thread.", + GetLevel(), MutexErrors::TooMuchRecursion ); + case EPERM: + throw MutexException( "This thread does not own the mutex.", + GetLevel(), MutexErrors::NotPrivileged ); } #endif return MutexErrors::Success; @@ -884,6 +900,9 @@ MutexErrors::Type SpinLevelMutex::TryLock( void ) volatile switch ( result ) { case 0: +//#if defined( DEBUG_LOKI_LEVEL_MUTEX ) +// cout << __FUNCTION__ << '\t' << __LINE__ << endl; +//#endif return MutexErrors::Success; default: case EBUSY: @@ -891,6 +910,9 @@ MutexErrors::Type SpinLevelMutex::TryLock( void ) volatile case EAGAIN: throw MutexException( "pthread mutex reached recursion limit!", GetLevel(), MutexErrors::TooMuchRecursion ); + case EINVAL: + throw MutexException( "pthread mutex locked by thread with lower priority!", + GetLevel(), MutexErrors::InvertedPriority ); } return MutexErrors::TryFailed; #endif @@ -910,6 +932,9 @@ MutexErrors::Type SpinLevelMutex::Unlock( void ) volatile if ( EPERM == result ) throw MutexException( "current thread did not lock this pthread mutex!", GetLevel(), MutexErrors::NotLockedByThread ); +//#if defined( DEBUG_LOKI_LEVEL_MUTEX ) +// cout << __FUNCTION__ << '\t' << __LINE__ << endl; +//#endif #endif return MutexErrors::Success; } @@ -1165,4 +1190,4 @@ bool MultiMutexLocker::Unlock( void ) } // end namespace Loki -#endif // #if defined( COMPILER_ALLOWS_THREAD_LOCAL_STORAGE ) +#endif // #if defined( LOKI_THREAD_LOCAL )