diff options
Diffstat (limited to 'Runtime/Threads/Posix')
-rw-r--r-- | Runtime/Threads/Posix/PlatformMutex.cpp | 51 | ||||
-rw-r--r-- | Runtime/Threads/Posix/PlatformMutex.h | 29 | ||||
-rw-r--r-- | Runtime/Threads/Posix/PlatformSemaphore.h | 69 | ||||
-rw-r--r-- | Runtime/Threads/Posix/PlatformThread.cpp | 185 | ||||
-rw-r--r-- | Runtime/Threads/Posix/PlatformThread.h | 56 | ||||
-rw-r--r-- | Runtime/Threads/Posix/PlatformThreadSpecificValue.h | 63 |
6 files changed, 453 insertions, 0 deletions
diff --git a/Runtime/Threads/Posix/PlatformMutex.cpp b/Runtime/Threads/Posix/PlatformMutex.cpp new file mode 100644 index 0000000..b48e138 --- /dev/null +++ b/Runtime/Threads/Posix/PlatformMutex.cpp @@ -0,0 +1,51 @@ +#include "UnityPrefix.h" + +#if SUPPORT_THREADS + +#ifndef MUTEX_API_PTHREAD +#define MUTEX_API_PTHREAD (UNITY_OSX || UNITY_IPHONE || UNITY_ANDROID || UNITY_PEPPER || UNITY_LINUX || UNITY_BB10 || UNITY_TIZEN) +#endif + +#endif // SUPPORT_THREADS + +#if MUTEX_API_PTHREAD +// ------------------------------------------------------------------------------------------------- +// pthreads + +#include "PlatformMutex.h" + +#if defined(__native_client__) +#define PTHREAD_MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE_NP +#endif + +PlatformMutex::PlatformMutex ( ) +{ + pthread_mutexattr_t attr; + + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_RECURSIVE ); + pthread_mutex_init(&mutex, &attr); + pthread_mutexattr_destroy(&attr); +} + +PlatformMutex::~PlatformMutex () +{ + pthread_mutex_destroy(&mutex); +} + +void PlatformMutex::Lock() +{ + pthread_mutex_lock(&mutex); +} + +void PlatformMutex::Unlock() +{ + pthread_mutex_unlock(&mutex); +} + +bool PlatformMutex::TryLock() +{ + return pthread_mutex_trylock(&mutex) == 0; +} + +#endif // MUTEX_API_PTHREAD diff --git a/Runtime/Threads/Posix/PlatformMutex.h b/Runtime/Threads/Posix/PlatformMutex.h new file mode 100644 index 0000000..0071094 --- /dev/null +++ b/Runtime/Threads/Posix/PlatformMutex.h @@ -0,0 +1,29 @@ +#ifndef __PLATFORMMUTEX_H +#define __PLATFORMMUTEX_H + +#if SUPPORT_THREADS + +#include <pthread.h> +#include "Runtime/Utilities/NonCopyable.h" + +/** + * A platform/api specific mutex class. Always recursive (a single thread can lock multiple times). + */ +class PlatformMutex : public NonCopyable +{ + friend class Mutex; +protected: + PlatformMutex(); + ~PlatformMutex(); + + void Lock(); + void Unlock(); + bool TryLock(); + +private: + + pthread_mutex_t mutex; +}; + +#endif // SUPPORT_THREADS +#endif // __PLATFORMMUTEX_H diff --git a/Runtime/Threads/Posix/PlatformSemaphore.h b/Runtime/Threads/Posix/PlatformSemaphore.h new file mode 100644 index 0000000..bc20a55 --- /dev/null +++ b/Runtime/Threads/Posix/PlatformSemaphore.h @@ -0,0 +1,69 @@ +#ifndef __PLATFORMSEMAPHORE_H +#define __PLATFORMSEMAPHORE_H + +#if SUPPORT_THREADS + +#ifndef SEMAPHORE_API_PTHREAD +#define SEMAPHORE_API_PTHREAD (UNITY_LINUX || UNITY_PEPPER || UNITY_ANDROID || UNITY_PS3 || UNITY_BB10 || UNITY_TIZEN) +#endif + +#endif // SUPPORT_THREADS + +#if SEMAPHORE_API_PTHREAD + +#if UNITY_PEPPER +# include <errno.h> +# if defined(__native_client__) +# include <semaphore.h> +# else +# include <sys/semaphore.h> +# endif +#else +# include <semaphore.h> +# include <errno.h> +#endif + +#include "Runtime/Utilities/Word.h" +#include "Runtime/Utilities/NonCopyable.h" + +class PlatformSemaphore : public NonCopyable +{ + friend class Semaphore; +protected: + void Create(); + void Destroy(); + + void WaitForSignal(); + void Signal(); + +private: + sem_t m_Semaphore; +}; + +#define REPORT_SEM_ERROR(action) ErrorStringMsg ("Failed to %s a semaphore (%s)\n", action, strerror (errno)) + + inline void PlatformSemaphore::Create() { if (sem_init(&m_Semaphore, 0, 0) == -1) REPORT_SEM_ERROR ("open"); } + inline void PlatformSemaphore::Destroy() { if (sem_destroy(&m_Semaphore) == -1) REPORT_SEM_ERROR ("destroy"); } +#if !UNITY_BB10 + inline void PlatformSemaphore::WaitForSignal() { if (sem_wait(&m_Semaphore) == -1) REPORT_SEM_ERROR ("wait on"); } +#else + inline void PlatformSemaphore::WaitForSignal() { + int ret = 0; + while ((ret = sem_wait(&m_Semaphore)) == -1 && errno == EINTR) + { + continue; + } + + if( ret == -1 ) + REPORT_SEM_ERROR ("wait on"); + } +#endif + inline void PlatformSemaphore::Signal() { + if (sem_post(&m_Semaphore) == -1) + REPORT_SEM_ERROR ("post to"); + } + +#undef REPORT_SEM_ERROR + +#endif // SEMAPHORE_API_PTHREAD +#endif // __PLATFORMSEMAPHORE_H diff --git a/Runtime/Threads/Posix/PlatformThread.cpp b/Runtime/Threads/Posix/PlatformThread.cpp new file mode 100644 index 0000000..3b3a9e0 --- /dev/null +++ b/Runtime/Threads/Posix/PlatformThread.cpp @@ -0,0 +1,185 @@ +#include "UnityPrefix.h" + +#if SUPPORT_THREADS + +#ifndef THREAD_API_PTHREAD +#define THREAD_API_PTHREAD (UNITY_OSX || UNITY_PS3 || UNITY_IPHONE || UNITY_ANDROID || UNITY_PEPPER || UNITY_LINUX || UNITY_BB10 || UNITY_TIZEN) +#endif + +#endif // SUPPORT_THREADS + +#if THREAD_API_PTHREAD + +#include "PlatformThread.h" +#include "Runtime/Threads/Thread.h" +#include "Runtime/Threads/ThreadHelper.h" + +#include "Runtime/Utilities/Word.h" +//#include "Runtime/Utilities/Utility.h" + +// module@TODO : Move this to PlatformThread.h +#if UNITY_PS3 +# include <sys/timer.h> +# include "pthread_ext/pthread_ext.h" +# define pthread_create pthread_ext_create +#endif + +#if UNITY_PEPPER && defined(__native_client__) +#include <sys/time.h> +#include <sys/signal.h> +#include <sys/nacl_syscalls.h> +#endif + +#if UNITY_ANDROID +#include <jni.h> + JavaVM* GetJavaVm(); + extern "C" void* GC_lookup_thread(pthread_t id); + extern "C" void GC_delete_thread(pthread_t id); +#endif + +PlatformThread::PlatformThread() +: m_Thread((ThreadID)NULL) +{ +} + +PlatformThread::~PlatformThread() +{ + AssertMsg(m_Thread == (ThreadID)NULL, "***Thread was not cleaned up!***"); +} + + +void PlatformThread::Create(const Thread* thread, const UInt32 stackSize, const int processor) +{ + m_DefaultPriority = 0; + m_Processor = processor; + + if(stackSize) + { + pthread_attr_t attr; + memset(&attr, 0, sizeof(attr)); + +// module@TODO : Implement pthread_attr_init/pthread_attr_setstacksize in PlatformThread.h +#if UNITY_PS3 + attr.stacksize = stackSize; + attr.name = "_UNITY_"; +#else + pthread_attr_init(&attr); + pthread_attr_setstacksize(&attr, stackSize); +#endif + pthread_create(&m_Thread, &attr, Thread::RunThreadWrapper, (void*)thread); + } + else { + pthread_create(&m_Thread, NULL, Thread::RunThreadWrapper, (void*)thread); + } + +#if UNITY_OSX || UNITY_IPHONE || UNITY_PS3 + // Y U no want on Linux? + struct sched_param param; + int outputPolicy; + if (pthread_getschedparam(m_Thread, &outputPolicy, ¶m) == 0) + m_DefaultPriority = param.sched_priority; + AssertIf(m_DefaultPriority == 0); // Y U no like 0 priority? +#endif + + if (thread->m_Priority != kNormalPriority) + UpdatePriority(thread); +} + +void PlatformThread::Enter(const Thread* thread) +{ + ThreadHelper::SetThreadProcessor(thread, m_Processor); +} + +void PlatformThread::Exit(const Thread* thread, void* result) +{ +#if UNITY_ANDROID + if (GC_lookup_thread(pthread_self())) + GC_delete_thread(pthread_self()); + GetJavaVm()->DetachCurrentThread(); + pthread_exit(result); +#endif +} + +void PlatformThread::Join(const Thread* thread) +{ + if (Thread::EqualsCurrentThreadID(m_Thread)) + { + ErrorStringMsg("***Thread '%s' tried to join itself!***", thread->m_Name); + } + + if (m_Thread) + { + int error = pthread_join(m_Thread, NULL); + if (error) + ErrorString(Format("Error joining threads: %d", error)); + + m_Thread = 0; + } +} + +void PlatformThread::UpdatePriority(const Thread* thread) const +{ +#if UNITY_PEPPER || UNITY_BB10 + + // No thread priority in NaCl yet. + // For BB10 the user Unity is run as lacks permission to set priority. + +#else // Default POSIX impl below + + ThreadPriority p = thread->m_Priority; + +#if UNITY_OSX || UNITY_IPHONE || UNITY_PS3 + AssertIf(m_DefaultPriority == 0); +#endif + + struct sched_param param; + int policy; + ErrorIf(pthread_getschedparam(m_Thread, &policy, ¶m)); +#if UNITY_PS3 + int min = 3071; + int max = 0; +#else + int min = sched_get_priority_min(policy); + int max = sched_get_priority_max(policy); +#endif + + int iPriority; + switch (p) + { + case kLowPriority: + iPriority = min; + break; + + case kBelowNormalPriority: + iPriority = min + (m_DefaultPriority-min)/2; + break; + + case kNormalPriority: + iPriority = m_DefaultPriority; + break; + + case kHighPriority: + iPriority = max; + break; + + default: + iPriority = min; + AssertString("Undefined thread priority"); + break; + } + + if (param.sched_priority != iPriority) + { + param.sched_priority = iPriority; + ErrorIf(pthread_setschedparam(m_Thread, policy, ¶m)); + } + +#endif +} + +PlatformThread::ThreadID PlatformThread::GetCurrentThreadID() +{ + return (ThreadID)pthread_self(); +} + +#endif // THREAD_API_PTHREAD diff --git a/Runtime/Threads/Posix/PlatformThread.h b/Runtime/Threads/Posix/PlatformThread.h new file mode 100644 index 0000000..757d4d5 --- /dev/null +++ b/Runtime/Threads/Posix/PlatformThread.h @@ -0,0 +1,56 @@ +#ifndef PLATFORMTHREAD_H +#define PLATFORMTHREAD_H + +#if SUPPORT_THREADS + +#include <pthread.h> +#include "Runtime/Utilities/NonCopyable.h" + +class Thread; + +#if UNITY_PS3 // module@TODO : Move to Platforms/PS3/Include/PlatformThread.h +#define DEFAULT_UNITY_THREAD_STACK_SIZE 128*1024 +#endif + +#define UNITY_THREAD_FUNCTION_RETURNTYPE void* +#define UNITY_THREAD_FUNCTION_RETURN_SIGNATURE UNITY_THREAD_FUNCTION_RETURNTYPE + +class EXPORT_COREMODULE PlatformThread : public NonCopyable +{ + friend class Thread; + friend class ThreadHelper; + +protected: + typedef pthread_t ThreadID; + + // Starts a thread to execute within the calling process. + // Typically maps to 'CreateThread' (WinAPI) or 'pthread_create' (POSIX). + void Create(const Thread* thread, const UInt32 stackSize, const int processor); + // To be called from the thread's 'start_routine' (aka RunThreadWrapper) + // in order to boot-strap the thread (in terms of setting the thread affinity or similar). + void Enter(const Thread* thread); + // To be called as final exit/cleanup call when a thread's 'start_routine' (aka RunThreadWrapper) exits. + // Depending on the backing thread API this function may not return. + void Exit(const Thread* thread, void* result); + // The function waits for the thread specified by 'thread' to terminate. + // Typically maps to 'WaitForSingleObject' (WinAPI) or 'pthread_join' (POSIX). + void Join(const Thread* thread); + // Uses the thread->m_Priority to update the thread scheduler settings, if possible. + // Typically maps to 'SetThreadPriority' (WinAPI) or 'pthread_setschedparam' (POSIX). + // Depending on the process permissions this call may turn into a no-op. + void UpdatePriority(const Thread* thread) const; + // Returns a unique identifier for the currently executing thread. + static ThreadID GetCurrentThreadID(); + +private: + PlatformThread(); + ~PlatformThread(); + + pthread_t m_Thread; + int m_DefaultPriority; + int m_Processor; +}; + +#endif // SUPPORT_THREADS + +#endif // PLATFORMTHREAD_H diff --git a/Runtime/Threads/Posix/PlatformThreadSpecificValue.h b/Runtime/Threads/Posix/PlatformThreadSpecificValue.h new file mode 100644 index 0000000..7513834 --- /dev/null +++ b/Runtime/Threads/Posix/PlatformThreadSpecificValue.h @@ -0,0 +1,63 @@ +#ifndef PLATFORMTHREADSPECIFICVALUE_H +#define PLATFORMTHREADSPECIFICVALUE_H + +#if UNITY_DYNAMIC_TLS + +#include <pthread.h> +#include "Runtime/Utilities/LogAssert.h" +#include "Runtime/Utilities/Utility.h" + +class PlatformThreadSpecificValue +{ +public: + PlatformThreadSpecificValue(); + ~PlatformThreadSpecificValue(); + + void* GetValue() const; + void SetValue(void* value); + +private: + pthread_key_t m_TLSKey; +}; + +inline PlatformThreadSpecificValue::PlatformThreadSpecificValue() +{ + int rc = pthread_key_create(&m_TLSKey, NULL); + DebugAssertIf(rc != 0); + UNUSED(rc); +} + +inline PlatformThreadSpecificValue::~PlatformThreadSpecificValue() +{ + int rc = pthread_key_delete(m_TLSKey); + DebugAssertIf(rc != 0); + UNUSED(rc); +} + +inline void* PlatformThreadSpecificValue::GetValue() const +{ +#if !UNITY_LINUX + // 0 is a valid key on Linux and POSIX specifies keys as opaque objects, + // so technically we have no business snopping in them anyway... + DebugAssertIf(m_TLSKey == 0); +#endif + return pthread_getspecific(m_TLSKey); +} + +inline void PlatformThreadSpecificValue::SetValue(void* value) +{ +#if !UNITY_LINUX + // 0 is a valid key on Linux and POSIX specifies keys as opaque objects, + // so technically we have no business snopping in them anyway... + DebugAssertIf(m_TLSKey == 0); +#endif + pthread_setspecific(m_TLSKey, value); +} + +#else + + #error "POSIX doesn't define a static TLS path" + +#endif // UNITY_DYNAMIC_TLS + +#endif // PLATFORMTHREADSPECIFICVALUE_H |