summaryrefslogtreecommitdiff
path: root/Runtime/Threads/Posix
diff options
context:
space:
mode:
Diffstat (limited to 'Runtime/Threads/Posix')
-rw-r--r--Runtime/Threads/Posix/PlatformMutex.cpp51
-rw-r--r--Runtime/Threads/Posix/PlatformMutex.h29
-rw-r--r--Runtime/Threads/Posix/PlatformSemaphore.h69
-rw-r--r--Runtime/Threads/Posix/PlatformThread.cpp185
-rw-r--r--Runtime/Threads/Posix/PlatformThread.h56
-rw-r--r--Runtime/Threads/Posix/PlatformThreadSpecificValue.h63
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, &param) == 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, &param));
+#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, &param));
+ }
+
+#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