2010-04-25 00:31:27 +00:00
/*
2010-04-24 21:37:39 +00:00
* Copyright ( C ) 2007 - 2009 Gabest
* http : //www.gabest.org
*
* This Program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 , or ( at your option )
* any later version .
2010-04-25 00:31:27 +00:00
*
2010-04-24 21:37:39 +00:00
* This Program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
2010-04-25 00:31:27 +00:00
*
2010-04-24 21:37:39 +00:00
* You should have received a copy of the GNU General Public License
* along with GNU Make ; see the file COPYING . If not , write to
2012-09-09 18:16:11 +00:00
* the Free Software Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 , USA USA .
2010-04-24 21:37:39 +00:00
* http : //www.gnu.org/copyleft/gpl.html
*
*/
# pragma once
2012-01-18 11:47:31 +00:00
# include "GSdx.h"
2012-02-08 16:57:14 +00:00
class IGSThread
{
protected :
virtual void ThreadProc ( ) = 0 ;
} ;
class IGSLock
{
public :
virtual void Lock ( ) = 0 ;
virtual bool TryLock ( ) = 0 ;
virtual void Unlock ( ) = 0 ;
2013-06-28 17:32:37 +00:00
virtual ~ IGSLock ( ) { }
2012-02-08 16:57:14 +00:00
} ;
class IGSEvent
{
public :
virtual void Set ( ) = 0 ;
virtual bool Wait ( IGSLock * l ) = 0 ;
2013-06-28 17:32:37 +00:00
virtual ~ IGSEvent ( ) { }
2012-02-08 16:57:14 +00:00
} ;
2011-02-19 03:36:30 +00:00
# ifdef _WINDOWS
2011-12-27 09:15:35 +00:00
typedef void ( WINAPI * InitializeConditionVariablePtr ) ( CONDITION_VARIABLE * ConditionVariable ) ;
typedef void ( WINAPI * WakeConditionVariablePtr ) ( CONDITION_VARIABLE * ConditionVariable ) ;
typedef void ( WINAPI * WakeAllConditionVariablePtr ) ( CONDITION_VARIABLE * ConditionVariable ) ;
2012-02-08 16:57:14 +00:00
typedef BOOL ( WINAPI * SleepConditionVariableSRWPtr ) ( CONDITION_VARIABLE * ConditionVariable , SRWLOCK * SRWLock , DWORD dwMilliseconds , ULONG Flags ) ;
2011-12-27 09:15:35 +00:00
typedef void ( WINAPI * InitializeSRWLockPtr ) ( SRWLOCK * SRWLock ) ;
typedef void ( WINAPI * AcquireSRWLockExclusivePtr ) ( SRWLOCK * SRWLock ) ;
2012-02-08 16:57:14 +00:00
typedef BOOLEAN ( WINAPI * TryAcquireSRWLockExclusivePtr ) ( SRWLOCK * SRWLock ) ;
typedef void ( WINAPI * ReleaseSRWLockExclusivePtr ) ( SRWLOCK * SRWLock ) ;
typedef void ( WINAPI * AcquireSRWLockSharedPtr ) ( SRWLOCK * SRWLock ) ;
typedef BOOLEAN ( WINAPI * TryAcquireSRWLockSharedPtr ) ( SRWLOCK * SRWLock ) ;
typedef void ( WINAPI * ReleaseSRWLockSharedPtr ) ( SRWLOCK * SRWLock ) ;
2011-12-27 09:15:35 +00:00
extern InitializeConditionVariablePtr pInitializeConditionVariable ;
extern WakeConditionVariablePtr pWakeConditionVariable ;
extern WakeAllConditionVariablePtr pWakeAllConditionVariable ;
extern SleepConditionVariableSRWPtr pSleepConditionVariableSRW ;
2012-02-08 16:57:14 +00:00
extern InitializeSRWLockPtr pInitializeSRWLock ;
2011-12-27 09:15:35 +00:00
extern AcquireSRWLockExclusivePtr pAcquireSRWLockExclusive ;
2012-02-08 16:57:14 +00:00
extern TryAcquireSRWLockExclusivePtr pTryAcquireSRWLockExclusive ;
extern ReleaseSRWLockExclusivePtr pReleaseSRWLockExclusive ;
extern AcquireSRWLockSharedPtr pAcquireSRWLockShared ;
extern TryAcquireSRWLockSharedPtr pTryAcquireSRWLockShared ;
extern ReleaseSRWLockSharedPtr pReleaseSRWLockShared ;
2011-12-27 09:15:35 +00:00
2012-02-08 16:57:14 +00:00
class GSThread : public IGSThread
2010-04-24 21:37:39 +00:00
{
DWORD m_ThreadId ;
HANDLE m_hThread ;
2011-02-19 03:36:30 +00:00
static DWORD WINAPI StaticThreadProc ( void * lpParam ) ;
protected :
void CreateThread ( ) ;
void CloseThread ( ) ;
public :
GSThread ( ) ;
virtual ~ GSThread ( ) ;
} ;
2012-02-08 16:57:14 +00:00
class GSCritSec : public IGSLock
2011-02-19 03:36:30 +00:00
{
CRITICAL_SECTION m_cs ;
public :
GSCritSec ( ) { InitializeCriticalSection ( & m_cs ) ; }
~ GSCritSec ( ) { DeleteCriticalSection ( & m_cs ) ; }
2012-02-08 16:57:14 +00:00
void Lock ( ) { EnterCriticalSection ( & m_cs ) ; }
bool TryLock ( ) { return TryEnterCriticalSection ( & m_cs ) = = TRUE ; }
void Unlock ( ) { LeaveCriticalSection ( & m_cs ) ; }
2011-02-19 03:36:30 +00:00
} ;
2012-02-08 16:57:14 +00:00
class GSEvent : public IGSEvent
2011-02-19 03:36:30 +00:00
{
protected :
HANDLE m_hEvent ;
public :
2012-02-08 16:57:14 +00:00
GSEvent ( ) { m_hEvent = CreateEvent ( NULL , FALSE , FALSE , NULL ) ; }
2011-12-20 14:33:28 +00:00
~ GSEvent ( ) { CloseHandle ( m_hEvent ) ; }
2011-02-19 03:36:30 +00:00
void Set ( ) { SetEvent ( m_hEvent ) ; }
2012-02-08 16:57:14 +00:00
bool Wait ( IGSLock * l ) { if ( l ) l - > Unlock ( ) ; bool b = WaitForSingleObject ( m_hEvent , INFINITE ) = = WAIT_OBJECT_0 ; if ( l ) l - > Lock ( ) ; return b ; }
2011-02-19 03:36:30 +00:00
} ;
2011-03-27 03:12:12 +00:00
2012-02-08 16:57:14 +00:00
class GSCondVarLock : public IGSLock
2011-12-27 09:15:35 +00:00
{
SRWLOCK m_lock ;
public :
GSCondVarLock ( ) { pInitializeSRWLock ( & m_lock ) ; }
void Lock ( ) { pAcquireSRWLockExclusive ( & m_lock ) ; }
2012-02-08 16:57:14 +00:00
bool TryLock ( ) { return pTryAcquireSRWLockExclusive ( & m_lock ) = = TRUE ; }
void Unlock ( ) { pReleaseSRWLockExclusive ( & m_lock ) ; }
2011-12-27 09:15:35 +00:00
operator SRWLOCK * ( ) { return & m_lock ; }
} ;
2012-02-08 16:57:14 +00:00
class GSCondVar : public IGSEvent
2011-12-27 09:15:35 +00:00
{
CONDITION_VARIABLE m_cv ;
public :
GSCondVar ( ) { pInitializeConditionVariable ( & m_cv ) ; }
void Set ( ) { pWakeConditionVariable ( & m_cv ) ; }
2012-02-08 16:57:14 +00:00
bool Wait ( IGSLock * l ) { return pSleepConditionVariableSRW ( & m_cv , * ( GSCondVarLock * ) l , INFINITE , 0 ) ! = 0 ; }
2011-12-27 09:15:35 +00:00
operator CONDITION_VARIABLE * ( ) { return & m_cv ; }
} ;
2011-02-19 03:36:30 +00:00
# else
2014-11-18 13:40:29 +00:00
// let us use std::thread for now, comment out the definition to go back to pthread
2014-12-14 11:19:15 +00:00
//#define _STD_THREAD_
2014-11-18 13:40:29 +00:00
# ifdef _STD_THREAD_
# include <thread>
# include <mutex>
# include <condition_variable>
# else
2011-02-19 03:36:30 +00:00
# include <pthread.h>
2011-02-19 10:27:10 +00:00
# include <semaphore.h>
2014-11-18 13:40:29 +00:00
# endif
2011-02-19 03:36:30 +00:00
2012-02-08 16:57:14 +00:00
class GSThread : public IGSThread
2011-02-19 03:36:30 +00:00
{
2014-11-18 13:40:29 +00:00
# ifdef _STD_THREAD_
std : : thread * t ;
# else
2011-02-19 03:36:30 +00:00
pthread_attr_t m_thread_attr ;
pthread_t m_thread ;
2014-11-18 13:40:29 +00:00
# endif
2011-02-19 03:36:30 +00:00
static void * StaticThreadProc ( void * param ) ;
2010-04-24 21:37:39 +00:00
protected :
void CreateThread ( ) ;
void CloseThread ( ) ;
public :
GSThread ( ) ;
virtual ~ GSThread ( ) ;
} ;
2011-02-19 03:36:30 +00:00
2012-02-08 16:57:14 +00:00
class GSCritSec : public IGSLock
2011-02-19 03:36:30 +00:00
{
2014-11-18 13:40:29 +00:00
# ifdef _STD_THREAD_
recursive_mutex * mutex_critsec ;
# else
2011-02-19 03:36:30 +00:00
pthread_mutexattr_t m_mutex_attr ;
pthread_mutex_t m_mutex ;
2014-11-18 13:40:29 +00:00
# endif
2011-02-19 03:36:30 +00:00
public :
2012-02-08 16:57:14 +00:00
GSCritSec ( bool recursive = true )
2011-02-19 03:36:30 +00:00
{
2014-11-18 13:40:29 +00:00
# ifdef _STD_THREAD_
mutex_critsec = new recursive_mutex ( ) ;
# else
2011-02-19 03:36:30 +00:00
pthread_mutexattr_init ( & m_mutex_attr ) ;
2012-02-08 16:57:14 +00:00
pthread_mutexattr_settype ( & m_mutex_attr , recursive ? PTHREAD_MUTEX_RECURSIVE : PTHREAD_MUTEX_NORMAL ) ;
2011-02-19 03:36:30 +00:00
pthread_mutex_init ( & m_mutex , & m_mutex_attr ) ;
2014-11-18 13:40:29 +00:00
# endif
2011-02-19 03:36:30 +00:00
}
~ GSCritSec ( )
{
2014-11-18 13:40:29 +00:00
# ifdef _STD_THREAD_
delete ( mutex_critsec ) ;
# else
2011-02-19 03:36:30 +00:00
pthread_mutex_destroy ( & m_mutex ) ;
pthread_mutexattr_destroy ( & m_mutex_attr ) ;
2014-11-18 13:40:29 +00:00
# endif
}
# ifdef _STD_THREAD_
void Lock ( )
{
mutex_critsec - > lock ( ) ;
}
bool TryLock ( )
{
return mutex_critsec - > try_lock ( ) ;
2011-02-19 03:36:30 +00:00
}
2014-11-18 13:40:29 +00:00
void Unlock ( )
{
mutex_critsec - > unlock ( ) ;
}
recursive_mutex & GetMutex ( ) { return ref ( * mutex_critsec ) ; }
# else
2011-02-19 03:36:30 +00:00
void Lock ( ) { pthread_mutex_lock ( & m_mutex ) ; }
bool TryLock ( ) { return pthread_mutex_trylock ( & m_mutex ) = = 0 ; }
void Unlock ( ) { pthread_mutex_unlock ( & m_mutex ) ; }
2012-02-10 21:18:47 +00:00
operator pthread_mutex_t * ( ) { return & m_mutex ; }
2014-11-18 13:40:29 +00:00
# endif
2011-02-19 03:36:30 +00:00
} ;
2014-11-18 13:40:29 +00:00
# ifndef _STD_THREAD_
2012-02-08 16:57:14 +00:00
class GSEvent : public IGSEvent
2011-02-19 03:36:30 +00:00
{
protected :
2011-02-19 10:27:10 +00:00
sem_t m_sem ;
2011-02-19 03:36:30 +00:00
public :
2011-12-20 14:33:28 +00:00
GSEvent ( ) { sem_init ( & m_sem , 0 , 0 ) ; }
~ GSEvent ( ) { sem_destroy ( & m_sem ) ; }
2011-02-19 03:36:30 +00:00
2011-02-19 10:27:10 +00:00
void Set ( ) { sem_post ( & m_sem ) ; }
2012-02-08 16:57:14 +00:00
bool Wait ( IGSLock * l ) { if ( l ) l - > Unlock ( ) ; bool b = sem_wait ( & m_sem ) = = 0 ; if ( l ) l - > Lock ( ) ; return b ; }
2011-02-19 03:36:30 +00:00
} ;
2014-11-18 13:40:29 +00:00
# endif
2012-02-08 16:57:14 +00:00
class GSCondVarLock : public GSCritSec
2011-12-27 09:15:35 +00:00
{
public :
2012-02-08 16:57:14 +00:00
GSCondVarLock ( ) : GSCritSec ( false )
2011-12-27 13:14:30 +00:00
{
}
2011-12-27 09:15:35 +00:00
} ;
2012-02-08 16:57:14 +00:00
class GSCondVar : public IGSEvent
2011-12-27 09:15:35 +00:00
{
2014-11-18 13:40:29 +00:00
# ifdef _STD_THREAD_
condition_variable_any * cond_var ;
# else
pthread_cond_t m_cv ;
2011-12-27 13:14:30 +00:00
pthread_condattr_t m_cv_attr ;
2014-11-18 13:40:29 +00:00
# endif
2011-12-27 09:15:35 +00:00
public :
2011-12-27 13:14:30 +00:00
GSCondVar ( )
{
2014-11-18 13:40:29 +00:00
# ifdef _STD_THREAD_
cond_var = new condition_variable_any ( ) ;
# else
2011-12-27 13:14:30 +00:00
pthread_condattr_init ( & m_cv_attr ) ;
pthread_cond_init ( & m_cv , & m_cv_attr ) ;
2014-11-18 13:40:29 +00:00
# endif
2011-12-27 13:14:30 +00:00
}
2012-02-08 16:57:14 +00:00
2011-12-27 13:14:30 +00:00
virtual ~ GSCondVar ( )
{
2014-11-18 13:40:29 +00:00
# ifdef _STD_THREAD_
delete ( cond_var ) ;
# else
2011-12-27 13:14:30 +00:00
pthread_condattr_destroy ( & m_cv_attr ) ;
pthread_cond_destroy ( & m_cv ) ;
2014-11-18 13:40:29 +00:00
# endif
}
# ifdef _STD_THREAD_
void Set ( )
{
cond_var - > notify_one ( ) ;
}
bool Wait ( IGSLock * l )
{
cond_var - > wait ( ( ( ( GSCondVarLock * ) l ) - > GetMutex ( ) ) ) ; // Predicate is not useful, it is implicit in the loop
return 1 ; // Anyway this value is not used(and no way to get it from std::thread)
}
2011-12-27 09:15:35 +00:00
2014-11-18 13:40:29 +00:00
operator condition_variable_any * ( ) { return cond_var ; }
# else
void Set ( ) { pthread_cond_signal ( & m_cv ) ; }
2014-04-18 21:21:27 +00:00
bool Wait ( IGSLock * l ) { return pthread_cond_wait ( & m_cv , * ( GSCondVarLock * ) l ) = = 0 ; }
2011-12-27 09:15:35 +00:00
operator pthread_cond_t * ( ) { return & m_cv ; }
2014-11-18 13:40:29 +00:00
# endif
2011-12-27 09:15:35 +00:00
} ;
2011-02-19 03:36:30 +00:00
# endif
class GSAutoLock
{
2012-02-08 16:57:14 +00:00
IGSLock * m_lock ;
2011-02-19 03:36:30 +00:00
public :
2012-02-08 16:57:14 +00:00
GSAutoLock ( IGSLock * l ) { ( m_lock = l ) - > Lock ( ) ; }
~ GSAutoLock ( ) { m_lock - > Unlock ( ) ; }
2011-12-20 14:33:28 +00:00
} ;
2011-12-22 14:36:54 +00:00
template < class T > class GSJobQueue : private GSThread
{
protected :
queue < T > m_queue ;
2012-01-18 11:47:31 +00:00
volatile long m_count ; // NOTE: it is the safest to have our own counter because m_queue.pop() might decrement its own before the last item runs out of its scope and gets destroyed (implementation dependent)
2011-12-22 14:36:54 +00:00
volatile bool m_exit ;
2012-02-08 16:57:14 +00:00
IGSEvent * m_notempty ;
IGSEvent * m_empty ;
IGSLock * m_lock ;
2011-12-22 14:36:54 +00:00
void ThreadProc ( )
{
2012-02-08 16:57:14 +00:00
m_lock - > Lock ( ) ;
2011-12-22 14:36:54 +00:00
2012-02-08 16:57:14 +00:00
while ( true )
2011-12-22 14:36:54 +00:00
{
2012-02-08 16:57:14 +00:00
while ( m_queue . empty ( ) )
2011-12-22 14:36:54 +00:00
{
2012-02-08 16:57:14 +00:00
m_notempty - > Wait ( m_lock ) ;
2011-12-24 15:02:48 +00:00
2012-02-08 16:57:14 +00:00
if ( m_exit ) { m_lock - > Unlock ( ) ; return ; }
}
2011-12-22 14:36:54 +00:00
2012-02-08 16:57:14 +00:00
T & item = m_queue . front ( ) ;
2011-12-22 14:36:54 +00:00
2012-02-08 16:57:14 +00:00
m_lock - > Unlock ( ) ;
2011-12-22 14:36:54 +00:00
2012-02-08 16:57:14 +00:00
Process ( item ) ;
2011-12-22 14:36:54 +00:00
2012-02-08 16:57:14 +00:00
m_lock - > Lock ( ) ;
2011-12-22 14:36:54 +00:00
2012-02-08 16:57:14 +00:00
m_queue . pop ( ) ;
2011-12-24 15:02:48 +00:00
2012-02-08 16:57:14 +00:00
if ( - - m_count = = 0 )
{
m_empty - > Set ( ) ;
2011-12-22 14:36:54 +00:00
}
}
}
public :
GSJobQueue ( )
: m_count ( 0 )
, m_exit ( false )
{
2012-02-08 16:57:14 +00:00
bool condvar = ! ! theApp . GetConfig ( " condvar " , 1 ) ;
2011-12-24 15:02:48 +00:00
2011-12-23 02:49:27 +00:00
# ifdef _WINDOWS
2012-01-18 11:47:31 +00:00
if ( pInitializeConditionVariable = = NULL )
{
2012-02-08 16:57:14 +00:00
condvar = false ;
2012-01-18 11:47:31 +00:00
}
2011-12-27 09:15:35 +00:00
2011-12-22 14:36:54 +00:00
# endif
2014-11-18 13:40:29 +00:00
# ifndef _STD_THREAD_
2012-02-08 16:57:14 +00:00
if ( condvar )
2014-11-18 13:40:29 +00:00
# endif
2012-02-08 16:57:14 +00:00
{
m_notempty = new GSCondVar ( ) ;
m_empty = new GSCondVar ( ) ;
m_lock = new GSCondVarLock ( ) ;
}
2014-11-18 13:40:29 +00:00
# ifndef _STD_THREAD_
2012-02-08 16:57:14 +00:00
else
{
m_notempty = new GSEvent ( ) ;
m_empty = new GSEvent ( ) ;
m_lock = new GSCritSec ( ) ;
}
2014-11-18 13:40:29 +00:00
# endif
2012-02-08 16:57:14 +00:00
2011-12-22 14:36:54 +00:00
CreateThread ( ) ;
}
virtual ~ GSJobQueue ( )
{
m_exit = true ;
2012-02-08 16:57:14 +00:00
m_notempty - > Set ( ) ;
CloseThread ( ) ;
delete m_notempty ;
delete m_empty ;
delete m_lock ;
2011-12-22 14:36:54 +00:00
}
2012-01-18 11:47:31 +00:00
bool IsEmpty ( ) const
2011-12-22 14:36:54 +00:00
{
2012-01-18 11:47:31 +00:00
ASSERT ( m_count > = 0 ) ;
return m_count = = 0 ;
2011-12-22 14:36:54 +00:00
}
2012-01-18 11:47:31 +00:00
void Push ( const T & item )
2011-12-22 14:36:54 +00:00
{
2012-02-08 16:57:14 +00:00
m_lock - > Lock ( ) ;
2011-12-27 09:15:35 +00:00
2012-02-08 16:57:14 +00:00
m_queue . push ( item ) ;
2011-12-26 22:30:59 +00:00
2012-02-08 16:57:14 +00:00
if ( m_count + + = = 0 )
2011-12-22 14:36:54 +00:00
{
2012-02-08 16:57:14 +00:00
m_notempty - > Set ( ) ;
2011-12-22 14:36:54 +00:00
}
2012-02-08 16:57:14 +00:00
m_lock - > Unlock ( ) ;
2011-12-22 14:36:54 +00:00
}
2012-01-18 11:47:31 +00:00
void Wait ( )
2011-12-22 14:36:54 +00:00
{
2012-02-08 16:57:14 +00:00
if ( m_count > 0 )
2011-12-22 14:36:54 +00:00
{
2012-02-08 16:57:14 +00:00
m_lock - > Lock ( ) ;
2011-12-22 14:36:54 +00:00
2012-02-08 16:57:14 +00:00
while ( m_count ! = 0 )
{
m_empty - > Wait ( m_lock ) ;
}
2012-01-18 11:47:31 +00:00
2012-02-08 16:57:14 +00:00
ASSERT ( m_queue . empty ( ) ) ;
2012-01-18 11:47:31 +00:00
2012-02-08 16:57:14 +00:00
m_lock - > Unlock ( ) ;
2011-12-22 14:36:54 +00:00
}
}
virtual void Process ( T & item ) = 0 ;
} ;
2013-06-17 04:11:10 +00:00
// http://software.intel.com/en-us/blogs/2012/11/06/exploring-intel-transactional-synchronization-extensions-with-intel-software
class TransactionScope
{
public :
class Lock
{
volatile long state ;
public :
Lock ( )
: state ( 0 )
{
}
void lock ( )
{
while ( _InterlockedCompareExchange ( & state , 1 , 0 ) ! = 0 )
{
do { _mm_pause ( ) ; } while ( state = = 1 ) ;
}
}
void unlock ( )
{
_InterlockedExchange ( & state , 0 ) ;
}
bool isLocked ( ) const
{
return state = = 1 ;
}
} ;
private :
Lock & fallBackLock ;
TransactionScope ( ) ;
public :
TransactionScope ( Lock & fallBackLock_ , int max_retries = 3 )
: fallBackLock ( fallBackLock_ )
{
# if _M_SSE >= 0x501
int nretries = 0 ;
while ( 1 )
{
+ + nretries ;
unsigned status = _xbegin ( ) ;
if ( status = = _XBEGIN_STARTED )
{
if ( ! fallBackLock . isLocked ( ) ) return ;
_xabort ( 0xff ) ;
}
if ( ( status & _XABORT_EXPLICIT ) & & _XABORT_CODE ( status ) = = 0xff & & ! ( status & _XABORT_NESTED ) )
{
while ( fallBackLock . isLocked ( ) ) _mm_pause ( ) ;
}
else if ( ! ( status & _XABORT_RETRY ) )
{
break ;
}
if ( nretries > = max_retries )
{
break ;
}
}
# endif
fallBackLock . lock ( ) ;
}
~ TransactionScope ( )
{
if ( fallBackLock . isLocked ( ) )
{
fallBackLock . unlock ( ) ;
}
# if _M_SSE >= 0x501
else
{
_xend ( ) ;
}
# endif
}
} ;