Add pthread module for threading.

This commit is contained in:
Pavel Krajcevski 2012-09-30 15:34:21 -04:00
parent 4d52ea18ad
commit 920c947d55
3 changed files with 285 additions and 9 deletions

View File

@ -1,4 +1,4 @@
CMAKE_MINIMUM_REQUIRED(VERSION 2.6) CMAKE_MINIMUM_REQUIRED(VERSION 2.8 FATAL_ERROR)
PROJECT(TexC) PROJECT(TexC)
ADD_SUBDIRECTORY(BPTCEncoder) ADD_SUBDIRECTORY(BPTCEncoder)

View File

@ -34,19 +34,44 @@ INCLUDE_DIRECTORIES( ${TexC_BINARY_DIR}/IO/include )
INCLUDE_DIRECTORIES( ${TexC_SOURCE_DIR}/Core/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 ) FIND_PACKAGE( Boost COMPONENTS thread system )
IF( Boost_FOUND ) 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} ) INCLUDE_DIRECTORIES( ${Boost_INCLUDE_DIR} )
SET( THREAD_API "Boost" )
SET( SOURCES ${SOURCES} "src/ThreadBoost.cpp" ) SET( SOURCES ${SOURCES} "src/ThreadBoost.cpp" )
LINK_DIRECTORIES( ${Boost_LIBRARY_DIR} ) LINK_DIRECTORIES( ${Boost_LIBRARY_DIR} )
ENDIF() 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/Thread.cpp" )
SET( SOURCES ${SOURCES} "src/ThreadGroup.cpp" ) SET( SOURCES ${SOURCES} "src/ThreadGroup.cpp" )
SET( SOURCES ${SOURCES} "src/WorkerQueue.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/Thread.h" )
SET( HEADERS ${HEADERS} "src/ThreadGroup.h" ) SET( HEADERS ${HEADERS} "src/ThreadGroup.h" )
SET( HEADERS ${HEADERS} "src/WorkerQueue.h" ) SET( HEADERS ${HEADERS} "src/WorkerQueue.h" )
ELSE()
MESSAGE( FATAL_ERROR "Could not find suitable threading library." )
ENDIF() ENDIF()
ADD_LIBRARY( TexCompCore ADD_LIBRARY( TexCompCore
@ -66,10 +89,14 @@ ADD_LIBRARY( TexCompCore
TARGET_LINK_LIBRARIES( TexCompCore TexCompIO ) TARGET_LINK_LIBRARIES( TexCompCore TexCompIO )
TARGET_LINK_LIBRARIES( TexCompCore BPTCEncoder ) TARGET_LINK_LIBRARIES( TexCompCore BPTCEncoder )
IF( Boost_FOUND ) IF( THREAD_API MATCHES "Boost" )
TARGET_LINK_LIBRARIES( TexCompCore ${Boost_LIBRARIES} ) TARGET_LINK_LIBRARIES( TexCompCore ${Boost_LIBRARIES} )
ENDIF() ENDIF()
IF( THREAD_API MATCHES "PThread" )
TARGET_LINK_LIBRARIES( TexCompCore ${CMAKE_THREAD_LIBS_INIT} )
ENDIF()
IF( NOT WIN32 AND NOT APPLE ) IF( NOT WIN32 AND NOT APPLE )
TARGET_LINK_LIBRARIES( TexCompCore rt ) TARGET_LINK_LIBRARIES( TexCompCore rt )
ENDIF() ENDIF()

249
Core/src/ThreadPThread.cpp Normal file
View File

@ -0,0 +1,249 @@
#include "Thread.h"
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <errno.h>
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();
}