summaryrefslogtreecommitdiff
path: root/Runtime/Threads/Winapi
diff options
context:
space:
mode:
Diffstat (limited to 'Runtime/Threads/Winapi')
-rw-r--r--Runtime/Threads/Winapi/PlatformEvent.h70
-rw-r--r--Runtime/Threads/Winapi/PlatformMutex.cpp54
-rw-r--r--Runtime/Threads/Winapi/PlatformMutex.h28
-rw-r--r--Runtime/Threads/Winapi/PlatformSemaphore.h59
-rw-r--r--Runtime/Threads/Winapi/PlatformThread.cpp140
-rw-r--r--Runtime/Threads/Winapi/PlatformThread.h67
-rw-r--r--Runtime/Threads/Winapi/PlatformThreadSpecificValue.h61
7 files changed, 479 insertions, 0 deletions
diff --git a/Runtime/Threads/Winapi/PlatformEvent.h b/Runtime/Threads/Winapi/PlatformEvent.h
new file mode 100644
index 0000000..1aa590d
--- /dev/null
+++ b/Runtime/Threads/Winapi/PlatformEvent.h
@@ -0,0 +1,70 @@
+#ifndef __PLATFORMEVENT_H
+#define __PLATFORMEVENT_H
+
+// Event synchronization object.
+
+#if SUPPORT_THREADS
+
+#include "Runtime/Utilities/NonCopyable.h"
+
+class Event : public NonCopyable
+{
+public:
+ explicit Event();
+ ~Event();
+
+ void WaitForSignal();
+ void Signal();
+
+private:
+ HANDLE m_Event;
+};
+
+inline Event::Event()
+{
+#if UNITY_WINRT
+ m_Event = CreateEventExW(nullptr, nullptr, 0, 0); // ?!-
+#else
+ m_Event = CreateEvent(NULL, FALSE, FALSE, NULL);
+#endif
+}
+
+inline Event::~Event()
+{
+ if (m_Event != NULL)
+ CloseHandle(m_Event);
+}
+
+inline void Event::WaitForSignal()
+{
+#if UNITY_WINRT
+ WaitForSingleObjectEx(m_Event, INFINITE, FALSE); // ?!-
+#else
+ while (1)
+ {
+ DWORD result = WaitForSingleObjectEx(m_Event, INFINITE, TRUE);
+ switch (result)
+ {
+ case WAIT_OBJECT_0:
+ // We got the event
+ return;
+ case WAIT_IO_COMPLETION:
+ // Allow thread to run IO completion task
+ Sleep(1);
+ break;
+ default:
+ Assert (false);
+ break;
+ }
+ }
+#endif
+}
+
+inline void Event::Signal()
+{
+ SetEvent(m_Event);
+}
+
+#endif // SUPPORT_THREADS
+
+#endif // __PLATFORMEVENT_H
diff --git a/Runtime/Threads/Winapi/PlatformMutex.cpp b/Runtime/Threads/Winapi/PlatformMutex.cpp
new file mode 100644
index 0000000..3f2bd63
--- /dev/null
+++ b/Runtime/Threads/Winapi/PlatformMutex.cpp
@@ -0,0 +1,54 @@
+#include "UnityPrefix.h"
+
+#if SUPPORT_THREADS
+
+#ifndef MUTEX_API_WINAPI
+#define MUTEX_API_WINAPI (UNITY_WIN || UNITY_XENON || UNITY_WINRT)
+#endif
+
+#endif // SUPPORT_THREADS
+
+#if MUTEX_API_WINAPI
+
+#include "PlatformMutex.h"
+
+// -------------------------------------------------------------------------------------------------
+// windows
+
+// Note: TryEnterCriticalSection only exists on NT-derived systems.
+// But we do not run on Win9x currently anyway, so just accept it.
+#if !defined _WIN32_WINNT || _WIN32_WINNT < 0x0400
+extern "C" WINBASEAPI BOOL WINAPI TryEnterCriticalSection( IN OUT LPCRITICAL_SECTION lpCriticalSection );
+#endif
+
+PlatformMutex::PlatformMutex()
+{
+#if UNITY_WINRT
+ BOOL const result = InitializeCriticalSectionEx(&crit_sec, 0, CRITICAL_SECTION_NO_DEBUG_INFO);
+ Assert(FALSE != result);
+#else
+ InitializeCriticalSection( &crit_sec );
+#endif
+}
+
+PlatformMutex::~PlatformMutex ()
+{
+ DeleteCriticalSection( &crit_sec );
+}
+
+void PlatformMutex::Lock()
+{
+ EnterCriticalSection( &crit_sec );
+}
+
+void PlatformMutex::Unlock()
+{
+ LeaveCriticalSection( &crit_sec );
+}
+
+bool PlatformMutex::TryLock()
+{
+ return TryEnterCriticalSection( &crit_sec ) ? true : false;
+}
+
+#endif // MUTEX_API_WINAPI
diff --git a/Runtime/Threads/Winapi/PlatformMutex.h b/Runtime/Threads/Winapi/PlatformMutex.h
new file mode 100644
index 0000000..11f174e
--- /dev/null
+++ b/Runtime/Threads/Winapi/PlatformMutex.h
@@ -0,0 +1,28 @@
+#ifndef __PLATFORMMUTEX_H
+#define __PLATFORMMUTEX_H
+
+#if SUPPORT_THREADS
+
+#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:
+
+ CRITICAL_SECTION crit_sec;
+};
+
+#endif // SUPPORT_THREADS
+#endif // __PLATFORMMUTEX_H
diff --git a/Runtime/Threads/Winapi/PlatformSemaphore.h b/Runtime/Threads/Winapi/PlatformSemaphore.h
new file mode 100644
index 0000000..0f00f20
--- /dev/null
+++ b/Runtime/Threads/Winapi/PlatformSemaphore.h
@@ -0,0 +1,59 @@
+#ifndef __PLATFORMSEMAPHORE_H
+#define __PLATFORMSEMAPHORE_H
+
+#if SUPPORT_THREADS
+
+#include "Runtime/Utilities/NonCopyable.h"
+
+class PlatformSemaphore : public NonCopyable
+{
+ friend class Semaphore;
+protected:
+ void Create();
+ void Destroy();
+
+ void WaitForSignal();
+ void Signal();
+
+private:
+ HANDLE m_Semaphore;
+};
+
+ inline void PlatformSemaphore::Create()
+ {
+#if UNITY_WINRT
+ m_Semaphore = CreateSemaphoreExW(NULL, 0, 256, NULL, 0, (STANDARD_RIGHTS_REQUIRED | SEMAPHORE_MODIFY_STATE | SYNCHRONIZE));
+#else
+ m_Semaphore = CreateSemaphoreA( NULL, 0, 256, NULL );
+#endif
+ }
+ inline void PlatformSemaphore::Destroy(){ if( m_Semaphore ) CloseHandle(m_Semaphore); }
+ inline void PlatformSemaphore::WaitForSignal()
+ {
+#if UNITY_WINRT // ?!-
+ WaitForSingleObjectEx(m_Semaphore, INFINITE, FALSE);
+#else
+ while (1)
+ {
+ DWORD result = WaitForSingleObjectEx( m_Semaphore, INFINITE, TRUE );
+ switch (result)
+ {
+ case WAIT_OBJECT_0:
+ // We got the signal
+ return;
+ case WAIT_IO_COMPLETION:
+ // Allow thread to run IO completion task
+ Sleep(1);
+ break;
+ default:
+ Assert(false);
+ break;
+ }
+ }
+#endif
+ }
+ inline void PlatformSemaphore::Signal() { ReleaseSemaphore( m_Semaphore, 1, NULL ); }
+
+#endif // SUPPORT_THREADS
+
+#endif // __PLATFORMSEMAPHORE_H
diff --git a/Runtime/Threads/Winapi/PlatformThread.cpp b/Runtime/Threads/Winapi/PlatformThread.cpp
new file mode 100644
index 0000000..c0dd578
--- /dev/null
+++ b/Runtime/Threads/Winapi/PlatformThread.cpp
@@ -0,0 +1,140 @@
+#include "UnityPrefix.h"
+
+#if SUPPORT_THREADS
+
+#ifndef THREAD_API_WINAPI
+#define THREAD_API_WINAPI (UNITY_WIN || UNITY_XENON || UNITY_WINRT)
+#endif
+
+#endif // SUPPORT_THREADS
+
+#if THREAD_API_WINAPI
+
+#include "PlatformThread.h"
+#include "Runtime/Threads/Thread.h"
+#include "Runtime/Threads/ThreadHelper.h"
+
+#include "Runtime/Utilities/Word.h"
+
+// module@TODO : Move this to PlatformThread.h
+#if UNITY_WINRT
+#include "PlatformDependent/MetroPlayer/Win32Threads.h"
+#endif
+
+PlatformThread::PlatformThread()
+: m_Thread(NULL)
+#if !UNITY_WINRT
+, m_ThreadId(0)
+#endif
+{
+}
+
+PlatformThread::~PlatformThread()
+{
+ AssertMsg(m_Thread == NULL, "***Thread was not cleaned up!***");
+}
+
+
+void PlatformThread::Create(const Thread* thread, const UInt32 stackSize, const int processor)
+{
+#if UNITY_WINRT
+ m_Thread = win32::CreateThread(Thread::RunThreadWrapper, (LPVOID) thread);
+#else // UNITY_WINRT
+ DWORD creationFlags = 0;
+#if UNITY_XENON
+ if (processor != DEFAULT_UNITY_THREAD_PROCESSOR)
+ creationFlags = CREATE_SUSPENDED;
+#endif
+
+ m_Thread = ::CreateThread(NULL, stackSize, Thread::RunThreadWrapper, (LPVOID) thread, creationFlags, &m_ThreadId);
+ Assert(NULL != m_Thread);
+
+#if UNITY_XENON
+ if (processor != DEFAULT_UNITY_THREAD_PROCESSOR)
+ {
+ ThreadHelper::SetThreadProcessor(thread, processor);
+ ResumeThread(m_Thread);
+ }
+#endif
+
+#endif // UNITY_WINRT
+
+}
+
+void PlatformThread::Enter(const Thread* thread)
+{
+ if (thread->m_Priority != kNormalPriority)
+ UpdatePriority(thread);
+}
+
+void PlatformThread::Exit(const Thread* thread, void* result)
+{
+}
+
+void PlatformThread::Join(const Thread* thread)
+{
+#if !UNITY_WINRT // Why doesn't WINRT store the thread ID ?
+ if (Thread::EqualsCurrentThreadID(m_ThreadId))
+ {
+ ErrorStringMsg("***Thread '%s' tried to join itself!***", thread->m_Name);
+ }
+#endif
+
+ if (thread->m_Running)
+ {
+ DWORD waitResult = WaitForSingleObjectEx(m_Thread, INFINITE, FALSE);
+ Assert(WAIT_OBJECT_0 == waitResult);
+ }
+
+ if (m_Thread != NULL)
+ {
+ BOOL closeResult = CloseHandle(m_Thread);
+ Assert(FALSE != closeResult);
+ }
+ m_Thread = NULL;
+}
+
+void PlatformThread::UpdatePriority(const Thread* thread) const
+{
+ ThreadPriority p = thread->m_Priority;
+
+#if UNITY_WINRT
+
+ #pragma message("todo: implement") // ?!-
+
+#else
+
+ int iPriority;
+ switch (p)
+ {
+ case kLowPriority:
+ iPriority = THREAD_PRIORITY_LOWEST;
+ break;
+
+ case kBelowNormalPriority:
+ iPriority = THREAD_PRIORITY_BELOW_NORMAL;
+ break;
+
+ case kNormalPriority:
+ iPriority = THREAD_PRIORITY_NORMAL;
+ break;
+ case kHighPriority:
+ iPriority = THREAD_PRIORITY_HIGHEST;
+ break;
+
+ default:
+ AssertString("Undefined thread priority");
+ }
+
+ int res = SetThreadPriority(m_Thread, iPriority);
+ AssertIf(res == 0);
+
+#endif
+}
+
+PlatformThread::ThreadID PlatformThread::GetCurrentThreadID()
+{
+ return GetCurrentThreadId();
+}
+
+#endif // THREAD_API_PTHREAD
diff --git a/Runtime/Threads/Winapi/PlatformThread.h b/Runtime/Threads/Winapi/PlatformThread.h
new file mode 100644
index 0000000..289e39e
--- /dev/null
+++ b/Runtime/Threads/Winapi/PlatformThread.h
@@ -0,0 +1,67 @@
+#ifndef PLATFORMTHREAD_H
+#define PLATFORMTHREAD_H
+
+#if SUPPORT_THREADS
+
+#include "Runtime/Utilities/NonCopyable.h"
+
+class Thread;
+
+#if UNITY_XENON // module@TODO : Move to Platforms/Xenon/Include/PlatformThread.h
+#define DEFAULT_UNITY_THREAD_STACK_SIZE 128*1024
+#endif
+
+// The function signature is actually important here,
+// and on Windows it must match the signature of LPTHREAD_START_ROUTINE,
+// and no other way will be "ok".
+// It does not suffice to cast to the more "general" version, because
+// then you will run into ESP check failures sooner or later. Probably sooner.
+#define UNITY_THREAD_FUNCTION_RETURNTYPE DWORD
+#define UNITY_THREAD_FUNCTION_RETURN_SIGNATURE UNITY_THREAD_FUNCTION_RETURNTYPE WINAPI
+
+class EXPORT_COREMODULE PlatformThread : public NonCopyable
+{
+ friend class Thread;
+ friend class ThreadHelper;
+
+protected:
+ typedef DWORD 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();
+
+#if UNITY_WINRT
+
+ HANDLE m_Thread;
+
+#elif UNITY_WIN || UNITY_XENON
+
+ HANDLE m_Thread;
+ DWORD m_ThreadId;
+
+#endif
+};
+
+#endif // SUPPORT_THREADS
+
+#endif // PLATFORMTHREAD_H
diff --git a/Runtime/Threads/Winapi/PlatformThreadSpecificValue.h b/Runtime/Threads/Winapi/PlatformThreadSpecificValue.h
new file mode 100644
index 0000000..8e6d42a
--- /dev/null
+++ b/Runtime/Threads/Winapi/PlatformThreadSpecificValue.h
@@ -0,0 +1,61 @@
+#ifndef PLATFORMTHREADSPECIFICVALUE_H
+#define PLATFORMTHREADSPECIFICVALUE_H
+
+#if UNITY_DYNAMIC_TLS
+
+#if UNITY_WINRT
+#include "PlatformDependent/MetroPlayer/Win32Threads.h"
+using win32::TlsAlloc;
+using win32::TlsFree;
+using win32::TlsGetValue;
+using win32::TlsSetValue;
+#endif
+
+class PlatformThreadSpecificValue
+{
+public:
+ PlatformThreadSpecificValue();
+ ~PlatformThreadSpecificValue();
+
+ void* GetValue() const;
+ void SetValue(void* value);
+
+private:
+ DWORD m_TLSKey;
+};
+
+inline PlatformThreadSpecificValue::PlatformThreadSpecificValue ()
+{
+ m_TLSKey = TlsAlloc();
+ AssertIf( m_TLSKey == TLS_OUT_OF_INDEXES );
+}
+
+inline PlatformThreadSpecificValue::~PlatformThreadSpecificValue ()
+{
+ TlsFree( m_TLSKey );
+}
+
+inline void* PlatformThreadSpecificValue::GetValue () const
+{
+#if UNITY_WIN
+ void* result = TlsGetValue(m_TLSKey);
+ DebugAssertIf( result == NULL && GetLastError() != ERROR_SUCCESS );
+ return result;
+#elif UNITY_XENON
+ return TlsGetValue(m_TLSKey); // on XENON TlsGetValue does not call SetLastError
+#endif
+}
+
+inline void PlatformThreadSpecificValue::SetValue (void* value)
+{
+ BOOL ok = TlsSetValue( m_TLSKey, value );
+ DebugAssertIf( !ok );
+}
+
+#else
+
+ #define UNITY_TLS_VALUE(type) __declspec(thread) type
+
+#endif // UNITY_DYNAMIC_TLS
+
+#endif // PLATFORMTHREADSPECIFICVALUE_H