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
2010-04-25 00:31:27 +00:00
* the Free Software Foundation , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
2010-04-24 21:37:39 +00:00
* http : //www.gnu.org/copyleft/gpl.html
*
*/
# pragma once
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 ) ;
typedef void ( WINAPI * SleepConditionVariableSRWPtr ) ( CONDITION_VARIABLE * ConditionVariable , SRWLOCK * SRWLock , DWORD dwMilliseconds , ULONG Flags ) ;
typedef void ( WINAPI * InitializeSRWLockPtr ) ( SRWLOCK * SRWLock ) ;
typedef void ( WINAPI * AcquireSRWLockExclusivePtr ) ( SRWLOCK * SRWLock ) ;
typedef void ( WINAPI * ReleaseSRWLockExclusivePtr ) ( SRWLOCK * SRWLock ) ;
extern InitializeConditionVariablePtr pInitializeConditionVariable ;
extern WakeConditionVariablePtr pWakeConditionVariable ;
extern WakeAllConditionVariablePtr pWakeAllConditionVariable ;
extern SleepConditionVariableSRWPtr pSleepConditionVariableSRW ;
extern InitializeSRWLockPtr pInitializeSRWLock ; ;
extern AcquireSRWLockExclusivePtr pAcquireSRWLockExclusive ;
extern ReleaseSRWLockExclusivePtr pReleaseSRWLockExclusive ;
2010-04-24 21:37:39 +00:00
class GSThread
{
DWORD m_ThreadId ;
HANDLE m_hThread ;
2011-02-19 03:36:30 +00:00
static DWORD WINAPI StaticThreadProc ( void * lpParam ) ;
protected :
virtual void ThreadProc ( ) = 0 ;
void CreateThread ( ) ;
void CloseThread ( ) ;
public :
GSThread ( ) ;
virtual ~ GSThread ( ) ;
} ;
class GSCritSec
{
CRITICAL_SECTION m_cs ;
public :
GSCritSec ( ) { InitializeCriticalSection ( & m_cs ) ; }
~ GSCritSec ( ) { DeleteCriticalSection ( & m_cs ) ; }
void Lock ( ) { EnterCriticalSection ( & m_cs ) ; }
bool TryLock ( ) { return TryEnterCriticalSection ( & m_cs ) = = TRUE ; }
void Unlock ( ) { LeaveCriticalSection ( & m_cs ) ; }
} ;
2011-12-20 14:33:28 +00:00
class GSEvent
2011-02-19 03:36:30 +00:00
{
protected :
HANDLE m_hEvent ;
public :
2011-12-20 14:33:28 +00:00
GSEvent ( bool manual = false , bool initial = false ) { m_hEvent = CreateEvent ( NULL , manual , initial , NULL ) ; }
~ GSEvent ( ) { CloseHandle ( m_hEvent ) ; }
2011-02-19 03:36:30 +00:00
void Set ( ) { SetEvent ( m_hEvent ) ; }
2011-12-20 14:33:28 +00:00
void Reset ( ) { ResetEvent ( m_hEvent ) ; }
2011-02-19 03:36:30 +00:00
bool Wait ( ) { return WaitForSingleObject ( m_hEvent , INFINITE ) = = WAIT_OBJECT_0 ; }
} ;
2011-03-27 03:12:12 +00:00
2011-12-27 09:15:35 +00:00
class GSCondVarLock
{
SRWLOCK m_lock ;
public :
GSCondVarLock ( ) { pInitializeSRWLock ( & m_lock ) ; }
void Lock ( ) { pAcquireSRWLockExclusive ( & m_lock ) ; }
void Unlock ( ) { pReleaseSRWLockExclusive ( & m_lock ) ; }
operator SRWLOCK * ( ) { return & m_lock ; }
} ;
class GSCondVar
{
CONDITION_VARIABLE m_cv ;
public :
GSCondVar ( ) { pInitializeConditionVariable ( & m_cv ) ; }
void Set ( ) { pWakeConditionVariable ( & m_cv ) ; }
void Wait ( GSCondVarLock & lock ) { pSleepConditionVariableSRW ( & m_cv , lock , INFINITE , 0 ) ; }
operator CONDITION_VARIABLE * ( ) { return & m_cv ; }
} ;
2011-02-19 03:36:30 +00:00
# else
# include <pthread.h>
2011-02-19 10:27:10 +00:00
# include <semaphore.h>
2011-12-27 13:14:30 +00:00
# include "GSdx.h"
2011-02-19 03:36:30 +00:00
class GSThread
{
pthread_attr_t m_thread_attr ;
pthread_t m_thread ;
static void * StaticThreadProc ( void * param ) ;
2010-04-24 21:37:39 +00:00
protected :
virtual void ThreadProc ( ) = 0 ;
void CreateThread ( ) ;
void CloseThread ( ) ;
public :
GSThread ( ) ;
virtual ~ GSThread ( ) ;
} ;
2011-02-19 03:36:30 +00:00
class GSCritSec
{
pthread_mutexattr_t m_mutex_attr ;
pthread_mutex_t m_mutex ;
public :
GSCritSec ( )
{
pthread_mutexattr_init ( & m_mutex_attr ) ;
2011-12-27 13:14:30 +00:00
pthread_mutexattr_settype ( & m_mutex_attr , PTHREAD_MUTEX_RECURSIVE ) ;
2011-02-19 03:36:30 +00:00
pthread_mutex_init ( & m_mutex , & m_mutex_attr ) ;
}
~ GSCritSec ( )
{
pthread_mutex_destroy ( & m_mutex ) ;
pthread_mutexattr_destroy ( & m_mutex_attr ) ;
}
void Lock ( ) { pthread_mutex_lock ( & m_mutex ) ; }
bool TryLock ( ) { return pthread_mutex_trylock ( & m_mutex ) = = 0 ; }
void Unlock ( ) { pthread_mutex_unlock ( & m_mutex ) ; }
} ;
2011-12-20 14:33:28 +00:00
class GSEvent
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 ) ; }
bool Wait ( ) { return sem_wait ( & m_sem ) = = 0 ; }
2011-02-19 03:36:30 +00:00
} ;
2011-12-27 13:14:30 +00:00
// Note except the mutex attribute the code is same as GSCritSec object
2011-12-27 09:15:35 +00:00
class GSCondVarLock
{
2011-12-27 13:14:30 +00:00
pthread_mutexattr_t m_mutex_attr ;
pthread_mutex_t m_mutex ;
2011-12-27 09:15:35 +00:00
public :
2011-12-27 13:14:30 +00:00
GSCondVarLock ( )
{
pthread_mutexattr_init ( & m_mutex_attr ) ;
pthread_mutexattr_settype ( & m_mutex_attr , PTHREAD_MUTEX_NORMAL ) ;
pthread_mutex_init ( & m_mutex , & m_mutex_attr ) ;
}
virtual ~ GSCondVarLock ( )
{
pthread_mutex_destroy ( & m_mutex ) ;
pthread_mutexattr_destroy ( & m_mutex_attr ) ;
}
2011-12-27 09:15:35 +00:00
2011-12-27 13:14:30 +00:00
void Lock ( ) { pthread_mutex_lock ( & m_mutex ) ; }
void Unlock ( ) { pthread_mutex_unlock ( & m_mutex ) ; }
2011-12-27 09:15:35 +00:00
2011-12-27 13:14:30 +00:00
operator pthread_mutex_t * ( ) { return & m_mutex ; }
2011-12-27 09:15:35 +00:00
} ;
class GSCondVar
{
pthread_cond_t m_cv ;
2011-12-27 13:14:30 +00:00
pthread_condattr_t m_cv_attr ;
2011-12-27 09:15:35 +00:00
public :
2011-12-27 13:14:30 +00:00
GSCondVar ( )
{
pthread_condattr_init ( & m_cv_attr ) ;
pthread_cond_init ( & m_cv , & m_cv_attr ) ;
}
virtual ~ GSCondVar ( )
{
pthread_condattr_destroy ( & m_cv_attr ) ;
pthread_cond_destroy ( & m_cv ) ;
}
2011-12-27 09:15:35 +00:00
void Set ( ) { pthread_cond_signal ( & m_cv ) ; }
void Wait ( GSCondVarLock & lock ) { pthread_cond_wait ( & m_cv , lock ) ; }
operator pthread_cond_t * ( ) { return & m_cv ; }
} ;
2011-02-19 03:36:30 +00:00
# endif
class GSAutoLock
{
protected :
GSCritSec * m_cs ;
public :
GSAutoLock ( GSCritSec * cs ) { m_cs = cs ; m_cs - > Lock ( ) ; }
~ GSAutoLock ( ) { m_cs - > Unlock ( ) ; }
} ;
2011-12-20 14:33:28 +00:00
class GSEventSpin
{
protected :
volatile long m_sync ;
volatile bool m_manual ;
public :
GSEventSpin ( bool manual = false , bool initial = false ) { m_sync = initial ? 1 : 0 ; m_manual = manual ; }
~ GSEventSpin ( ) { }
void Set ( ) { _interlockedbittestandset ( & m_sync , 0 ) ; }
void Reset ( ) { _interlockedbittestandreset ( & m_sync , 0 ) ; }
bool Wait ( )
{
if ( m_manual ) while ( ! m_sync ) _mm_pause ( ) ;
else while ( ! _interlockedbittestandreset ( & m_sync , 0 ) ) _mm_pause ( ) ;
return true ;
}
} ;
2011-12-22 14:36:54 +00:00
template < class T > class GSJobQueue : private GSThread
{
protected :
int m_count ;
queue < T > m_queue ;
volatile bool m_exit ;
2011-12-24 15:02:48 +00:00
struct { GSCritSec lock ; GSEvent notempty ; volatile long count ; } m_ev ;
2011-12-27 09:15:35 +00:00
struct { GSCondVar notempty , empty ; GSCondVarLock lock ; bool available ; } m_cv ;
2011-12-22 14:36:54 +00:00
void ThreadProc ( )
{
if ( m_cv . available )
{
2011-12-27 09:15:35 +00:00
m_cv . lock . Lock ( ) ;
2011-12-22 14:36:54 +00:00
while ( true )
{
while ( m_queue . empty ( ) )
{
2011-12-27 09:15:35 +00:00
m_cv . notempty . Wait ( m_cv . lock ) ;
2011-12-22 14:36:54 +00:00
2011-12-27 09:15:35 +00:00
if ( m_exit ) { m_cv . lock . Unlock ( ) ; return ; }
2011-12-22 14:36:54 +00:00
}
2012-01-13 18:10:05 +00:00
T & item = m_queue . front ( ) ;
2011-12-22 14:36:54 +00:00
2012-01-13 18:10:05 +00:00
m_cv . lock . Unlock ( ) ;
2011-12-22 14:36:54 +00:00
2012-01-13 18:10:05 +00:00
Process ( item ) ;
2011-12-22 14:36:54 +00:00
2012-01-13 18:10:05 +00:00
m_cv . lock . Lock ( ) ;
2011-12-22 14:36:54 +00:00
2012-01-13 18:10:05 +00:00
m_queue . pop ( ) ;
2011-12-22 14:36:54 +00:00
if ( m_queue . empty ( ) )
{
2011-12-27 09:15:35 +00:00
m_cv . empty . Set ( ) ;
2011-12-22 14:36:54 +00:00
}
}
}
else
{
2011-12-24 15:02:48 +00:00
m_ev . lock . Lock ( ) ;
while ( true )
2011-12-22 14:36:54 +00:00
{
2011-12-24 15:02:48 +00:00
while ( m_queue . empty ( ) )
{
m_ev . lock . Unlock ( ) ;
m_ev . notempty . Wait ( ) ;
if ( m_exit ) { return ; }
m_ev . lock . Lock ( ) ;
}
2011-12-22 14:36:54 +00:00
2012-01-13 18:10:05 +00:00
T & item = m_queue . front ( ) ;
2011-12-22 14:36:54 +00:00
2012-01-13 18:10:05 +00:00
m_ev . lock . Unlock ( ) ;
2011-12-22 14:36:54 +00:00
2012-01-13 18:10:05 +00:00
Process ( item ) ;
2011-12-22 14:36:54 +00:00
2012-01-13 18:10:05 +00:00
m_ev . lock . Lock ( ) ;
2011-12-22 14:36:54 +00:00
2012-01-13 18:10:05 +00:00
m_queue . pop ( ) ;
2011-12-24 15:02:48 +00:00
_InterlockedDecrement ( & m_ev . count ) ;
2011-12-22 14:36:54 +00:00
}
}
}
public :
GSJobQueue ( )
: m_count ( 0 )
, m_exit ( false )
{
2011-12-24 15:02:48 +00:00
m_ev . count = 0 ;
2011-12-23 02:49:27 +00:00
# ifdef _WINDOWS
2011-12-27 09:15:35 +00:00
m_cv . available = pInitializeConditionVariable ! = NULL ;
2011-12-22 14:36:54 +00:00
2011-12-26 22:30:59 +00:00
# elif defined(_LINUX)
2011-12-27 09:15:35 +00:00
2011-12-27 13:14:30 +00:00
//m_cv.available = true;
m_cv . available = ! ! theApp . GetConfig ( " condvar " , 1 ) ;
2011-12-27 09:15:35 +00:00
2011-12-22 14:36:54 +00:00
# endif
CreateThread ( ) ;
}
virtual ~ GSJobQueue ( )
{
m_exit = true ;
if ( m_cv . available )
{
2011-12-27 09:15:35 +00:00
m_cv . notempty . Set ( ) ;
2011-12-22 14:36:54 +00:00
}
else
{
m_ev . notempty . Set ( ) ;
}
}
int GetCount ( ) const
{
return m_count ;
}
virtual void Push ( const T & item )
{
if ( m_cv . available )
{
2011-12-27 09:15:35 +00:00
m_cv . lock . Lock ( ) ;
2011-12-26 22:30:59 +00:00
m_queue . push ( item ) ;
2011-12-27 09:15:35 +00:00
m_cv . lock . Unlock ( ) ;
2011-12-26 22:30:59 +00:00
2011-12-27 09:15:35 +00:00
m_cv . notempty . Set ( ) ;
2011-12-22 14:36:54 +00:00
}
else
{
GSAutoLock l ( & m_ev . lock ) ;
m_queue . push ( item ) ;
2011-12-24 15:02:48 +00:00
_InterlockedIncrement ( & m_ev . count ) ;
2011-12-22 14:36:54 +00:00
m_ev . notempty . Set ( ) ;
}
m_count + + ;
}
virtual void Wait ( )
{
if ( m_cv . available )
{
2011-12-27 09:15:35 +00:00
m_cv . lock . Lock ( ) ;
2011-12-22 14:36:54 +00:00
while ( ! m_queue . empty ( ) )
{
2011-12-27 09:15:35 +00:00
m_cv . empty . Wait ( m_cv . lock ) ;
2011-12-22 14:36:54 +00:00
}
2011-12-27 09:15:35 +00:00
m_cv . lock . Unlock ( ) ;
2011-12-22 14:36:54 +00:00
}
else
{
2011-12-24 15:02:48 +00:00
// 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
2011-12-24 15:02:48 +00:00
while ( m_ev . count > 0 ) _mm_pause ( ) ;
2011-12-22 14:36:54 +00:00
}
m_count + + ;
}
virtual void Process ( T & item ) = 0 ;
} ;