diff options
Diffstat (limited to 'LibOVR/Src/Kernel/OVR_ThreadsWinAPI.cpp')
-rw-r--r-- | LibOVR/Src/Kernel/OVR_ThreadsWinAPI.cpp | 1146 |
1 files changed, 0 insertions, 1146 deletions
diff --git a/LibOVR/Src/Kernel/OVR_ThreadsWinAPI.cpp b/LibOVR/Src/Kernel/OVR_ThreadsWinAPI.cpp deleted file mode 100644 index 4786435..0000000 --- a/LibOVR/Src/Kernel/OVR_ThreadsWinAPI.cpp +++ /dev/null @@ -1,1146 +0,0 @@ -/************************************************************************************
-
-Filename : OVR_ThreadsWinAPI.cpp
-Platform : WinAPI
-Content : Windows specific thread-related (safe) functionality
-Created : September 19, 2012
-Notes :
-
-Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved.
-
-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.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,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-
-************************************************************************************/
-
-#include "OVR_Threads.h"
-#include "OVR_Hash.h"
-#include "OVR_Log.h"
-#include "OVR_Timer.h"
-
-#ifdef OVR_ENABLE_THREADS
-
-// For _beginthreadex / _endtheadex
-#include <process.h>
-
-namespace OVR {
-
-
-//-----------------------------------------------------------------------------------
-// *** Internal Mutex implementation class
-
-class MutexImpl : public NewOverrideBase
-{
- // System mutex or semaphore
- HANDLE hMutexOrSemaphore;
- bool Recursive;
- volatile unsigned LockCount;
-
- friend class WaitConditionImpl;
-
-public:
- // Constructor/destructor
- MutexImpl(bool recursive = 1);
- ~MutexImpl();
-
- // Locking functions
- void DoLock();
- bool TryLock();
- void Unlock(Mutex* pmutex);
- // Returns 1 if the mutes is currently locked
- bool IsLockedByAnotherThread(Mutex* pmutex);
-};
-
-// *** Constructor/destructor
-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()
-{
- CloseHandle(hMutexOrSemaphore);
-}
-
-
-// Lock and try lock
-void MutexImpl::DoLock()
-{
- if (::WaitForSingleObject(hMutexOrSemaphore, INFINITE) != WAIT_OBJECT_0)
- return;
- LockCount++;
-}
-
-bool MutexImpl::TryLock()
-{
- DWORD ret;
- if ((ret=::WaitForSingleObject(hMutexOrSemaphore, 0)) != WAIT_OBJECT_0)
- return 0;
- LockCount++;
- return 1;
-}
-
-void MutexImpl::Unlock(Mutex* pmutex)
-{
- OVR_UNUSED(pmutex);
-
- unsigned lockCount;
- LockCount--;
- lockCount = LockCount;
-
- // Release mutex
- if ((Recursive ? ReleaseMutex(hMutexOrSemaphore) :
- ReleaseSemaphore(hMutexOrSemaphore, 1, NULL)) != 0)
- {
- // This used to call Wait handlers if lockCount == 0.
- }
-}
-
-bool MutexImpl::IsLockedByAnotherThread(Mutex* pmutex)
-{
- // There could be multiple interpretations of IsLocked with respect to current thread
- if (LockCount == 0)
- return 0;
- if (!TryLock())
- return 1;
- Unlock(pmutex);
- return 0;
-}
-
-/*
-bool MutexImpl::IsSignaled() const
-{
- // An mutex is signaled if it is not locked ANYWHERE
- // Note that this is different from IsLockedByAnotherThread function,
- // that takes current thread into account
- return LockCount == 0;
-}
-*/
-
-
-// *** Actual Mutex class implementation
-
-Mutex::Mutex(bool recursive)
-{
- pImpl = new MutexImpl(recursive);
-}
-Mutex::~Mutex()
-{
- delete pImpl;
-}
-
-// Lock and try lock
-void Mutex::DoLock()
-{
- pImpl->DoLock();
-}
-bool Mutex::TryLock()
-{
- return pImpl->TryLock();
-}
-void Mutex::Unlock()
-{
- pImpl->Unlock(this);
-}
-bool Mutex::IsLockedByAnotherThread()
-{
- return pImpl->IsLockedByAnotherThread(this);
-}
-
-//-----------------------------------------------------------------------------------
-// ***** Event
-
-bool Event::Wait(unsigned delay)
-{
- Mutex::Locker lock(&StateMutex);
-
- // Do the correct amount of waiting
- if (delay == OVR_WAIT_INFINITE)
- {
- while(!State)
- StateWaitCondition.Wait(&StateMutex);
- }
- else if (delay)
- {
- if (!State)
- StateWaitCondition.Wait(&StateMutex, delay);
- }
-
- bool state = State;
- // Take care of temporary 'pulsing' of a state
- if (Temporary)
- {
- Temporary = false;
- State = false;
- }
- return state;
-}
-
-void Event::updateState(bool newState, bool newTemp, bool mustNotify)
-{
- Mutex::Locker lock(&StateMutex);
- State = newState;
- Temporary = newTemp;
- if (mustNotify)
- StateWaitCondition.NotifyAll();
-}
-
-
-//-----------------------------------------------------------------------------------
-// ***** Win32 Wait Condition Implementation
-
-// Internal implementation class
-class WaitConditionImpl : public NewOverrideBase
-{
- // Event pool entries for extra events
- struct EventPoolEntry : public NewOverrideBase
- {
- HANDLE hEvent;
- EventPoolEntry *pNext;
- EventPoolEntry *pPrev;
- };
-
- Lock WaitQueueLoc;
- // Stores free events that can be used later
- EventPoolEntry * pFreeEventList;
-
- // A queue of waiting objects to be signaled
- EventPoolEntry* pQueueHead;
- EventPoolEntry* pQueueTail;
-
- // Allocation functions for free events
- EventPoolEntry* GetNewEvent();
- void ReleaseEvent(EventPoolEntry* pevent);
-
- // Queue operations
- void QueuePush(EventPoolEntry* pentry);
- EventPoolEntry* QueuePop();
- void QueueFindAndRemove(EventPoolEntry* pentry);
-
-public:
-
- // Constructor/destructor
- WaitConditionImpl();
- ~WaitConditionImpl();
-
- // Release mutex and wait for condition. The mutex is re-acqured after the wait.
- bool Wait(Mutex *pmutex, unsigned delay = OVR_WAIT_INFINITE);
-
- // Notify a condition, releasing at one object waiting
- void Notify();
- // Notify a condition, releasing all objects waiting
- void NotifyAll();
-};
-
-
-
-WaitConditionImpl::WaitConditionImpl()
-{
- pFreeEventList = 0;
- pQueueHead =
- pQueueTail = 0;
-}
-
-WaitConditionImpl::~WaitConditionImpl()
-{
- // Free all the resources
- EventPoolEntry* p = pFreeEventList;
- EventPoolEntry* pentry;
-
- while(p)
- {
- // Move to next
- pentry = p;
- p = p->pNext;
- // Delete old
- ::CloseHandle(pentry->hEvent);
- delete pentry;
- }
- // Shouldn't we also consider the queue?
-
- // To be safe
- pFreeEventList = 0;
- pQueueHead =
- pQueueTail = 0;
-}
-
-
-// Allocation functions for free events
-WaitConditionImpl::EventPoolEntry* WaitConditionImpl::GetNewEvent()
-{
- EventPoolEntry* pentry;
-
- // If there are any free nodes, use them
- if (pFreeEventList)
- {
- pentry = pFreeEventList;
- pFreeEventList = pFreeEventList->pNext;
- }
- else
- {
- // Allocate a new node
- pentry = new EventPoolEntry;
- pentry->pNext = 0;
- pentry->pPrev = 0;
- // Non-signaled manual event
- pentry->hEvent = ::CreateEvent(NULL, TRUE, 0, NULL);
- }
-
- return pentry;
-}
-
-void WaitConditionImpl::ReleaseEvent(EventPoolEntry* pevent)
-{
- // Mark event as non-signaled
- ::ResetEvent(pevent->hEvent);
- // And add it to free pool
- pevent->pNext = pFreeEventList;
- pevent->pPrev = 0;
- pFreeEventList = pevent;
-}
-
-// Queue operations
-void WaitConditionImpl::QueuePush(EventPoolEntry* pentry)
-{
- // Items already exist? Just add to tail
- if (pQueueTail)
- {
- pentry->pPrev = pQueueTail;
- pQueueTail->pNext = pentry;
- pentry->pNext = 0;
- pQueueTail = pentry;
- }
- else
- {
- // No items in queue
- pentry->pNext =
- pentry->pPrev = 0;
- pQueueHead =
- pQueueTail = pentry;
- }
-}
-
-WaitConditionImpl::EventPoolEntry* WaitConditionImpl::QueuePop()
-{
- EventPoolEntry* pentry = pQueueHead;
-
- // No items, null pointer
- if (pentry)
- {
- // More items after this one? just grab the first item
- if (pQueueHead->pNext)
- {
- pQueueHead = pentry->pNext;
- pQueueHead->pPrev = 0;
- }
- else
- {
- // Last item left
- pQueueTail =
- pQueueHead = 0;
- }
- }
- return pentry;
-}
-
-void WaitConditionImpl::QueueFindAndRemove(EventPoolEntry* pentry)
-{
- // Do an exhaustive search looking for an entry
- EventPoolEntry* p = pQueueHead;
-
- while(p)
- {
- // Entry found? Remove.
- if (p == pentry)
- {
-
- // Remove the node form the list
- // Prev link
- if (pentry->pPrev)
- pentry->pPrev->pNext = pentry->pNext;
- else
- pQueueHead = pentry->pNext;
- // Next link
- if (pentry->pNext)
- pentry->pNext->pPrev = pentry->pPrev;
- else
- pQueueTail = pentry->pPrev;
- // Done
- return;
- }
-
- // Move to next item
- p = p->pNext;
- }
-}
-
-
-bool WaitConditionImpl::Wait(Mutex *pmutex, unsigned delay)
-{
- bool result = 0;
- unsigned i;
- unsigned lockCount = pmutex->pImpl->LockCount;
- EventPoolEntry* pentry;
-
- // Mutex must have been locked
- if (lockCount == 0)
- return 0;
-
- // Add an object to the wait queue
- WaitQueueLoc.DoLock();
- QueuePush(pentry = GetNewEvent());
- WaitQueueLoc.Unlock();
-
- // Finally, release a mutex or semaphore
- if (pmutex->pImpl->Recursive)
- {
- // Release the recursive mutex N times
- pmutex->pImpl->LockCount = 0;
- for(i=0; i<lockCount; i++)
- ::ReleaseMutex(pmutex->pImpl->hMutexOrSemaphore);
- }
- else
- {
- pmutex->pImpl->LockCount = 0;
- ::ReleaseSemaphore(pmutex->pImpl->hMutexOrSemaphore, 1, NULL);
- }
-
- // Note that there is a gap here between mutex.Unlock() and Wait(). However,
- // if notify() comes in at this point in the other thread it will set our
- // corresponding event so wait will just fall through, as expected.
-
- // Block and wait on the event
- DWORD waitResult = ::WaitForSingleObject(pentry->hEvent,
- (delay == OVR_WAIT_INFINITE) ? INFINITE : delay);
- /*
-repeat_wait:
- DWORD waitResult =
-
- ::MsgWaitForMultipleObjects(1, &pentry->hEvent, FALSE,
- (delay == OVR_WAIT_INFINITE) ? INFINITE : delay,
- QS_ALLINPUT);
- */
-
- WaitQueueLoc.DoLock();
- switch(waitResult)
- {
- case WAIT_ABANDONED:
- case WAIT_OBJECT_0:
- result = 1;
- // Wait was successful, therefore the event entry should already be removed
- // So just add entry back to a free list
- ReleaseEvent(pentry);
- break;
- /*
- case WAIT_OBJECT_0 + 1:
- // Messages in WINDOWS queue
- {
- MSG msg;
- PeekMessage(&msg, NULL, 0U, 0U, PM_NOREMOVE);
- WaitQueueLoc.Unlock();
- goto repeat_wait;
- }
- break; */
- default:
- // Timeout, our entry should still be in a queue
- QueueFindAndRemove(pentry);
- ReleaseEvent(pentry);
- }
- WaitQueueLoc.Unlock();
-
- // Re-aquire the mutex
- for(i=0; i<lockCount; i++)
- pmutex->DoLock();
-
- // Return the result
- return result;
-}
-
-// Notify a condition, releasing the least object in a queue
-void WaitConditionImpl::Notify()
-{
- Lock::Locker lock(&WaitQueueLoc);
-
- // Pop last entry & signal it
- EventPoolEntry* pentry = QueuePop();
- if (pentry)
- ::SetEvent(pentry->hEvent);
-}
-
-// Notify a condition, releasing all objects waiting
-void WaitConditionImpl::NotifyAll()
-{
- Lock::Locker lock(&WaitQueueLoc);
-
- // Pop and signal all events
- // NOTE : There is no need to release the events, it's the waiters job to do so
- EventPoolEntry* pentry = QueuePop();
- while (pentry)
- {
- ::SetEvent(pentry->hEvent);
- pentry = QueuePop();
- }
-}
-
-
-
-// *** Actual implementation of WaitCondition
-
-WaitCondition::WaitCondition()
-{
- pImpl = new WaitConditionImpl;
-}
-WaitCondition::~WaitCondition()
-{
- delete pImpl;
-}
-
-// Wait without a mutex
-bool WaitCondition::Wait(Mutex *pmutex, unsigned delay)
-{
- return pImpl->Wait(pmutex, delay);
-}
-// Notification
-void WaitCondition::Notify()
-{
- pImpl->Notify();
-}
-void WaitCondition::NotifyAll()
-{
- pImpl->NotifyAll();
-}
-
-
-
-//-----------------------------------------------------------------------------------
-// ***** Thread Class
-
-// Per-thread variable
-// MA: Don't use TLS for now - portability issues with DLLs, etc.
-/*
-#if !defined(OVR_CC_MSVC) || (OVR_CC_MSVC < 1300)
-__declspec(thread) Thread* pCurrentThread = 0;
-#else
-#pragma data_seg(".tls$")
-__declspec(thread) Thread* pCurrentThread = 0;
-#pragma data_seg(".rwdata")
-#endif
-*/
-
-// *** Thread constructors.
-
-Thread::Thread(size_t stackSize, int processor)
-{
- CreateParams params;
- params.stackSize = stackSize;
- params.processor = processor;
- Init(params);
-}
-
-Thread::Thread(Thread::ThreadFn threadFunction, void* userHandle, size_t stackSize,
- int processor, Thread::ThreadState initialState)
-{
- CreateParams params(threadFunction, userHandle, stackSize, processor, initialState);
- Init(params);
-}
-
-Thread::Thread(const CreateParams& params)
-{
- Init(params);
-}
-void Thread::Init(const CreateParams& params)
-{
- // Clear the variables
- ThreadFlags = 0;
- ThreadHandle = 0;
- IdValue = 0;
- ExitCode = 0;
- SuspendCount = 0;
- StackSize = params.stackSize;
- Processor = params.processor;
- Priority = params.priority;
-
- // Clear Function pointers
- ThreadFunction = params.threadFunction;
- UserHandle = params.userHandle;
- if (params.initialState != NotRunning)
- Start(params.initialState);
-
-}
-
-Thread::~Thread()
-{
- // Thread should not running while object is being destroyed,
- // this would indicate ref-counting issue.
- //OVR_ASSERT(IsRunning() == 0);
-
- // Clean up thread.
- CleanupSystemThread();
- ThreadHandle = 0;
-}
-
-
-// *** Overridable User functions.
-
-// Default Run implementation
-int Thread::Run()
-{
- if (!ThreadFunction)
- return 0;
-
- int ret = ThreadFunction(this, UserHandle);
-
- return ret;
-}
-
-void Thread::OnExit()
-{
-}
-
-// Finishes the thread and releases internal reference to it.
-void Thread::FinishAndRelease()
-{
- // Note: thread must be US.
- ThreadFlags &= (uint32_t)~(OVR_THREAD_STARTED);
- ThreadFlags |= OVR_THREAD_FINISHED;
-
- // Release our reference; this is equivalent to 'delete this'
- // from the point of view of our thread.
- Release();
-}
-
-
-// *** ThreadList - used to tack all created threads
-
-class ThreadList : public NewOverrideBase
-{
- //------------------------------------------------------------------------
- struct ThreadHashOp
- {
- size_t operator()(const Thread* ptr)
- {
- return (((size_t)ptr) >> 6) ^ (size_t)ptr;
- }
- };
-
- HashSet<Thread*, ThreadHashOp> ThreadSet;
- Mutex ThreadMutex;
- WaitCondition ThreadsEmpty;
- // Track the root thread that created us.
- ThreadId RootThreadId;
-
- static ThreadList* volatile pRunningThreads;
-
- void addThread(Thread *pthread)
- {
- Mutex::Locker lock(&ThreadMutex);
- ThreadSet.Add(pthread);
- }
-
- void removeThread(Thread *pthread)
- {
- Mutex::Locker lock(&ThreadMutex);
- ThreadSet.Remove(pthread);
- if (ThreadSet.GetSize() == 0)
- ThreadsEmpty.Notify();
- }
-
- void finishAllThreads()
- {
- // Only original root thread can call this.
- OVR_ASSERT(GetCurrentThreadId() == RootThreadId);
-
- Mutex::Locker lock(&ThreadMutex);
- while (ThreadSet.GetSize() != 0)
- ThreadsEmpty.Wait(&ThreadMutex);
- }
-
-public:
-
- ThreadList()
- {
- RootThreadId = GetCurrentThreadId();
- }
- ~ThreadList() { }
-
-
- static void AddRunningThread(Thread *pthread)
- {
- // Non-atomic creation ok since only the root thread
- if (!pRunningThreads)
- {
- pRunningThreads = new ThreadList;
- OVR_ASSERT(pRunningThreads);
- }
- pRunningThreads->addThread(pthread);
- }
-
- // NOTE: 'pthread' might be a dead pointer when this is
- // called so it should not be accessed; it is only used
- // for removal.
- static void RemoveRunningThread(Thread *pthread)
- {
- OVR_ASSERT(pRunningThreads);
- pRunningThreads->removeThread(pthread);
- }
-
- static void FinishAllThreads()
- {
- // This is ok because only root thread can wait for other thread finish.
- if (pRunningThreads)
- {
- pRunningThreads->finishAllThreads();
- delete pRunningThreads;
- pRunningThreads = 0;
- }
- }
-};
-
-// By default, we have no thread list.
-ThreadList* volatile ThreadList::pRunningThreads = 0;
-
-
-// FinishAllThreads - exposed publicly in Thread.
-void Thread::FinishAllThreads()
-{
- ThreadList::FinishAllThreads();
-}
-
-
-// *** Run override
-
-int Thread::PRun()
-{
- // Suspend us on start, if requested
- if (ThreadFlags & OVR_THREAD_START_SUSPENDED)
- {
- Suspend();
- ThreadFlags &= (uint32_t)~OVR_THREAD_START_SUSPENDED;
- }
-
- // Call the virtual run function
- ExitCode = Run();
-
- return ExitCode;
-}
-
-
-
-/* MA: Don't use TLS for now.
-
-// Static function to return a pointer to the current thread
-void Thread::InitCurrentThread(Thread *pthread)
-{
- pCurrentThread = pthread;
-}
-
-// Static function to return a pointer to the current thread
-Thread* Thread::GetThread()
-{
- return pCurrentThread;
-}
-*/
-
-
-// *** User overridables
-
-bool Thread::GetExitFlag() const
-{
- return (ThreadFlags & OVR_THREAD_EXIT) != 0;
-}
-
-void Thread::SetExitFlag(bool exitFlag)
-{
- // The below is atomic since ThreadFlags is AtomicInt.
- if (exitFlag)
- ThreadFlags |= OVR_THREAD_EXIT;
- else
- ThreadFlags &= (uint32_t) ~OVR_THREAD_EXIT;
-}
-
-
-// Determines whether the thread was running and is now finished
-bool Thread::IsFinished() const
-{
- return (ThreadFlags & OVR_THREAD_FINISHED) != 0;
-}
-// Determines whether the thread is suspended
-bool Thread::IsSuspended() const
-{
- return SuspendCount > 0;
-}
-// Returns current thread state
-Thread::ThreadState Thread::GetThreadState() const
-{
- if (IsSuspended())
- return Suspended;
- if (ThreadFlags & OVR_THREAD_STARTED)
- 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
-/* static */
-int Thread::GetOSPriority(ThreadPriority p)
-{
- switch(p)
- {
- // 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)
- {
- DWORD_PTR ret = SetThreadAffinityMask(GetCurrentThread(), (DWORD)pthread->Processor);
- if (ret == 0)
- OVR_DEBUG_LOG(("Could not set hardware processor for the thread"));
- }
- BOOL ret = ::SetThreadPriority(GetCurrentThread(), Thread::GetOSPriority(pthread->Priority));
- if (ret == 0)
- OVR_DEBUG_LOG(("Could not set thread priority"));
- OVR_UNUSED(ret);
-
- // Ensure that ThreadId is assigned once thread is running, in case
- // beginthread hasn't filled it in yet.
- pthread->IdValue = (ThreadId)::GetCurrentThreadId();
-
- DWORD result = pthread->PRun();
- // Signal the thread as done and release it atomically.
- pthread->FinishAndRelease();
- // At this point Thread object might be dead; however we can still pass
- // it to RemoveRunningThread since it is only used as a key there.
- ThreadList::RemoveRunningThread(pthread);
- return (unsigned) result;
-}
-
-bool Thread::Start(ThreadState initialState)
-{
- if (initialState == NotRunning)
- return 0;
- if (GetThreadState() != NotRunning)
- {
- OVR_DEBUG_LOG(("Thread::Start failed - thread %p already running", this));
- return 0;
- }
-
- // Free old thread handle before creating the new one
- CleanupSystemThread();
-
- // AddRef to us until the thread is finished.
- AddRef();
- ThreadList::AddRunningThread(this);
-
- 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)
- {
- ThreadFlags = 0;
- Release();
- ThreadList::RemoveRunningThread(this);
- return 0;
- }
- return 1;
-}
-
-
-// Suspend the thread until resumed
-bool Thread::Suspend()
-{
- // Can't suspend a thread that wasn't started
- if (!(ThreadFlags & OVR_THREAD_STARTED))
- return 0;
-
- if (::SuspendThread(ThreadHandle) != 0xFFFFFFFF)
- {
- SuspendCount++;
- return 1;
- }
- return 0;
-}
-
-// Resumes currently suspended thread
-bool Thread::Resume()
-{
- // Can't suspend a thread that wasn't started
- if (!(ThreadFlags & OVR_THREAD_STARTED))
- return 0;
-
- // Decrement count, and resume thread if it is 0
- int32_t oldCount = SuspendCount.ExchangeAdd_Acquire(-1);
- if (oldCount >= 1)
- {
- if (oldCount == 1)
- {
- if (::ResumeThread(ThreadHandle) != 0xFFFFFFFF)
- {
- return 1;
- }
- }
- else
- {
- return 1;
- }
- }
- return 0;
-}
-
-
-// Quits with an exit code
-void Thread::Exit(int exitCode)
-{
- // Can only exist the current thread.
- // MA: Don't use TLS for now.
- //if (GetThread() != this)
- // return;
-
- // Call the virtual OnExit function.
- OnExit();
-
- // Signal this thread object as done and release it's references.
- FinishAndRelease();
- ThreadList::RemoveRunningThread(this);
-
- // 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
-}
-
-
-void Thread::CleanupSystemThread()
-{
- if (ThreadHandle != 0)
- {
- ::CloseHandle(ThreadHandle);
- ThreadHandle = 0;
- }
-}
-
-// *** Sleep functions
-// static
-bool Thread::Sleep(unsigned secs)
-{
- ::Sleep(secs*1000);
- return 1;
-}
-
-// static
-bool Thread::MSleep(unsigned msecs)
-{
- ::Sleep(msecs);
- return 1;
-}
-
-
-
-void Thread::SetThreadName( const char* name )
-{
- 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.
-}
-
-
-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
-}
-
-
-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;
-
- #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;
-}
-
-// Returns the unique Id of a thread it is called on, intended for
-// comparison purposes.
-ThreadId GetCurrentThreadId()
-{
- return (ThreadId)::GetCurrentThreadId();
-}
-
-} // OVR
-
-#endif
|