@ -71,13 +71,17 @@ void static inline DeleteLock(void* cs) {}
# define AssertLockNotHeld(cs) AssertLockNotHeldInternal(#cs, __FILE__, __LINE__, &cs)
# define AssertLockNotHeld(cs) AssertLockNotHeldInternal(#cs, __FILE__, __LINE__, &cs)
/**
/**
* Template mixin that adds - Wthread - safety locking
* Template mixin that adds - Wthread - safety locking annotations and lock order
* annotations to a subset of the mutex API .
* checking to a subset of the mutex API .
*/
*/
template < typename PARENT >
template < typename PARENT >
class LOCKABLE AnnotatedMixin : public PARENT
class LOCKABLE AnnotatedMixin : public PARENT
{
{
public :
public :
~ AnnotatedMixin ( ) {
DeleteLock ( ( void * ) this ) ;
}
void lock ( ) EXCLUSIVE_LOCK_FUNCTION ( )
void lock ( ) EXCLUSIVE_LOCK_FUNCTION ( )
{
{
PARENT : : lock ( ) ;
PARENT : : lock ( ) ;
@ -92,19 +96,15 @@ public:
{
{
return PARENT : : try_lock ( ) ;
return PARENT : : try_lock ( ) ;
}
}
using UniqueLock = std : : unique_lock < PARENT > ;
} ;
} ;
/**
/**
* Wrapped mutex : supports recursive locking , but no waiting
* Wrapped mutex : supports recursive locking , but no waiting
* TODO : We should move away from using the recursive lock by default .
* TODO : We should move away from using the recursive lock by default .
*/
*/
class CCriticalSection : public AnnotatedMixin < std : : recursive_mutex >
typedef AnnotatedMixin < std : : recursive_mutex > CCriticalSection ;
{
public :
~ CCriticalSection ( ) {
DeleteLock ( ( void * ) this ) ;
}
} ;
/** Wrapped mutex: supports waiting but not recursive locking */
/** Wrapped mutex: supports waiting but not recursive locking */
typedef AnnotatedMixin < std : : mutex > CWaitableCriticalSection ;
typedef AnnotatedMixin < std : : mutex > CWaitableCriticalSection ;
@ -119,20 +119,19 @@ typedef std::unique_lock<std::mutex> WaitableLock;
void PrintLockContention ( const char * pszName , const char * pszFile , int nLine ) ;
void PrintLockContention ( const char * pszName , const char * pszFile , int nLine ) ;
# endif
# endif
/** Wrapper around std::unique_lock<CCriticalSection> */
/** Wrapper around std::unique_lock style lock for Mutex. */
class SCOPED_LOCKABLE CCriticalBlock
template < typename Mutex , typename Base = typename Mutex : : UniqueLock >
class SCOPED_LOCKABLE CCriticalBlock : public Base
{
{
private :
private :
std : : unique_lock < CCriticalSection > lock ;
void Enter ( const char * pszName , const char * pszFile , int nLine )
void Enter ( const char * pszName , const char * pszFile , int nLine )
{
{
EnterCritical ( pszName , pszFile , nLine , ( void * ) ( lock. mutex ( ) ) ) ;
EnterCritical ( pszName , pszFile , nLine , ( void * ) ( Base: : mutex ( ) ) ) ;
# ifdef DEBUG_LOCKCONTENTION
# ifdef DEBUG_LOCKCONTENTION
if ( ! lock. try_lock ( ) ) {
if ( ! Base: : try_lock ( ) ) {
PrintLockContention ( pszName , pszFile , nLine ) ;
PrintLockContention ( pszName , pszFile , nLine ) ;
# endif
# endif
lock. lock ( ) ;
Base: : lock ( ) ;
# ifdef DEBUG_LOCKCONTENTION
# ifdef DEBUG_LOCKCONTENTION
}
}
# endif
# endif
@ -140,15 +139,15 @@ private:
bool TryEnter ( const char * pszName , const char * pszFile , int nLine )
bool TryEnter ( const char * pszName , const char * pszFile , int nLine )
{
{
EnterCritical ( pszName , pszFile , nLine , ( void * ) ( lock. mutex ( ) ) , true ) ;
EnterCritical ( pszName , pszFile , nLine , ( void * ) ( Base: : mutex ( ) ) , true ) ;
lock. try_lock ( ) ;
Base: : try_lock ( ) ;
if ( ! lock. owns_lock ( ) )
if ( ! Base: : owns_lock ( ) )
LeaveCritical ( ) ;
LeaveCritical ( ) ;
return lock. owns_lock ( ) ;
return Base: : owns_lock ( ) ;
}
}
public :
public :
CCriticalBlock ( CCriticalSection & mutexIn , const char * pszName , const char * pszFile , int nLine , bool fTry = false ) EXCLUSIVE_LOCK_FUNCTION ( mutexIn ) : lock ( mutexIn , std : : defer_lock )
CCriticalBlock ( Mutex & mutexIn , const char * pszName , const char * pszFile , int nLine , bool fTry = false ) EXCLUSIVE_LOCK_FUNCTION ( mutexIn ) : Base ( mutexIn , std : : defer_lock )
{
{
if ( fTry )
if ( fTry )
TryEnter ( pszName , pszFile , nLine ) ;
TryEnter ( pszName , pszFile , nLine ) ;
@ -156,11 +155,11 @@ public:
Enter ( pszName , pszFile , nLine ) ;
Enter ( pszName , pszFile , nLine ) ;
}
}
CCriticalBlock ( CCriticalSection * pmutexIn , const char * pszName , const char * pszFile , int nLine , bool fTry = false ) EXCLUSIVE_LOCK_FUNCTION ( pmutexIn )
CCriticalBlock ( Mutex * pmutexIn , const char * pszName , const char * pszFile , int nLine , bool fTry = false ) EXCLUSIVE_LOCK_FUNCTION ( pmutexIn )
{
{
if ( ! pmutexIn ) return ;
if ( ! pmutexIn ) return ;
lock = std : : unique_lock < CCriticalSection > ( * pmutexIn , std : : defer_lock ) ;
* static_cast < Base * > ( this ) = Base ( * pmutexIn , std : : defer_lock ) ;
if ( fTry )
if ( fTry )
TryEnter ( pszName , pszFile , nLine ) ;
TryEnter ( pszName , pszFile , nLine ) ;
else
else
@ -169,22 +168,28 @@ public:
~ CCriticalBlock ( ) UNLOCK_FUNCTION ( )
~ CCriticalBlock ( ) UNLOCK_FUNCTION ( )
{
{
if ( lock. owns_lock ( ) )
if ( Base: : owns_lock ( ) )
LeaveCritical ( ) ;
LeaveCritical ( ) ;
}
}
operator bool ( )
operator bool ( )
{
{
return lock. owns_lock ( ) ;
return Base: : owns_lock ( ) ;
}
}
} ;
} ;
template < typename MutexArg >
using DebugLock = CCriticalBlock < typename std : : remove_reference < typename std : : remove_pointer < MutexArg > : : type > : : type > ;
# define PASTE(x, y) x ## y
# define PASTE(x, y) x ## y
# define PASTE2(x, y) PASTE(x, y)
# define PASTE2(x, y) PASTE(x, y)
# define LOCK(cs) CCriticalBlock PASTE2(criticalblock, __COUNTER__)(cs, #cs, __FILE__, __LINE__)
# define LOCK(cs) DebugLock<decltype(cs)> PASTE2(criticalblock, __COUNTER__)(cs, #cs, __FILE__, __LINE__)
# define LOCK2(cs1, cs2) CCriticalBlock criticalblock1(cs1, #cs1, __FILE__, __LINE__), criticalblock2(cs2, #cs2, __FILE__, __LINE__)
# define LOCK2(cs1, cs2) \
# define TRY_LOCK(cs, name) CCriticalBlock name(cs, #cs, __FILE__, __LINE__, true)
DebugLock < decltype ( cs1 ) > criticalblock1 ( cs1 , # cs1 , __FILE__ , __LINE__ ) ; \
DebugLock < decltype ( cs2 ) > criticalblock2 ( cs2 , # cs2 , __FILE__ , __LINE__ ) ;
# define TRY_LOCK(cs, name) DebugLock<decltype(cs)> name(cs, #cs, __FILE__, __LINE__, true)
# define WAIT_LOCK(cs, name) DebugLock<decltype(cs)> name(cs, #cs, __FILE__, __LINE__)
# define ENTER_CRITICAL_SECTION(cs) \
# define ENTER_CRITICAL_SECTION(cs) \
{ \
{ \