diff options
Diffstat (limited to 'Runtime/Threads/Winapi')
-rw-r--r-- | Runtime/Threads/Winapi/PlatformEvent.h | 70 | ||||
-rw-r--r-- | Runtime/Threads/Winapi/PlatformMutex.cpp | 54 | ||||
-rw-r--r-- | Runtime/Threads/Winapi/PlatformMutex.h | 28 | ||||
-rw-r--r-- | Runtime/Threads/Winapi/PlatformSemaphore.h | 59 | ||||
-rw-r--r-- | Runtime/Threads/Winapi/PlatformThread.cpp | 140 | ||||
-rw-r--r-- | Runtime/Threads/Winapi/PlatformThread.h | 67 | ||||
-rw-r--r-- | Runtime/Threads/Winapi/PlatformThreadSpecificValue.h | 61 |
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 |