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:
parent
096a7d5841
commit
f16c81d265
2 changed files with 69 additions and 59 deletions
|
@ -1,12 +1,12 @@
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// LevelMutex facility for the Loki Library
|
// 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.
|
// 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
|
// Permission to use, copy, modify, distribute and sell this software for any
|
||||||
// purpose is hereby granted without fee, provided that the above copyright
|
// purpose is hereby granted without fee, provided that the above copyright
|
||||||
// notice appear in all copies and that both that copyright notice and this
|
// notice appear in all copies and that both that copyright notice and this
|
||||||
// permission notice appear in supporting documentation.
|
// permission notice appear in supporting documentation.
|
||||||
//
|
//
|
||||||
// The author makes no representations about the suitability of this software
|
// The author makes no representations about the suitability of this software
|
||||||
|
@ -35,35 +35,14 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(_WIN32) && !defined(_WIN64)
|
#if !defined(_WIN32) && !defined(_WIN64)
|
||||||
#include <unistd.h> // declares sleep under Linux
|
#include <unistd.h> // declares usleep under Linux
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/** @par thread_local Keyword
|
#include <loki/ThreadLocal.h> // Include Loki's form of thread_local declaration.
|
||||||
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
|
|
||||||
|
|
||||||
#elif ( __GNUC__ )
|
#if !defined( LOKI_THREAD_LOCAL )
|
||||||
#define LOKI_THREAD_LOCAL __thread
|
#warning "Your compiler will not allow Loki::LevelMutex."
|
||||||
|
#else
|
||||||
#else
|
|
||||||
#warning "Check if your compiler provides thread local storage."
|
|
||||||
#define LOKI_THREAD_LOCAL thread_local
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined( DEBUG ) || defined( _DEBUG )
|
#if defined( DEBUG ) || defined( _DEBUG )
|
||||||
#define LOKI_MUTEX_DEBUG_CODE( x ) x
|
#define LOKI_MUTEX_DEBUG_CODE( x ) x
|
||||||
|
@ -106,7 +85,11 @@ public:
|
||||||
InvalidAttribute, ///< PThread mutex improperly initialized.
|
InvalidAttribute, ///< PThread mutex improperly initialized.
|
||||||
InvalidAddress, ///< Bad pointer used to initialize a PThread mutex.
|
InvalidAddress, ///< Bad pointer used to initialize a PThread mutex.
|
||||||
ExceptionThrown, ///< Exception caught in mutex operation.
|
ExceptionThrown, ///< Exception caught in mutex operation.
|
||||||
|
InvertedPriority, ///< Mutex already locked by thread with lower priority.
|
||||||
MayDeadlock, ///< Locking this mutex may cause a deadlock.
|
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.
|
OtherError ///< Unknown error occurred.
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -374,7 +357,7 @@ private:
|
||||||
*/
|
*/
|
||||||
virtual MutexErrors::Type LockThis( unsigned int milliSeconds ) volatile = 0;
|
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;
|
virtual MutexErrors::Type UnlockThis( void ) volatile = 0;
|
||||||
|
|
||||||
/// Pointer to singly-linked list of mutexes locked by the current thread.
|
/// 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.
|
Implements a sleeping loop to wait for the mutex to unlock.
|
||||||
|
|
||||||
@par Purpose
|
@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
|
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
|
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
|
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.
|
/// Returns true if the mutex is locked by this object.
|
||||||
inline bool IsLocked( void ) const { return m_locked; }
|
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; }
|
const volatile LevelMutexInfo & GetMutex( void ) const { return m_mutex; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -1179,7 +1162,7 @@ public:
|
||||||
/// Returns true if the mutexes are locked by this object.
|
/// Returns true if the mutexes are locked by this object.
|
||||||
inline bool IsLocked( void ) const { return m_locked; }
|
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; }
|
const LevelMutexInfo::MutexContainer & GetMutexes( void ) const { return m_mutexes; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -1202,4 +1185,6 @@ private:
|
||||||
|
|
||||||
} // end namespace Loki
|
} // end namespace Loki
|
||||||
|
|
||||||
|
#endif // end else if compiler allows thread_local storage
|
||||||
|
|
||||||
#endif // end file guardian
|
#endif // end file guardian
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// LevelMutex facility for the Loki Library
|
// 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.
|
// 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
|
// 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.
|
/// @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"
|
#include "../include/loki/LevelMutex.h"
|
||||||
|
|
||||||
|
#if defined( LOKI_THREAD_LOCAL )
|
||||||
|
|
||||||
#if !defined( _MSC_VER )
|
#if !defined( _MSC_VER )
|
||||||
#include <unistd.h> // needed for usleep function.
|
#include <unistd.h> // needed for usleep function.
|
||||||
#endif
|
#endif
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
|
#if defined( DEBUG ) || defined( _DEBUG )
|
||||||
|
#define DEBUG_LOKI_LEVEL_MUTEX 1
|
||||||
|
#include <iostream>
|
||||||
|
#endif
|
||||||
|
|
||||||
using namespace ::std;
|
using namespace ::std;
|
||||||
|
|
||||||
|
@ -806,6 +792,9 @@ SpinLevelMutex::SpinLevelMutex( unsigned int level ) :
|
||||||
switch ( result )
|
switch ( result )
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
|
//#if defined( DEBUG_LOKI_LEVEL_MUTEX )
|
||||||
|
// cout << __FUNCTION__ << '\t' << __LINE__ << endl;
|
||||||
|
//#endif
|
||||||
return;
|
return;
|
||||||
case EBUSY:
|
case EBUSY:
|
||||||
throw MutexException( "pthread mutex already initialized!",
|
throw MutexException( "pthread mutex already initialized!",
|
||||||
|
@ -817,6 +806,18 @@ SpinLevelMutex::SpinLevelMutex( unsigned int level ) :
|
||||||
case EFAULT:
|
case EFAULT:
|
||||||
throw MutexException( "pthread mutex has an invalid address!",
|
throw MutexException( "pthread mutex has an invalid address!",
|
||||||
level, MutexErrors::InvalidAddress );
|
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
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -830,6 +831,9 @@ SpinLevelMutex::~SpinLevelMutex( void )
|
||||||
#if defined( _MSC_VER )
|
#if defined( _MSC_VER )
|
||||||
::DeleteCriticalSection( &m_mutex );
|
::DeleteCriticalSection( &m_mutex );
|
||||||
#else
|
#else
|
||||||
|
//#if defined( DEBUG_LOKI_LEVEL_MUTEX )
|
||||||
|
// cout << __FUNCTION__ << '\t' << __LINE__ << endl;
|
||||||
|
//#endif
|
||||||
::pthread_mutex_destroy( &m_mutex );
|
::pthread_mutex_destroy( &m_mutex );
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -853,17 +857,29 @@ MutexErrors::Type SpinLevelMutex::Lock( void ) volatile
|
||||||
switch ( result )
|
switch ( result )
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
|
//#if defined( DEBUG_LOKI_LEVEL_MUTEX )
|
||||||
|
// cout << __FUNCTION__ << '\t' << __LINE__ << endl;
|
||||||
|
//#endif
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
case EINVAL:
|
case EINVAL:
|
||||||
throw MutexException( "pthread mutex not initialized properly!",
|
throw MutexException( "pthread mutex locked by thread with lower priority!",
|
||||||
GetLevel(), MutexErrors::NotInitialized );
|
GetLevel(), MutexErrors::InvertedPriority );
|
||||||
case EFAULT :
|
case EFAULT :
|
||||||
throw MutexException( "pthread mutex is not valid!",
|
throw MutexException( "pthread mutex is not valid!",
|
||||||
GetLevel(), MutexErrors::InvalidAddress );
|
GetLevel(), MutexErrors::InvalidAddress );
|
||||||
case EDEADLK:
|
case EDEADLK:
|
||||||
throw MutexException( "locking this pthread mutex may cause a deadlock!",
|
throw MutexException( "locking this pthread mutex may cause a deadlock!",
|
||||||
GetLevel(), MutexErrors::MayDeadlock );
|
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
|
#endif
|
||||||
return MutexErrors::Success;
|
return MutexErrors::Success;
|
||||||
|
@ -884,6 +900,9 @@ MutexErrors::Type SpinLevelMutex::TryLock( void ) volatile
|
||||||
switch ( result )
|
switch ( result )
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
|
//#if defined( DEBUG_LOKI_LEVEL_MUTEX )
|
||||||
|
// cout << __FUNCTION__ << '\t' << __LINE__ << endl;
|
||||||
|
//#endif
|
||||||
return MutexErrors::Success;
|
return MutexErrors::Success;
|
||||||
default:
|
default:
|
||||||
case EBUSY:
|
case EBUSY:
|
||||||
|
@ -891,6 +910,9 @@ MutexErrors::Type SpinLevelMutex::TryLock( void ) volatile
|
||||||
case EAGAIN:
|
case EAGAIN:
|
||||||
throw MutexException( "pthread mutex reached recursion limit!",
|
throw MutexException( "pthread mutex reached recursion limit!",
|
||||||
GetLevel(), MutexErrors::TooMuchRecursion );
|
GetLevel(), MutexErrors::TooMuchRecursion );
|
||||||
|
case EINVAL:
|
||||||
|
throw MutexException( "pthread mutex locked by thread with lower priority!",
|
||||||
|
GetLevel(), MutexErrors::InvertedPriority );
|
||||||
}
|
}
|
||||||
return MutexErrors::TryFailed;
|
return MutexErrors::TryFailed;
|
||||||
#endif
|
#endif
|
||||||
|
@ -910,6 +932,9 @@ MutexErrors::Type SpinLevelMutex::Unlock( void ) volatile
|
||||||
if ( EPERM == result )
|
if ( EPERM == result )
|
||||||
throw MutexException( "current thread did not lock this pthread mutex!",
|
throw MutexException( "current thread did not lock this pthread mutex!",
|
||||||
GetLevel(), MutexErrors::NotLockedByThread );
|
GetLevel(), MutexErrors::NotLockedByThread );
|
||||||
|
//#if defined( DEBUG_LOKI_LEVEL_MUTEX )
|
||||||
|
// cout << __FUNCTION__ << '\t' << __LINE__ << endl;
|
||||||
|
//#endif
|
||||||
#endif
|
#endif
|
||||||
return MutexErrors::Success;
|
return MutexErrors::Success;
|
||||||
}
|
}
|
||||||
|
@ -1165,4 +1190,4 @@ bool MultiMutexLocker::Unlock( void )
|
||||||
|
|
||||||
} // end namespace Loki
|
} // end namespace Loki
|
||||||
|
|
||||||
#endif // #if defined( COMPILER_ALLOWS_THREAD_LOCAL_STORAGE )
|
#endif // #if defined( LOKI_THREAD_LOCAL )
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue