aboutsummaryrefslogtreecommitdiffstats
path: root/LibOVR/Src/Kernel/OVR_ThreadsWinAPI.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'LibOVR/Src/Kernel/OVR_ThreadsWinAPI.cpp')
-rw-r--r--LibOVR/Src/Kernel/OVR_ThreadsWinAPI.cpp247
1 files changed, 194 insertions, 53 deletions
diff --git a/LibOVR/Src/Kernel/OVR_ThreadsWinAPI.cpp b/LibOVR/Src/Kernel/OVR_ThreadsWinAPI.cpp
index 91a5e31..4786435 100644
--- a/LibOVR/Src/Kernel/OVR_ThreadsWinAPI.cpp
+++ b/LibOVR/Src/Kernel/OVR_ThreadsWinAPI.cpp
@@ -6,16 +6,16 @@ Content : Windows specific thread-related (safe) functionality
Created : September 19, 2012
Notes :
-Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
+Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved.
-Licensed under the Oculus VR Rift SDK License Version 3.1 (the "License");
+Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License");
you may not use the Oculus VR Rift SDK except in compliance with the License,
which is provided at the time of installation or download, or which
otherwise accompanies this software in either electronic or hard copy form.
You may obtain a copy of the License at
-http://www.oculusvr.com/licenses/LICENSE-3.1
+http://www.oculusvr.com/licenses/LICENSE-3.2
Unless required by applicable law or agreed to in writing, the Oculus VR SDK
distributed under the License is distributed on an "AS IS" BASIS,
@@ -28,6 +28,7 @@ limitations under the License.
#include "OVR_Threads.h"
#include "OVR_Hash.h"
#include "OVR_Log.h"
+#include "OVR_Timer.h"
#ifdef OVR_ENABLE_THREADS
@@ -67,7 +68,12 @@ MutexImpl::MutexImpl(bool recursive)
{
Recursive = recursive;
LockCount = 0;
+#if defined(OVR_OS_WIN32) // Older versions of Windows don't support CreateSemaphoreEx, so stick with CreateSemaphore for portability.
hMutexOrSemaphore = Recursive ? CreateMutex(NULL, 0, NULL) : CreateSemaphore(NULL, 1, 1, NULL);
+#else
+ // No CreateSemaphore() call, so emulate it.
+ hMutexOrSemaphore = Recursive ? CreateMutex(NULL, 0, NULL) : CreateSemaphoreEx(NULL, 1, 1, NULL, 0, SEMAPHORE_ALL_ACCESS);
+#endif
}
MutexImpl::~MutexImpl()
{
@@ -541,7 +547,7 @@ __declspec(thread) Thread* pCurrentThread = 0;
// *** Thread constructors.
-Thread::Thread(UPInt stackSize, int processor)
+Thread::Thread(size_t stackSize, int processor)
{
CreateParams params;
params.stackSize = stackSize;
@@ -549,7 +555,7 @@ Thread::Thread(UPInt stackSize, int processor)
Init(params);
}
-Thread::Thread(Thread::ThreadFn threadFunction, void* userHandle, UPInt stackSize,
+Thread::Thread(Thread::ThreadFn threadFunction, void* userHandle, size_t stackSize,
int processor, Thread::ThreadState initialState)
{
CreateParams params(threadFunction, userHandle, stackSize, processor, initialState);
@@ -597,9 +603,14 @@ Thread::~Thread()
// Default Run implementation
int Thread::Run()
{
- // Call pointer to function, if available.
- return (ThreadFunction) ? ThreadFunction(this, UserHandle) : 0;
+ if (!ThreadFunction)
+ return 0;
+
+ int ret = ThreadFunction(this, UserHandle);
+
+ return ret;
}
+
void Thread::OnExit()
{
}
@@ -608,7 +619,7 @@ void Thread::OnExit()
void Thread::FinishAndRelease()
{
// Note: thread must be US.
- ThreadFlags &= (UInt32)~(OVR_THREAD_STARTED);
+ ThreadFlags &= (uint32_t)~(OVR_THREAD_STARTED);
ThreadFlags |= OVR_THREAD_FINISHED;
// Release our reference; this is equivalent to 'delete this'
@@ -624,9 +635,9 @@ class ThreadList : public NewOverrideBase
//------------------------------------------------------------------------
struct ThreadHashOp
{
- UPInt operator()(const Thread* ptr)
+ size_t operator()(const Thread* ptr)
{
- return (((UPInt)ptr) >> 6) ^ (UPInt)ptr;
+ return (((size_t)ptr) >> 6) ^ (size_t)ptr;
}
};
@@ -722,11 +733,12 @@ int Thread::PRun()
if (ThreadFlags & OVR_THREAD_START_SUSPENDED)
{
Suspend();
- ThreadFlags &= (UInt32)~OVR_THREAD_START_SUSPENDED;
+ ThreadFlags &= (uint32_t)~OVR_THREAD_START_SUSPENDED;
}
// Call the virtual run function
ExitCode = Run();
+
return ExitCode;
}
@@ -761,7 +773,7 @@ void Thread::SetExitFlag(bool exitFlag)
if (exitFlag)
ThreadFlags |= OVR_THREAD_EXIT;
else
- ThreadFlags &= (UInt32) ~OVR_THREAD_EXIT;
+ ThreadFlags &= (uint32_t) ~OVR_THREAD_EXIT;
}
@@ -779,12 +791,39 @@ bool Thread::IsSuspended() const
Thread::ThreadState Thread::GetThreadState() const
{
if (IsSuspended())
- return Suspended;
+ return Suspended;
if (ThreadFlags & OVR_THREAD_STARTED)
- return Running;
+ return Running;
return NotRunning;
}
+// Join thread
+bool Thread::Join(int maxWaitMs) const
+{
+ // If polling,
+ if (maxWaitMs == 0)
+ {
+ // Just return if finished
+ return IsFinished();
+ }
+ // If waiting forever,
+ else if (maxWaitMs > 0)
+ {
+ // Try waiting once
+ WaitForSingleObject(ThreadHandle, maxWaitMs);
+ // Return if the wait succeeded
+ return IsFinished();
+ }
+
+ // While not finished,
+ while (!IsFinished())
+ {
+ // Wait for the thread handle to signal
+ WaitForSingleObject(ThreadHandle, INFINITE);
+ }
+
+ return true;
+}
// ***** Thread management
@@ -793,19 +832,79 @@ int Thread::GetOSPriority(ThreadPriority p)
{
switch(p)
{
- case Thread::CriticalPriority: return THREAD_PRIORITY_TIME_CRITICAL;
- case Thread::HighestPriority: return THREAD_PRIORITY_HIGHEST;
- case Thread::AboveNormalPriority: return THREAD_PRIORITY_ABOVE_NORMAL;
- case Thread::NormalPriority: return THREAD_PRIORITY_NORMAL;
- case Thread::BelowNormalPriority: return THREAD_PRIORITY_BELOW_NORMAL;
- case Thread::LowestPriority: return THREAD_PRIORITY_LOWEST;
- case Thread::IdlePriority: return THREAD_PRIORITY_IDLE;
+ // If the process is REALTIME_PRIORITY_CLASS then it could have priority values 3 through14 and -3 through -14.
+ case Thread::CriticalPriority: return THREAD_PRIORITY_TIME_CRITICAL; // 15
+ case Thread::HighestPriority: return THREAD_PRIORITY_HIGHEST; // 2
+ case Thread::AboveNormalPriority: return THREAD_PRIORITY_ABOVE_NORMAL; // 1
+ case Thread::NormalPriority: return THREAD_PRIORITY_NORMAL; // 0
+ case Thread::BelowNormalPriority: return THREAD_PRIORITY_BELOW_NORMAL; // -1
+ case Thread::LowestPriority: return THREAD_PRIORITY_LOWEST; // -2
+ case Thread::IdlePriority: return THREAD_PRIORITY_IDLE; // -15
}
return THREAD_PRIORITY_NORMAL;
}
+/* static */
+Thread::ThreadPriority Thread::GetOVRPriority(int osPriority)
+{
+ // If the process is REALTIME_PRIORITY_CLASS then it could have priority values 3 through14 and -3 through -14.
+ // As a result, it's possible for those cases that an unknown/invalid ThreadPriority enum be returned. However,
+ // in practice we don't expect to be using such processes.
+
+ // The ThreadPriority types aren't linearly distributed, so we need to check for some values explicitly.
+ if(osPriority == THREAD_PRIORITY_TIME_CRITICAL)
+ return Thread::CriticalPriority;
+ if(osPriority == THREAD_PRIORITY_IDLE)
+ return Thread::IdlePriority;
+ return (ThreadPriority)(Thread::NormalPriority - osPriority);
+}
+
+Thread::ThreadPriority Thread::GetPriority()
+{
+ int osPriority = ::GetThreadPriority(ThreadHandle);
+
+ if(osPriority != THREAD_PRIORITY_ERROR_RETURN)
+ {
+ return GetOVRPriority(osPriority);
+ }
+
+ return NormalPriority;
+}
+
+/* static */
+Thread::ThreadPriority Thread::GetCurrentPriority()
+{
+ int osPriority = ::GetThreadPriority(::GetCurrentThread());
+
+ if(osPriority != THREAD_PRIORITY_ERROR_RETURN)
+ {
+ return GetOVRPriority(osPriority);
+ }
+
+ return NormalPriority;
+}
+
+bool Thread::SetPriority(ThreadPriority p)
+{
+ BOOL ret = ::SetThreadPriority(ThreadHandle, Thread::GetOSPriority(p));
+ return (ret != FALSE);
+}
+
+/* static */
+bool Thread::SetCurrentPriority(ThreadPriority p)
+{
+ BOOL ret = ::SetThreadPriority(::GetCurrentThread(), Thread::GetOSPriority(p));
+ return (ret != FALSE);
+}
+
+
+
// The actual first function called on thread start
+#if defined(OVR_OS_WIN32)
unsigned WINAPI Thread_Win32StartFn(void * phandle)
+#else // Other Micorosft OSs...
+DWORD WINAPI Thread_Win32StartFn(void *phandle)
+#endif
{
Thread * pthread = (Thread*)phandle;
if (pthread->Processor != -1)
@@ -852,8 +951,15 @@ bool Thread::Start(ThreadState initialState)
ExitCode = 0;
SuspendCount = 0;
ThreadFlags = (initialState == Running) ? 0 : OVR_THREAD_START_SUSPENDED;
+#if defined(OVR_OS_WIN32)
ThreadHandle = (HANDLE) _beginthreadex(0, (unsigned)StackSize,
Thread_Win32StartFn, this, 0, (unsigned*)&IdValue);
+#else // Other Micorosft OSs...
+ DWORD TheThreadId;
+ ThreadHandle = CreateThread(0, (unsigned)StackSize,
+ Thread_Win32StartFn, this, 0, &TheThreadId);
+ IdValue = (ThreadId)TheThreadId;
+#endif
// Failed? Fail the function
if (ThreadHandle == 0)
@@ -890,13 +996,15 @@ bool Thread::Resume()
return 0;
// Decrement count, and resume thread if it is 0
- SInt32 oldCount = SuspendCount.ExchangeAdd_Acquire(-1);
+ int32_t oldCount = SuspendCount.ExchangeAdd_Acquire(-1);
if (oldCount >= 1)
{
if (oldCount == 1)
{
- if (::ResumeThread(ThreadHandle) != 0xFFFFFFFF)
- return 1;
+ if (::ResumeThread(ThreadHandle) != 0xFFFFFFFF)
+ {
+ return 1;
+ }
}
else
{
@@ -922,8 +1030,12 @@ void Thread::Exit(int exitCode)
FinishAndRelease();
ThreadList::RemoveRunningThread(this);
- // Call the exit function.
+ // Call the exit function.
+#if defined(OVR_OS_WIN32) // _endthreadex doesn't exist on other Microsoft OSs and instead we need to call ExitThread directly.
_endthreadex((unsigned)exitCode);
+#else
+ ExitThread((unsigned)exitCode);
+#endif
}
@@ -951,43 +1063,74 @@ bool Thread::MSleep(unsigned msecs)
return 1;
}
+
+
void Thread::SetThreadName( const char* name )
{
-#if !defined(OVR_BUILD_SHIPPING) || defined(OVR_BUILD_PROFILING)
- // Looks ugly, but it is the recommended way to name a thread.
- typedef struct tagTHREADNAME_INFO {
- DWORD dwType; // Must be 0x1000
- LPCSTR szName; // Pointer to name (in user address space)
- DWORD dwThreadID; // Thread ID (-1 for caller thread)
- DWORD dwFlags; // Reserved for future use; must be zero
- } THREADNAME_INFO;
+ if(IdValue)
+ SetThreadName(name, IdValue);
+ // Else we don't know what thread to name. We can save the name and wait until the thread is created.
+}
- THREADNAME_INFO info;
- info.dwType = 0x1000;
- info.szName = name;
- info.dwThreadID = reinterpret_cast<DWORD>(GetThreadId());
- info.dwFlags = 0;
+void Thread::SetThreadName(const char* name, ThreadId threadId)
+{
+ #if !defined(OVR_BUILD_SHIPPING) || defined(OVR_BUILD_PROFILING)
+ // http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
+ #pragma pack(push,8)
+ struct THREADNAME_INFO {
+ DWORD dwType; // Must be 0x1000
+ LPCSTR szName; // Pointer to name (in user address space)
+ DWORD dwThreadID; // Thread ID (-1 for caller thread)
+ DWORD dwFlags; // Reserved for future use; must be zero
+ };
+ #pragma pack(pop)
+
+ THREADNAME_INFO info = { 0x1000, name, (DWORD)threadId, 0 };
+
+ __try
+ {
+ RaiseException( 0x406D1388, 0, sizeof(info)/sizeof(ULONG_PTR), reinterpret_cast<ULONG_PTR*>(&info));
+ }
+ __except( GetExceptionCode()==0x406D1388 ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_EXECUTE_HANDLER )
+ {
+ return;
+ }
+ #endif // OVR_BUILD_SHIPPING
+}
- __try
- {
-#ifdef _WIN64
- RaiseException( 0x406D1388, 0, sizeof(info)/sizeof(DWORD), (const ULONG_PTR *)&info );
-#else
- RaiseException( 0x406D1388, 0, sizeof(info)/sizeof(DWORD), (DWORD *)&info );
-#endif
- }
- __except( GetExceptionCode()==0x406D1388 ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_EXECUTE_HANDLER )
- {
- }
-#endif // OVR_BUILD_SHIPPING
+
+void Thread::SetCurrentThreadName( const char* name )
+{
+ SetThreadName(name, (ThreadId)::GetCurrentThreadId());
+}
+
+
+void Thread::GetThreadName(char* name, size_t /*nameCapacity*/, ThreadId /*threadId*/)
+{
+ // Not possible on Windows.
+ name[0] = 0;
+}
+
+
+void Thread::GetCurrentThreadName(char* name, size_t /*nameCapacity*/)
+{
+ // Not possible on Windows.
+ name[0] = 0;
}
+
// static
int Thread::GetCPUCount()
{
SYSTEM_INFO sysInfo;
- GetSystemInfo(&sysInfo);
+
+ #if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) // GetNativeSystemInfo requires WinXP+ and a corresponding SDK (0x0501) or later.
+ GetNativeSystemInfo(&sysInfo);
+ #else
+ GetSystemInfo(&sysInfo);
+ #endif
+
return (int) sysInfo.dwNumberOfProcessors;
}
@@ -1001,5 +1144,3 @@ ThreadId GetCurrentThreadId()
} // OVR
#endif
-
-