diff --git a/CMakeLists.txt b/CMakeLists.txt index b179974..6ae33ad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +CMAKE_MINIMUM_REQUIRED(VERSION 2.8 FATAL_ERROR) PROJECT(TexC) ADD_SUBDIRECTORY(BPTCEncoder) diff --git a/Core/CMakeLists.txt b/Core/CMakeLists.txt index 27d9dac..7bc7c40 100644 --- a/Core/CMakeLists.txt +++ b/Core/CMakeLists.txt @@ -34,19 +34,44 @@ INCLUDE_DIRECTORIES( ${TexC_BINARY_DIR}/IO/include ) INCLUDE_DIRECTORIES( ${TexC_SOURCE_DIR}/Core/include ) -SET( THREAD_API "None" ) +SET( THREAD_API "None" CACHE STRING "API used to implement threading operations") +SET( THREAD_APIS_AVAILABLE "None" ) + FIND_PACKAGE( Boost COMPONENTS thread system ) IF( Boost_FOUND ) + + SET( THREAD_APIS_AVAILABLE ${THREAD_APIS_AVAILABLE} "Boost" ) + IF( THREAD_API MATCHES "None" ) + SET( THREAD_API "Boost" ) + ENDIF() + +ENDIF() + +FIND_PACKAGE( Threads ) +IF( CMAKE_USE_PTHREADS_INIT ) + + SET( THREAD_APIS_AVAILABLE ${THREAD_APIS_AVAILABLE} "PThread" ) + IF( THREAD_API MATCHES "None" ) + SET( THREAD_API "Boost" ) + ENDIF() + +ENDIF() + +SET_PROPERTY( CACHE THREAD_API PROPERTY STRINGS ${THREAD_APIS_AVAILABLE} ) + +IF( THREAD_API MATCHES "Boost") INCLUDE_DIRECTORIES( ${Boost_INCLUDE_DIR} ) - - SET( THREAD_API "Boost" ) SET( SOURCES ${SOURCES} "src/ThreadBoost.cpp" ) - LINK_DIRECTORIES( ${Boost_LIBRARY_DIR} ) ENDIF() -IF( NOT THREAD_API MATCHES "None") +IF( THREAD_API MATCHES "PThread" ) + SET( SOURCES ${SOURCES} "src/ThreadPThread.cpp" ) +ENDIF() +IF( THREAD_API MATCHES "None") + MESSAGE( FATAL_ERROR "Could not find suitable threading library." ) +ELSE() SET( SOURCES ${SOURCES} "src/Thread.cpp" ) SET( SOURCES ${SOURCES} "src/ThreadGroup.cpp" ) SET( SOURCES ${SOURCES} "src/WorkerQueue.cpp" ) @@ -54,8 +79,6 @@ IF( NOT THREAD_API MATCHES "None") SET( HEADERS ${HEADERS} "src/Thread.h" ) SET( HEADERS ${HEADERS} "src/ThreadGroup.h" ) SET( HEADERS ${HEADERS} "src/WorkerQueue.h" ) -ELSE() - MESSAGE( FATAL_ERROR "Could not find suitable threading library." ) ENDIF() ADD_LIBRARY( TexCompCore @@ -66,10 +89,14 @@ ADD_LIBRARY( TexCompCore TARGET_LINK_LIBRARIES( TexCompCore TexCompIO ) TARGET_LINK_LIBRARIES( TexCompCore BPTCEncoder ) -IF( Boost_FOUND ) +IF( THREAD_API MATCHES "Boost" ) TARGET_LINK_LIBRARIES( TexCompCore ${Boost_LIBRARIES} ) ENDIF() +IF( THREAD_API MATCHES "PThread" ) + TARGET_LINK_LIBRARIES( TexCompCore ${CMAKE_THREAD_LIBS_INIT} ) +ENDIF() + IF( NOT WIN32 AND NOT APPLE ) TARGET_LINK_LIBRARIES( TexCompCore rt ) ENDIF() diff --git a/Core/src/ThreadPThread.cpp b/Core/src/ThreadPThread.cpp new file mode 100644 index 0000000..1569922 --- /dev/null +++ b/Core/src/ThreadPThread.cpp @@ -0,0 +1,249 @@ +#include "Thread.h" + +#include + +#include +#include +#include +#include +#include + +static void ReportErrorAndExit(int err, const char *msg) { + char errMsg[1024]; + sprintf(errMsg, "Thread error -- %s: ", msg); + + errno = err; + perror(errMsg); + exit(1); +} + +//////////////////////////////////////////////////////////////////////////////// +// +// Thread Implementation +// +//////////////////////////////////////////////////////////////////////////////// + +class TCThreadImpl : public TCThreadBaseImpl { +private: + + static void *RunThread(void *arg) { + TCThreadImpl *impl = (TCThreadImpl *)arg; + + impl->m_Callable(); + + return NULL; + } + + pthread_t m_ThreadID; + TCCallable &m_Callable; + +public: + TCThreadImpl(TCCallable &callable) : + m_Callable(callable) + { + int result = pthread_create(&m_ThreadID, NULL, RunThread, (void *)this); + if(result != 0) { + ReportErrorAndExit(result, "pthread_create"); + } + } + virtual ~TCThreadImpl() { } + + void Join() { + void *status; + int result = pthread_join(m_ThreadID, &status); + if(result != 0) { + ReportErrorAndExit(result, "pthread_join"); + } + } +}; + +class TCThreadImplFactory : public TCThreadBaseImplFactory { + TCCallable &m_Callable; +public: + TCThreadImplFactory(TCCallable &callable) : m_Callable(callable) { } + virtual ~TCThreadImplFactory() { } + virtual TCThreadBaseImpl *CreateImpl() const { + return new TCThreadImpl(m_Callable); + } +}; + +TCThread::TCThread(TCCallable &callable) + : TCThreadBase(TCThreadImplFactory(callable)) +{ } + +void TCThread::Join() { + CheckReferenceCount(); + ((TCThreadImpl *)m_Impl)->Join(); +} + +void TCThread::Yield() { + int result = pthread_yield(); + if(result != 0) { + ReportErrorAndExit(result, "pthread_yield"); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// +// Mutex Implementation +// +//////////////////////////////////////////////////////////////////////////////// + +class TCMutexImpl : public TCThreadBaseImpl { +private: + pthread_mutex_t m_Mutex; + +public: + pthread_mutex_t *GetMutex() { return &m_Mutex; } + TCMutexImpl() : TCThreadBaseImpl() { + int result = pthread_mutex_init( &m_Mutex, NULL ); + if(result != 0) { + ReportErrorAndExit(result, "pthread_mutex_init"); + } + } + + virtual ~TCMutexImpl() { + int result = pthread_mutex_destroy( &m_Mutex ); + if(result != 0) { + ReportErrorAndExit(result, "pthread_mutex_destroy"); + } + } + +}; + +class TCMutexImplFactory : public TCThreadBaseImplFactory { +public: + TCMutexImplFactory() { } + virtual ~TCMutexImplFactory() { } + virtual TCThreadBaseImpl *CreateImpl() const { + return new TCMutexImpl(); + } +}; + +TCMutex::TCMutex() : TCThreadBase(TCMutexImplFactory()) +{ } + +//////////////////////////////////////////////////////////////////////////////// +// +// Lock Implementation +// +//////////////////////////////////////////////////////////////////////////////// + +class TCLockImpl : public TCThreadBaseImpl { +private: + pthread_mutex_t *const m_MutexPtr; +public: + TCLockImpl(TCMutex &mutex) + : m_MutexPtr(((TCMutexImpl *)(mutex.m_Impl))->GetMutex()) + { + int result = pthread_mutex_lock( m_MutexPtr ); + if(result != 0) { + ReportErrorAndExit(result, "pthread_mutex_lock"); + } + } + + virtual ~TCLockImpl() { + int result = pthread_mutex_unlock( m_MutexPtr ); + if(result != 0) { + ReportErrorAndExit(result, "pthread_mutex_unlock"); + } + } + + pthread_mutex_t *GetMutexPtr() const { return m_MutexPtr; } +}; + +class TCLockImplFactory : public TCThreadBaseImplFactory { +private: + TCMutex &m_Mutex; +public: + TCLockImplFactory(TCMutex &mutex) : m_Mutex(mutex){ } + virtual ~TCLockImplFactory() { } + virtual TCThreadBaseImpl *CreateImpl() const { + return new TCLockImpl(m_Mutex); + } +}; + +TCLock::TCLock(TCMutex &mutex) : TCThreadBase(TCLockImplFactory(mutex)) +{ } + +//////////////////////////////////////////////////////////////////////////////// +// +// Condition Variable Implementation +// +//////////////////////////////////////////////////////////////////////////////// + +class TCConditionVariableImpl : public TCThreadBaseImpl { +private: + pthread_cond_t m_CV; +public: + TCConditionVariableImpl() { + int result = pthread_cond_init( &m_CV, NULL ); + if(result != 0) { + ReportErrorAndExit(result, "pthread_cond_init"); + } + } + + virtual ~TCConditionVariableImpl() { + int result = pthread_cond_destroy( &m_CV ); + if(result != 0) { + ReportErrorAndExit(result, "pthread_cond_destroy"); + } + } + + void Wait(TCLock &lock) { + TCLockImpl *lockImpl = (TCLockImpl *)(lock.m_Impl); + + int result = pthread_cond_wait( &m_CV, lockImpl->GetMutexPtr() ); + if(result != 0) { + ReportErrorAndExit( result, "pthread_cond_wait" ); + } + } + + void NotifyOne() { + int result = pthread_cond_signal( &m_CV ); + if(result != 0) { + ReportErrorAndExit( result, "pthread_cond_signal" ); + } + } + + void NotifyAll() { + int result = pthread_cond_broadcast( &m_CV ); + if(result != 0) { + ReportErrorAndExit( result, "pthread_cond_broadcast" ); + } + } +}; + +class TCConditionVariableImplFactory : public TCThreadBaseImplFactory { +public: + TCConditionVariableImplFactory() { } + virtual ~TCConditionVariableImplFactory() { } + virtual TCThreadBaseImpl *CreateImpl() const { + return new TCConditionVariableImpl(); + } +}; + +TCConditionVariable::TCConditionVariable() + : TCThreadBase(TCConditionVariableImplFactory()) +{ } + +void TCConditionVariable::Wait(TCLock &lock) { + CheckReferenceCount(); + + TCConditionVariableImpl *impl = (TCConditionVariableImpl *)m_Impl; + impl->Wait(lock); +} + +void TCConditionVariable::NotifyOne() { + CheckReferenceCount(); + + TCConditionVariableImpl *impl = (TCConditionVariableImpl *)m_Impl; + impl->NotifyOne(); +} + +void TCConditionVariable::NotifyAll() { + CheckReferenceCount(); + + TCConditionVariableImpl *impl = (TCConditionVariableImpl *)m_Impl; + impl->NotifyAll(); +}