summaryrefslogtreecommitdiffstats
path: root/lib/libUPnP/Neptune/Source/System/Posix/NptPosixThreads.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libUPnP/Neptune/Source/System/Posix/NptPosixThreads.cpp')
-rw-r--r--lib/libUPnP/Neptune/Source/System/Posix/NptPosixThreads.cpp716
1 files changed, 716 insertions, 0 deletions
diff --git a/lib/libUPnP/Neptune/Source/System/Posix/NptPosixThreads.cpp b/lib/libUPnP/Neptune/Source/System/Posix/NptPosixThreads.cpp
new file mode 100644
index 0000000..510d3e9
--- /dev/null
+++ b/lib/libUPnP/Neptune/Source/System/Posix/NptPosixThreads.cpp
@@ -0,0 +1,716 @@
+/*****************************************************************
+|
+| 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>
+#include <errno.h>
+
+#include "NptConfig.h"
+#include "NptTypes.h"
+#include "NptThreads.h"
+#include "NptLogging.h"
+#include "NptTime.h"
+#include "NptSystem.h"
+#include "NptUtils.h"
+#include "NptAutoreleasePool.h"
+
+/*----------------------------------------------------------------------
+| logging
++---------------------------------------------------------------------*/
+NPT_SET_LOCAL_LOGGER("neptune.threads.posix")
+
+/*----------------------------------------------------------------------
+| NPT_PosixMutex
++---------------------------------------------------------------------*/
+class NPT_PosixMutex : public NPT_MutexInterface
+{
+public:
+ // methods
+ NPT_PosixMutex(bool recursive = false);
+ ~NPT_PosixMutex() override;
+
+ // NPT_Mutex methods
+ NPT_Result Lock() override;
+ NPT_Result Unlock() override;
+
+private:
+ // members
+ pthread_mutex_t m_Mutex;
+};
+
+/*----------------------------------------------------------------------
+| NPT_PosixMutex::NPT_PosixMutex
++---------------------------------------------------------------------*/
+NPT_PosixMutex::NPT_PosixMutex(bool recursive)
+{
+ // Recursive by default
+ pthread_mutexattr_t attr;
+
+ if (recursive) {
+ pthread_mutexattr_init(&attr);
+ pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+ }
+
+ pthread_mutex_init(&m_Mutex, recursive?&attr: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(bool recursive)
+{
+ m_Delegate = new NPT_PosixMutex(recursive);
+}
+
+/*----------------------------------------------------------------------
+| NPT_PosixSharedVariable
++---------------------------------------------------------------------*/
+class NPT_PosixSharedVariable : public NPT_SharedVariableInterface
+{
+public:
+ // methods
+ NPT_PosixSharedVariable(int value);
+ ~NPT_PosixSharedVariable() override;
+ void SetValue(int value) override;
+ int GetValue() override;
+ NPT_Result WaitUntilEquals(int value, NPT_Timeout timeout) override;
+ NPT_Result WaitWhileEquals(int value, NPT_Timeout timeout) override;
+
+ 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() override;
+ int Increment() override;
+ int Decrement() override;
+ int GetValue() override;
+ void SetValue(int value) override;
+
+ 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() override;
+ NPT_Result Start() override;
+ NPT_Result Wait(NPT_Timeout timeout = NPT_TIMEOUT_INFINITE) override;
+ NPT_Result CancelBlockerSocket() override;
+ NPT_Result SetPriority(int priority) override;
+ NPT_Result GetPriority(int& priority) override;
+
+ // class methods
+ static NPT_Result GetPriority(NPT_Thread::ThreadId thread_id, int& priority);
+ static NPT_Result SetPriority(NPT_Thread::ThreadId thread_id, int priority);
+
+ private:
+ // methods
+ static void* EntryPoint(void* argument);
+
+ // NPT_Runnable methods
+ void Run() override;
+
+ // NPT_Interruptible methods
+ NPT_Result Interrupt() override { 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 %lld\n", (NPT_Thread::ThreadId)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)pid;
+}
+
+/*----------------------------------------------------------------------
+| NPT_Thread::SetCurrentThreadPriority
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_Thread::SetCurrentThreadPriority(int priority)
+{
+ return NPT_PosixThread::SetPriority(GetCurrentThreadId(), priority);
+}
+
+/*----------------------------------------------------------------------
+| NPT_Thread::GetCurrentThreadPriority
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_Thread::GetCurrentThreadPriority(int& priority)
+{
+ return NPT_PosixThread::GetPriority(GetCurrentThreadId(), priority);
+}
+
+/*----------------------------------------------------------------------
+| NPT_PosixThread::EntryPoint
++---------------------------------------------------------------------*/
+void*
+NPT_PosixThread::EntryPoint(void* argument)
+{
+ NPT_PosixThread* thread = reinterpret_cast<NPT_PosixThread*>(argument);
+
+ NPT_LOG_FINE("NPT_PosixThread::EntryPoint - in =======================");
+
+ // ensure there is the top level autorelease pool for each thread
+ NPT_AutoreleasePool pool;
+
+ // get the thread ID from this context, because m_ThreadId may not yet
+ // have been set by the parent thread in the Start() method
+ thread->m_ThreadId = pthread_self();
+
+ // set random seed per thread
+ NPT_TimeStamp now;
+ NPT_System::GetCurrentTimeStamp(now);
+ NPT_System::SetRandomSeed((unsigned int)(now.ToNanos() + (long)thread->m_ThreadId));
+
+ // 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");
+
+ // reset values
+ m_Joined = false;
+ m_ThreadId = 0;
+ m_Done.SetValue(0);
+
+ pthread_attr_t *attributes = NULL;
+
+#if defined(NPT_CONFIG_THREAD_STACK_SIZE) && 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
+
+ // use local copies of some of the object's members, because for
+ // detached threads, the object instance may have deleted itself
+ // before the pthread_create() function returns
+ bool detached = m_Detached;
+
+ // reset the joined flag
+ m_Joined = false;
+
+ // create the native thread
+ pthread_t thread_id;
+ int result = pthread_create(&thread_id, attributes, EntryPoint,
+ static_cast<NPT_PosixThread*>(this));
+ NPT_LOG_FINE_2("NPT_PosixThread::Start - id = %p, res=%d",
+ (void*)thread_id, result);
+ if (result != 0) {
+ // failed
+ return NPT_ERROR_ERRNO(result);
+ } else {
+ // detach the thread if we're not joinable
+ if (detached) {
+ pthread_detach(thread_id);
+ } else {
+ // store the thread ID (NOTE: this is also done by the thread Run() method
+ // but it is necessary to do it from both contexts, because we don't know
+ // which one will need it first.)
+ m_ThreadId = thread_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;
+
+ // 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) {
+ result = 0;
+ } else {
+ 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_PosixThread::CancelBlockerSocket
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_PosixThread::CancelBlockerSocket()
+{
+ return NPT_Socket::CancelBlockerSocket((NPT_Thread::ThreadId)m_ThreadId);
+}
+
+/*----------------------------------------------------------------------
+| NPT_PosixThread::SetPriority
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_PosixThread::SetPriority(int priority)
+{
+ // check that we're started
+ if (m_ThreadId == 0) {
+ return NPT_FAILURE;
+ }
+
+ return NPT_PosixThread::SetPriority((NPT_Thread::ThreadId)m_ThreadId, priority);
+}
+
+/*----------------------------------------------------------------------
+| NPT_PosixThread::SetPriority
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_PosixThread::SetPriority(NPT_Thread::ThreadId thread_id, int priority)
+{
+ // check that we're started
+ if (thread_id == 0) {
+ return NPT_FAILURE;
+ }
+
+ /* sched_priority will be the priority of the thread */
+ struct sched_param sp;
+ int policy;
+ int result = pthread_getschedparam((pthread_t)thread_id, &policy, &sp);
+
+ NPT_LOG_FINER_3("Current thread policy: %d, priority: %d, new priority: %d",
+ policy, sp.sched_priority, priority);
+ NPT_LOG_FINER_4("Thread max(SCHED_OTHER): %d, max(SCHED_RR): %d \
+ min(SCHED_OTHER): %d, min(SCHED_RR): %d",
+ sched_get_priority_max(SCHED_OTHER),
+ sched_get_priority_max(SCHED_RR),
+ sched_get_priority_min(SCHED_OTHER),
+ sched_get_priority_min(SCHED_RR));
+
+ sp.sched_priority = priority;
+
+ /*
+ if (sp.sched_priority <= 0)
+ sp.sched_priority += sched_get_priority_max (policy = SCHED_OTHER);
+ else
+ sp.sched_priority += sched_get_priority_min (policy = SCHED_RR);
+ */
+
+ /* scheduling parameters of target thread */
+ result = pthread_setschedparam((pthread_t)thread_id, policy, &sp);
+
+ return (result==0)?NPT_SUCCESS:NPT_ERROR_ERRNO(result);
+}
+
+/*----------------------------------------------------------------------
+| NPT_PosixThread::GetPriority
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_PosixThread::GetPriority(int& priority)
+{
+ // check that we're started
+ if (m_ThreadId == 0) {
+ return NPT_FAILURE;
+ }
+
+ return NPT_PosixThread::GetPriority((NPT_Thread::ThreadId)m_ThreadId, priority);
+}
+
+/*----------------------------------------------------------------------
+| NPT_PosixThread::GetPriority
++---------------------------------------------------------------------*/
+NPT_Result
+NPT_PosixThread::GetPriority(NPT_Thread::ThreadId thread_id, int& priority)
+{
+ // check that we're started
+ if (thread_id == 0) {
+ return NPT_FAILURE;
+ }
+
+ struct sched_param sp;
+ int policy;
+
+ int result = pthread_getschedparam((pthread_t)thread_id, &policy, &sp);
+ NPT_LOG_FINER_1("Current thread priority: %d", sp.sched_priority);
+
+ priority = sp.sched_priority;
+ return (result==0)?NPT_SUCCESS:NPT_ERROR_ERRNO(result);
+}
+
+/*----------------------------------------------------------------------
+| 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);
+}
+