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
This commit is contained in:
rich_sposato 2009-11-02 05:48:02 +00:00
parent 096a7d5841
commit f16c81d265
2 changed files with 69 additions and 59 deletions

View file

@ -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 <unistd.h> // declares sleep under Linux
#include <unistd.h> // 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 <loki/ThreadLocal.h> // 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

View file

@ -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 <unistd.h> // needed for usleep function.
#endif
#include <algorithm>
#include <cerrno>
#if defined( DEBUG ) || defined( _DEBUG )
#define DEBUG_LOKI_LEVEL_MUTEX 1
#include <iostream>
#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 )