Mercurial > projects > hoofbaby
diff deps/Platinum/ThirdParty/Neptune/Source/System/Posix/NptPosixThreads.cpp @ 0:3425707ddbf6
Initial import (hopefully this mercurial stuff works...)
author | fraserofthenight |
---|---|
date | Mon, 06 Jul 2009 08:06:28 -0700 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/deps/Platinum/ThirdParty/Neptune/Source/System/Posix/NptPosixThreads.cpp Mon Jul 06 08:06:28 2009 -0700 @@ -0,0 +1,573 @@ +/***************************************************************** +| +| Neptune - Threads :: Posix Implementation +| +| (c) 2001-2002 Gilles Boccon-Gibod +| Author: Gilles Boccon-Gibod (bok@bok.net) +| + ****************************************************************/ + +/*---------------------------------------------------------------------- +| includes ++---------------------------------------------------------------------*/ +#if defined(__SYMBIAN32__) +#include <stdio.h> +#endif +#include <pthread.h> +#include <unistd.h> +#include <time.h> +#include <sys/time.h> +#if defined(__SYMBIAN32__) +#include <errno.h> +#else +#include <cerrno> +#endif + +#include "NptConfig.h" +#include "NptTypes.h" +#include "NptThreads.h" +#include "NptLogging.h" +#include "NptTime.h" +#include "NptSystem.h" + +/*---------------------------------------------------------------------- +| logging ++---------------------------------------------------------------------*/ +NPT_SET_LOCAL_LOGGER("neptune.threads.posix") + +/*---------------------------------------------------------------------- +| NPT_PosixMutex ++---------------------------------------------------------------------*/ +class NPT_PosixMutex : public NPT_MutexInterface +{ +public: + // methods + NPT_PosixMutex(); + virtual ~NPT_PosixMutex(); + + // NPT_Mutex methods + virtual NPT_Result Lock(); + virtual NPT_Result Unlock(); + +private: + // members + pthread_mutex_t m_Mutex; +}; + +/*---------------------------------------------------------------------- +| NPT_PosixMutex::NPT_PosixMutex ++---------------------------------------------------------------------*/ +NPT_PosixMutex::NPT_PosixMutex() +{ + pthread_mutex_init(&m_Mutex, NULL); +} + +/*---------------------------------------------------------------------- +| NPT_PosixMutex::~NPT_PosixMutex ++---------------------------------------------------------------------*/ +NPT_PosixMutex::~NPT_PosixMutex() +{ + pthread_mutex_destroy(&m_Mutex); +} + +/*---------------------------------------------------------------------- +| NPT_PosixMutex::Lock ++---------------------------------------------------------------------*/ +NPT_Result +NPT_PosixMutex::Lock() +{ + pthread_mutex_lock(&m_Mutex); + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_PosixMutex::Unlock ++---------------------------------------------------------------------*/ +NPT_Result +NPT_PosixMutex::Unlock() +{ + pthread_mutex_unlock(&m_Mutex); + return NPT_SUCCESS; +} + +/*---------------------------------------------------------------------- +| NPT_Mutex::NPT_Mutex ++---------------------------------------------------------------------*/ +NPT_Mutex::NPT_Mutex() +{ + m_Delegate = new NPT_PosixMutex(); +} + +/*---------------------------------------------------------------------- +| NPT_PosixSharedVariable ++---------------------------------------------------------------------*/ +class NPT_PosixSharedVariable : public NPT_SharedVariableInterface +{ +public: + // methods + NPT_PosixSharedVariable(int value); + ~NPT_PosixSharedVariable(); + void SetValue(int value); + int GetValue(); + NPT_Result WaitUntilEquals(int value, NPT_Timeout timeout); + NPT_Result WaitWhileEquals(int value, NPT_Timeout timeout); + + private: + // members + volatile int m_Value; + pthread_mutex_t m_Mutex; + pthread_cond_t m_Condition; +}; + +/*---------------------------------------------------------------------- +| NPT_PosixSharedVariable::NPT_PosixSharedVariable ++---------------------------------------------------------------------*/ +NPT_PosixSharedVariable::NPT_PosixSharedVariable(int value) : + m_Value(value) +{ + pthread_mutex_init(&m_Mutex, NULL); + pthread_cond_init(&m_Condition, NULL); +} + +/*---------------------------------------------------------------------- +| NPT_PosixSharedVariable::~NPT_PosixSharedVariable ++---------------------------------------------------------------------*/ +NPT_PosixSharedVariable::~NPT_PosixSharedVariable() +{ + pthread_cond_destroy(&m_Condition); + pthread_mutex_destroy(&m_Mutex); +} + +/*---------------------------------------------------------------------- +| NPT_PosixSharedVariable::SetValue ++---------------------------------------------------------------------*/ +void +NPT_PosixSharedVariable::SetValue(int value) +{ + pthread_mutex_lock(&m_Mutex); + m_Value = value; + pthread_cond_broadcast(&m_Condition); + pthread_mutex_unlock(&m_Mutex); +} + +/*---------------------------------------------------------------------- +| NPT_PosixSharedVariable::GetValue ++---------------------------------------------------------------------*/ +int +NPT_PosixSharedVariable::GetValue() +{ + // we assume that int read/write are atomic on the platform + return m_Value; +} + +/*---------------------------------------------------------------------- +| NPT_PosixSharedVariable::WaitUntilEquals ++---------------------------------------------------------------------*/ +NPT_Result +NPT_PosixSharedVariable::WaitUntilEquals(int value, NPT_Timeout timeout) +{ + NPT_Result result = NPT_SUCCESS; + struct timespec timed; + + if (timeout != NPT_TIMEOUT_INFINITE) { + // get current time from system + struct timeval now; + if (gettimeofday(&now, NULL)) { + return NPT_FAILURE; + } + + now.tv_usec += timeout * 1000; + if (now.tv_usec >= 1000000) { + now.tv_sec += now.tv_usec / 1000000; + now.tv_usec = now.tv_usec % 1000000; + } + + // setup timeout + timed.tv_sec = now.tv_sec; + timed.tv_nsec = now.tv_usec * 1000; + } + + pthread_mutex_lock(&m_Mutex); + while (value != m_Value) { + if (timeout == NPT_TIMEOUT_INFINITE) { + pthread_cond_wait(&m_Condition, &m_Mutex); + } else { + int wait_res = pthread_cond_timedwait(&m_Condition, &m_Mutex, &timed); + if (wait_res == ETIMEDOUT) { + result = NPT_ERROR_TIMEOUT; + break; + } + } + } + pthread_mutex_unlock(&m_Mutex); + + return result; +} + +/*---------------------------------------------------------------------- +| NPT_PosixSharedVariable::WaitWhileEquals ++---------------------------------------------------------------------*/ +NPT_Result +NPT_PosixSharedVariable::WaitWhileEquals(int value, NPT_Timeout timeout) +{ + NPT_Result result = NPT_SUCCESS; + struct timespec timed; + + if (timeout != NPT_TIMEOUT_INFINITE) { + // get current time from system + struct timeval now; + if (gettimeofday(&now, NULL)) { + return NPT_FAILURE; + } + + now.tv_usec += timeout * 1000; + if (now.tv_usec >= 1000000) { + now.tv_sec += now.tv_usec / 1000000; + now.tv_usec = now.tv_usec % 1000000; + } + + // setup timeout + timed.tv_sec = now.tv_sec; + timed.tv_nsec = now.tv_usec * 1000; + } + + pthread_mutex_lock(&m_Mutex); + while (value == m_Value) { + if (timeout == NPT_TIMEOUT_INFINITE) { + pthread_cond_wait(&m_Condition, &m_Mutex); + } else { + int wait_res = pthread_cond_timedwait(&m_Condition, &m_Mutex, &timed); + if (wait_res == ETIMEDOUT) { + result = NPT_ERROR_TIMEOUT; + break; + } + } + } + pthread_mutex_unlock(&m_Mutex); + + return result; +} + +/*---------------------------------------------------------------------- +| NPT_SharedVariable::NPT_SharedVariable ++---------------------------------------------------------------------*/ +NPT_SharedVariable::NPT_SharedVariable(int value) +{ + m_Delegate = new NPT_PosixSharedVariable(value); +} + +/*---------------------------------------------------------------------- +| NPT_PosixAtomicVariable ++---------------------------------------------------------------------*/ +class NPT_PosixAtomicVariable : public NPT_AtomicVariableInterface +{ + public: + // methods + NPT_PosixAtomicVariable(int value); + ~NPT_PosixAtomicVariable(); + int Increment(); + int Decrement(); + int GetValue(); + void SetValue(int value); + + private: + // members + volatile int m_Value; + pthread_mutex_t m_Mutex; +}; + +/*---------------------------------------------------------------------- +| NPT_PosixAtomicVariable::NPT_PosixAtomicVariable ++---------------------------------------------------------------------*/ +NPT_PosixAtomicVariable::NPT_PosixAtomicVariable(int value) : + m_Value(value) +{ + pthread_mutex_init(&m_Mutex, NULL); +} + +/*---------------------------------------------------------------------- +| NPT_PosixAtomicVariable::~NPT_PosixAtomicVariable ++---------------------------------------------------------------------*/ +NPT_PosixAtomicVariable::~NPT_PosixAtomicVariable() +{ + pthread_mutex_destroy(&m_Mutex); +} + +/*---------------------------------------------------------------------- +| NPT_PosixAtomicVariable::Increment ++---------------------------------------------------------------------*/ +int +NPT_PosixAtomicVariable::Increment() +{ + int value; + + pthread_mutex_lock(&m_Mutex); + value = ++m_Value; + pthread_mutex_unlock(&m_Mutex); + + return value; +} + +/*---------------------------------------------------------------------- +| NPT_PosixAtomicVariable::Decrement ++---------------------------------------------------------------------*/ +int +NPT_PosixAtomicVariable::Decrement() +{ + int value; + + pthread_mutex_lock(&m_Mutex); + value = --m_Value; + pthread_mutex_unlock(&m_Mutex); + + return value; +} + +/*---------------------------------------------------------------------- +| NPT_PosixAtomicVariable::GetValue ++---------------------------------------------------------------------*/ +int +NPT_PosixAtomicVariable::GetValue() +{ + // we assume that int read/write are atomic on the platform + return m_Value; +} + +/*---------------------------------------------------------------------- +| NPT_PosixAtomicVariable::SetValue ++---------------------------------------------------------------------*/ +void +NPT_PosixAtomicVariable::SetValue(int value) +{ + pthread_mutex_lock(&m_Mutex); + m_Value = value; + pthread_mutex_unlock(&m_Mutex); +} + +/*---------------------------------------------------------------------- +| NPT_AtomicVariable::NPT_AtomicVariable ++---------------------------------------------------------------------*/ +NPT_AtomicVariable::NPT_AtomicVariable(int value) +{ + m_Delegate = new NPT_PosixAtomicVariable(value); +} + +/*---------------------------------------------------------------------- +| NPT_PosixThread ++---------------------------------------------------------------------*/ +class NPT_PosixThread : public NPT_ThreadInterface +{ + public: + // methods + NPT_PosixThread(NPT_Thread* delegator, + NPT_Runnable& target, + bool detached); + ~NPT_PosixThread(); + NPT_Result Start(); + NPT_Result Wait(NPT_Timeout timeout = NPT_TIMEOUT_INFINITE); + + private: + // methods + static void* EntryPoint(void* argument); + + // NPT_Runnable methods + void Run(); + + // NPT_Interruptible methods + NPT_Result Interrupt() { return NPT_ERROR_NOT_IMPLEMENTED; } + + // members + NPT_Thread* m_Delegator; + NPT_Runnable& m_Target; + bool m_Detached; + pthread_t m_ThreadId; + bool m_Joined; + NPT_PosixMutex m_JoinLock; + NPT_SharedVariable m_Done; +}; + +/*---------------------------------------------------------------------- +| NPT_PosixThread::NPT_PosixThread ++---------------------------------------------------------------------*/ +NPT_PosixThread::NPT_PosixThread(NPT_Thread* delegator, + NPT_Runnable& target, + bool detached) : + m_Delegator(delegator), + m_Target(target), + m_Detached(detached), + m_ThreadId(0), + m_Joined(false) +{ + NPT_LOG_FINE("NPT_PosixThread::NPT_PosixThread"); + m_Done.SetValue(0); +} + +/*---------------------------------------------------------------------- +| NPT_PosixThread::~NPT_PosixThread ++---------------------------------------------------------------------*/ +NPT_PosixThread::~NPT_PosixThread() +{ + NPT_LOG_FINE_1("NPT_PosixThread::~NPT_PosixThread %d\n", m_ThreadId); + + if (!m_Detached) { + // we're not detached, and not in the Run() method, so we need to + // wait until the thread is done + Wait(); + } +} + +/*---------------------------------------------------------------------- +| NPT_Thread::GetCurrentThreadId ++---------------------------------------------------------------------*/ +NPT_Thread::ThreadId +NPT_Thread::GetCurrentThreadId() +{ + pthread_t pid = pthread_self(); + return (NPT_Thread::ThreadId)((void*)pid); +} + +/*---------------------------------------------------------------------- +| NPT_PosixThread::EntryPoint ++---------------------------------------------------------------------*/ +void* +NPT_PosixThread::EntryPoint(void* argument) +{ + NPT_PosixThread* thread = reinterpret_cast<NPT_PosixThread*>(argument); + + NPT_LOG_FINE("NPT_PosixThread::EntryPoint - in ======================="); + + // set random seed per thread + NPT_TimeStamp now; + NPT_System::GetCurrentTimeStamp(now); + NPT_System::SetRandomSeed((unsigned int)(now.m_NanoSeconds + (long)NPT_Thread::GetCurrentThreadId())); + + // run the thread + thread->Run(); + + // Logging here will cause a crash on exit because LogManager may already be destroyed + //NPT_LOG_FINE("NPT_PosixThread::EntryPoint - out ======================"); + + // we're done with the thread object + // if we're detached, we need to delete ourselves + if (thread->m_Detached) { + delete thread->m_Delegator; + } else { + // notify we're done + thread->m_Done.SetValue(1); + } + + // done + return NULL; +} + +/*---------------------------------------------------------------------- +| NPT_PosixThread::Start ++---------------------------------------------------------------------*/ +NPT_Result +NPT_PosixThread::Start() +{ + NPT_LOG_FINE("NPT_PosixThread::Start - creating thread"); + + pthread_attr_t *attributes = NULL; + +#if defined(NPT_CONFIG_THREAD_STACK_SIZE) + pthread_attr_t stack_size_attributes; + pthread_attr_init(&stack_size_attributes); + pthread_attr_setstacksize(&stack_size_attributes, NPT_CONFIG_THREAD_STACK_SIZE); + attributes = &stack_size_attributes; +#endif + + // create a stack local id, as if detached, this object + // may already be deleted when pthread_create returns and + // before we get to call detach on the given thread + pthread_t id; + bool detached = m_Detached; + + // create the native thread + int result = pthread_create(&id, attributes, EntryPoint, + reinterpret_cast<void*>(this)); + NPT_LOG_FINE_2("NPT_PosixThread::Start - id = %d, res=%d", + id, result); + if (result) { + // failed + return NPT_FAILURE; + } else { + // detach the thread if we're not joinable + if (detached) { + pthread_detach(id); + } else { + m_ThreadId = id; + } + return NPT_SUCCESS; + } +} + +/*---------------------------------------------------------------------- +| NPT_PosixThread::Run ++---------------------------------------------------------------------*/ +void +NPT_PosixThread::Run() +{ + m_Target.Run(); +} + +/*---------------------------------------------------------------------- +| NPT_PosixThread::Wait ++---------------------------------------------------------------------*/ +NPT_Result +NPT_PosixThread::Wait(NPT_Timeout timeout /* = NPT_TIMEOUT_INFINITE */) +{ + void* return_value; + int result; + + NPT_LOG_FINE_1("NPT_PosixThread::Wait - waiting for id %d", m_ThreadId); + + // check that we're not detached + if (m_ThreadId == 0 || m_Detached) { + return NPT_FAILURE; + } + + // wait for the thread to finish + m_JoinLock.Lock(); + if (m_Joined) { + NPT_LOG_FINE_1("NPT_PosixThread::Wait - %d already joined", m_ThreadId); + result = 0; + } else { + NPT_LOG_FINE_1("NPT_PosixThread::Wait - joining thread id %d", m_ThreadId); + if (timeout != NPT_TIMEOUT_INFINITE) { + result = m_Done.WaitUntilEquals(1, timeout); + if (NPT_FAILED(result)) { + result = -1; + goto timedout; + } + } + + result = pthread_join(m_ThreadId, &return_value); + m_Joined = true; + } + +timedout: + m_JoinLock.Unlock(); + if (result != 0) { + return NPT_FAILURE; + } else { + return NPT_SUCCESS; + } +} + +/*---------------------------------------------------------------------- +| NPT_Thread::NPT_Thread ++---------------------------------------------------------------------*/ +NPT_Thread::NPT_Thread(bool detached) +{ + m_Delegate = new NPT_PosixThread(this, *this, detached); +} + +/*---------------------------------------------------------------------- +| NPT_Thread::NPT_Thread ++---------------------------------------------------------------------*/ +NPT_Thread::NPT_Thread(NPT_Runnable& target, bool detached) +{ + m_Delegate = new NPT_PosixThread(this, target, detached); +} +