oculus1
view libovr/Src/win32/OVR_ThreadsWinAPI.cpp @ 29:9a973ef0e2a3
fixed the performance issue under MacOSX by replacing glutSolidTeapot (which
uses glEvalMesh) with my own teapot generator.
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sun, 27 Oct 2013 06:31:18 +0200 |
parents | e2f9e4603129 |
children |
line source
1 /************************************************************************************
3 Filename : OVR_ThreadsWinAPI.cpp
4 Platform : WinAPI
5 Content : Windows specific thread-related (safe) functionality
6 Created : September 19, 2012
7 Notes :
9 Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
11 Use of this software is subject to the terms of the Oculus license
12 agreement provided at the time of installation or download, or which
13 otherwise accompanies this software in either electronic or hard copy form.
15 ************************************************************************************/
17 #include "OVR_Threads.h"
18 #include "OVR_Hash.h"
19 #include "OVR_Log.h"
21 #ifdef OVR_ENABLE_THREADS
23 // For _beginthreadex / _endtheadex
24 #include <process.h>
26 namespace OVR {
29 //-----------------------------------------------------------------------------------
30 // *** Internal Mutex implementation class
32 class MutexImpl : public NewOverrideBase
33 {
34 // System mutex or semaphore
35 HANDLE hMutexOrSemaphore;
36 bool Recursive;
37 volatile unsigned LockCount;
39 friend class WaitConditionImpl;
41 public:
42 // Constructor/destructor
43 MutexImpl(bool recursive = 1);
44 ~MutexImpl();
46 // Locking functions
47 void DoLock();
48 bool TryLock();
49 void Unlock(Mutex* pmutex);
50 // Returns 1 if the mutes is currently locked
51 bool IsLockedByAnotherThread(Mutex* pmutex);
52 };
54 // *** Constructor/destructor
55 MutexImpl::MutexImpl(bool recursive)
56 {
57 Recursive = recursive;
58 LockCount = 0;
59 hMutexOrSemaphore = Recursive ? CreateMutex(NULL, 0, NULL) : CreateSemaphore(NULL, 1, 1, NULL);
60 }
61 MutexImpl::~MutexImpl()
62 {
63 CloseHandle(hMutexOrSemaphore);
64 }
67 // Lock and try lock
68 void MutexImpl::DoLock()
69 {
70 if (::WaitForSingleObject(hMutexOrSemaphore, INFINITE) != WAIT_OBJECT_0)
71 return;
72 LockCount++;
73 }
75 bool MutexImpl::TryLock()
76 {
77 DWORD ret;
78 if ((ret=::WaitForSingleObject(hMutexOrSemaphore, 0)) != WAIT_OBJECT_0)
79 return 0;
80 LockCount++;
81 return 1;
82 }
84 void MutexImpl::Unlock(Mutex* pmutex)
85 {
86 OVR_UNUSED(pmutex);
88 unsigned lockCount;
89 LockCount--;
90 lockCount = LockCount;
92 // Release mutex
93 if ((Recursive ? ReleaseMutex(hMutexOrSemaphore) :
94 ReleaseSemaphore(hMutexOrSemaphore, 1, NULL)) != 0)
95 {
96 // This used to call Wait handlers if lockCount == 0.
97 }
98 }
100 bool MutexImpl::IsLockedByAnotherThread(Mutex* pmutex)
101 {
102 // There could be multiple interpretations of IsLocked with respect to current thread
103 if (LockCount == 0)
104 return 0;
105 if (!TryLock())
106 return 1;
107 Unlock(pmutex);
108 return 0;
109 }
111 /*
112 bool MutexImpl::IsSignaled() const
113 {
114 // An mutex is signaled if it is not locked ANYWHERE
115 // Note that this is different from IsLockedByAnotherThread function,
116 // that takes current thread into account
117 return LockCount == 0;
118 }
119 */
122 // *** Actual Mutex class implementation
124 Mutex::Mutex(bool recursive)
125 {
126 pImpl = new MutexImpl(recursive);
127 }
128 Mutex::~Mutex()
129 {
130 delete pImpl;
131 }
133 // Lock and try lock
134 void Mutex::DoLock()
135 {
136 pImpl->DoLock();
137 }
138 bool Mutex::TryLock()
139 {
140 return pImpl->TryLock();
141 }
142 void Mutex::Unlock()
143 {
144 pImpl->Unlock(this);
145 }
146 bool Mutex::IsLockedByAnotherThread()
147 {
148 return pImpl->IsLockedByAnotherThread(this);
149 }
151 //-----------------------------------------------------------------------------------
152 // ***** Event
154 bool Event::Wait(unsigned delay)
155 {
156 Mutex::Locker lock(&StateMutex);
158 // Do the correct amount of waiting
159 if (delay == OVR_WAIT_INFINITE)
160 {
161 while(!State)
162 StateWaitCondition.Wait(&StateMutex);
163 }
164 else if (delay)
165 {
166 if (!State)
167 StateWaitCondition.Wait(&StateMutex, delay);
168 }
170 bool state = State;
171 // Take care of temporary 'pulsing' of a state
172 if (Temporary)
173 {
174 Temporary = false;
175 State = false;
176 }
177 return state;
178 }
180 void Event::updateState(bool newState, bool newTemp, bool mustNotify)
181 {
182 Mutex::Locker lock(&StateMutex);
183 State = newState;
184 Temporary = newTemp;
185 if (mustNotify)
186 StateWaitCondition.NotifyAll();
187 }
190 //-----------------------------------------------------------------------------------
191 // ***** Win32 Wait Condition Implementation
193 // Internal implementation class
194 class WaitConditionImpl : public NewOverrideBase
195 {
196 // Event pool entries for extra events
197 struct EventPoolEntry : public NewOverrideBase
198 {
199 HANDLE hEvent;
200 EventPoolEntry *pNext;
201 EventPoolEntry *pPrev;
202 };
204 Lock WaitQueueLoc;
205 // Stores free events that can be used later
206 EventPoolEntry * pFreeEventList;
208 // A queue of waiting objects to be signaled
209 EventPoolEntry* pQueueHead;
210 EventPoolEntry* pQueueTail;
212 // Allocation functions for free events
213 EventPoolEntry* GetNewEvent();
214 void ReleaseEvent(EventPoolEntry* pevent);
216 // Queue operations
217 void QueuePush(EventPoolEntry* pentry);
218 EventPoolEntry* QueuePop();
219 void QueueFindAndRemove(EventPoolEntry* pentry);
221 public:
223 // Constructor/destructor
224 WaitConditionImpl();
225 ~WaitConditionImpl();
227 // Release mutex and wait for condition. The mutex is re-acqured after the wait.
228 bool Wait(Mutex *pmutex, unsigned delay = OVR_WAIT_INFINITE);
230 // Notify a condition, releasing at one object waiting
231 void Notify();
232 // Notify a condition, releasing all objects waiting
233 void NotifyAll();
234 };
238 WaitConditionImpl::WaitConditionImpl()
239 {
240 pFreeEventList = 0;
241 pQueueHead =
242 pQueueTail = 0;
243 }
245 WaitConditionImpl::~WaitConditionImpl()
246 {
247 // Free all the resources
248 EventPoolEntry* p = pFreeEventList;
249 EventPoolEntry* pentry;
251 while(p)
252 {
253 // Move to next
254 pentry = p;
255 p = p->pNext;
256 // Delete old
257 ::CloseHandle(pentry->hEvent);
258 delete pentry;
259 }
260 // Shouldn't we also consider the queue?
262 // To be safe
263 pFreeEventList = 0;
264 pQueueHead =
265 pQueueTail = 0;
266 }
269 // Allocation functions for free events
270 WaitConditionImpl::EventPoolEntry* WaitConditionImpl::GetNewEvent()
271 {
272 EventPoolEntry* pentry;
274 // If there are any free nodes, use them
275 if (pFreeEventList)
276 {
277 pentry = pFreeEventList;
278 pFreeEventList = pFreeEventList->pNext;
279 }
280 else
281 {
282 // Allocate a new node
283 pentry = new EventPoolEntry;
284 pentry->pNext = 0;
285 pentry->pPrev = 0;
286 // Non-signaled manual event
287 pentry->hEvent = ::CreateEvent(NULL, TRUE, 0, NULL);
288 }
290 return pentry;
291 }
293 void WaitConditionImpl::ReleaseEvent(EventPoolEntry* pevent)
294 {
295 // Mark event as non-signaled
296 ::ResetEvent(pevent->hEvent);
297 // And add it to free pool
298 pevent->pNext = pFreeEventList;
299 pevent->pPrev = 0;
300 pFreeEventList = pevent;
301 }
303 // Queue operations
304 void WaitConditionImpl::QueuePush(EventPoolEntry* pentry)
305 {
306 // Items already exist? Just add to tail
307 if (pQueueTail)
308 {
309 pentry->pPrev = pQueueTail;
310 pQueueTail->pNext = pentry;
311 pentry->pNext = 0;
312 pQueueTail = pentry;
313 }
314 else
315 {
316 // No items in queue
317 pentry->pNext =
318 pentry->pPrev = 0;
319 pQueueHead =
320 pQueueTail = pentry;
321 }
322 }
324 WaitConditionImpl::EventPoolEntry* WaitConditionImpl::QueuePop()
325 {
326 EventPoolEntry* pentry = pQueueHead;
328 // No items, null pointer
329 if (pentry)
330 {
331 // More items after this one? just grab the first item
332 if (pQueueHead->pNext)
333 {
334 pQueueHead = pentry->pNext;
335 pQueueHead->pPrev = 0;
336 }
337 else
338 {
339 // Last item left
340 pQueueTail =
341 pQueueHead = 0;
342 }
343 }
344 return pentry;
345 }
347 void WaitConditionImpl::QueueFindAndRemove(EventPoolEntry* pentry)
348 {
349 // Do an exhaustive search looking for an entry
350 EventPoolEntry* p = pQueueHead;
352 while(p)
353 {
354 // Entry found? Remove.
355 if (p == pentry)
356 {
358 // Remove the node form the list
359 // Prev link
360 if (pentry->pPrev)
361 pentry->pPrev->pNext = pentry->pNext;
362 else
363 pQueueHead = pentry->pNext;
364 // Next link
365 if (pentry->pNext)
366 pentry->pNext->pPrev = pentry->pPrev;
367 else
368 pQueueTail = pentry->pPrev;
369 // Done
370 return;
371 }
373 // Move to next item
374 p = p->pNext;
375 }
376 }
379 bool WaitConditionImpl::Wait(Mutex *pmutex, unsigned delay)
380 {
381 bool result = 0;
382 unsigned i;
383 unsigned lockCount = pmutex->pImpl->LockCount;
384 EventPoolEntry* pentry;
386 // Mutex must have been locked
387 if (lockCount == 0)
388 return 0;
390 // Add an object to the wait queue
391 WaitQueueLoc.DoLock();
392 QueuePush(pentry = GetNewEvent());
393 WaitQueueLoc.Unlock();
395 // Finally, release a mutex or semaphore
396 if (pmutex->pImpl->Recursive)
397 {
398 // Release the recursive mutex N times
399 pmutex->pImpl->LockCount = 0;
400 for(i=0; i<lockCount; i++)
401 ::ReleaseMutex(pmutex->pImpl->hMutexOrSemaphore);
402 }
403 else
404 {
405 pmutex->pImpl->LockCount = 0;
406 ::ReleaseSemaphore(pmutex->pImpl->hMutexOrSemaphore, 1, NULL);
407 }
409 // Note that there is a gap here between mutex.Unlock() and Wait(). However,
410 // if notify() comes in at this point in the other thread it will set our
411 // corresponding event so wait will just fall through, as expected.
413 // Block and wait on the event
414 DWORD waitResult = ::WaitForSingleObject(pentry->hEvent,
415 (delay == OVR_WAIT_INFINITE) ? INFINITE : delay);
416 /*
417 repeat_wait:
418 DWORD waitResult =
420 ::MsgWaitForMultipleObjects(1, &pentry->hEvent, FALSE,
421 (delay == OVR_WAIT_INFINITE) ? INFINITE : delay,
422 QS_ALLINPUT);
423 */
425 WaitQueueLoc.DoLock();
426 switch(waitResult)
427 {
428 case WAIT_ABANDONED:
429 case WAIT_OBJECT_0:
430 result = 1;
431 // Wait was successful, therefore the event entry should already be removed
432 // So just add entry back to a free list
433 ReleaseEvent(pentry);
434 break;
435 /*
436 case WAIT_OBJECT_0 + 1:
437 // Messages in WINDOWS queue
438 {
439 MSG msg;
440 PeekMessage(&msg, NULL, 0U, 0U, PM_NOREMOVE);
441 WaitQueueLoc.Unlock();
442 goto repeat_wait;
443 }
444 break; */
445 default:
446 // Timeout, our entry should still be in a queue
447 QueueFindAndRemove(pentry);
448 ReleaseEvent(pentry);
449 }
450 WaitQueueLoc.Unlock();
452 // Re-aquire the mutex
453 for(i=0; i<lockCount; i++)
454 pmutex->DoLock();
456 // Return the result
457 return result;
458 }
460 // Notify a condition, releasing the least object in a queue
461 void WaitConditionImpl::Notify()
462 {
463 Lock::Locker lock(&WaitQueueLoc);
465 // Pop last entry & signal it
466 EventPoolEntry* pentry = QueuePop();
467 if (pentry)
468 ::SetEvent(pentry->hEvent);
469 }
471 // Notify a condition, releasing all objects waiting
472 void WaitConditionImpl::NotifyAll()
473 {
474 Lock::Locker lock(&WaitQueueLoc);
476 // Pop and signal all events
477 // NOTE : There is no need to release the events, it's the waiters job to do so
478 EventPoolEntry* pentry = QueuePop();
479 while (pentry)
480 {
481 ::SetEvent(pentry->hEvent);
482 pentry = QueuePop();
483 }
484 }
488 // *** Actual implementation of WaitCondition
490 WaitCondition::WaitCondition()
491 {
492 pImpl = new WaitConditionImpl;
493 }
494 WaitCondition::~WaitCondition()
495 {
496 delete pImpl;
497 }
499 // Wait without a mutex
500 bool WaitCondition::Wait(Mutex *pmutex, unsigned delay)
501 {
502 return pImpl->Wait(pmutex, delay);
503 }
504 // Notification
505 void WaitCondition::Notify()
506 {
507 pImpl->Notify();
508 }
509 void WaitCondition::NotifyAll()
510 {
511 pImpl->NotifyAll();
512 }
516 //-----------------------------------------------------------------------------------
517 // ***** Thread Class
519 // Per-thread variable
520 // MA: Don't use TLS for now - portability issues with DLLs, etc.
521 /*
522 #if !defined(OVR_CC_MSVC) || (OVR_CC_MSVC < 1300)
523 __declspec(thread) Thread* pCurrentThread = 0;
524 #else
525 #pragma data_seg(".tls$")
526 __declspec(thread) Thread* pCurrentThread = 0;
527 #pragma data_seg(".rwdata")
528 #endif
529 */
531 // *** Thread constructors.
533 Thread::Thread(UPInt stackSize, int processor)
534 {
535 CreateParams params;
536 params.stackSize = stackSize;
537 params.processor = processor;
538 Init(params);
539 }
541 Thread::Thread(Thread::ThreadFn threadFunction, void* userHandle, UPInt stackSize,
542 int processor, Thread::ThreadState initialState)
543 {
544 CreateParams params(threadFunction, userHandle, stackSize, processor, initialState);
545 Init(params);
546 }
548 Thread::Thread(const CreateParams& params)
549 {
550 Init(params);
551 }
552 void Thread::Init(const CreateParams& params)
553 {
554 // Clear the variables
555 ThreadFlags = 0;
556 ThreadHandle = 0;
557 IdValue = 0;
558 ExitCode = 0;
559 SuspendCount = 0;
560 StackSize = params.stackSize;
561 Processor = params.processor;
562 Priority = params.priority;
564 // Clear Function pointers
565 ThreadFunction = params.threadFunction;
566 UserHandle = params.userHandle;
567 if (params.initialState != NotRunning)
568 Start(params.initialState);
570 }
572 Thread::~Thread()
573 {
574 // Thread should not running while object is being destroyed,
575 // this would indicate ref-counting issue.
576 //OVR_ASSERT(IsRunning() == 0);
578 // Clean up thread.
579 CleanupSystemThread();
580 ThreadHandle = 0;
581 }
584 // *** Overridable User functions.
586 // Default Run implementation
587 int Thread::Run()
588 {
589 // Call pointer to function, if available.
590 return (ThreadFunction) ? ThreadFunction(this, UserHandle) : 0;
591 }
592 void Thread::OnExit()
593 {
594 }
596 // Finishes the thread and releases internal reference to it.
597 void Thread::FinishAndRelease()
598 {
599 // Note: thread must be US.
600 ThreadFlags &= (UInt32)~(OVR_THREAD_STARTED);
601 ThreadFlags |= OVR_THREAD_FINISHED;
603 // Release our reference; this is equivalent to 'delete this'
604 // from the point of view of our thread.
605 Release();
606 }
609 // *** ThreadList - used to tack all created threads
611 class ThreadList : public NewOverrideBase
612 {
613 //------------------------------------------------------------------------
614 struct ThreadHashOp
615 {
616 UPInt operator()(const Thread* ptr)
617 {
618 return (((UPInt)ptr) >> 6) ^ (UPInt)ptr;
619 }
620 };
622 HashSet<Thread*, ThreadHashOp> ThreadSet;
623 Mutex ThreadMutex;
624 WaitCondition ThreadsEmpty;
625 // Track the root thread that created us.
626 ThreadId RootThreadId;
628 static ThreadList* volatile pRunningThreads;
630 void addThread(Thread *pthread)
631 {
632 Mutex::Locker lock(&ThreadMutex);
633 ThreadSet.Add(pthread);
634 }
636 void removeThread(Thread *pthread)
637 {
638 Mutex::Locker lock(&ThreadMutex);
639 ThreadSet.Remove(pthread);
640 if (ThreadSet.GetSize() == 0)
641 ThreadsEmpty.Notify();
642 }
644 void finishAllThreads()
645 {
646 // Only original root thread can call this.
647 OVR_ASSERT(GetCurrentThreadId() == RootThreadId);
649 Mutex::Locker lock(&ThreadMutex);
650 while (ThreadSet.GetSize() != 0)
651 ThreadsEmpty.Wait(&ThreadMutex);
652 }
654 public:
656 ThreadList()
657 {
658 RootThreadId = GetCurrentThreadId();
659 }
660 ~ThreadList() { }
663 static void AddRunningThread(Thread *pthread)
664 {
665 // Non-atomic creation ok since only the root thread
666 if (!pRunningThreads)
667 {
668 pRunningThreads = new ThreadList;
669 OVR_ASSERT(pRunningThreads);
670 }
671 pRunningThreads->addThread(pthread);
672 }
674 // NOTE: 'pthread' might be a dead pointer when this is
675 // called so it should not be accessed; it is only used
676 // for removal.
677 static void RemoveRunningThread(Thread *pthread)
678 {
679 OVR_ASSERT(pRunningThreads);
680 pRunningThreads->removeThread(pthread);
681 }
683 static void FinishAllThreads()
684 {
685 // This is ok because only root thread can wait for other thread finish.
686 if (pRunningThreads)
687 {
688 pRunningThreads->finishAllThreads();
689 delete pRunningThreads;
690 pRunningThreads = 0;
691 }
692 }
693 };
695 // By default, we have no thread list.
696 ThreadList* volatile ThreadList::pRunningThreads = 0;
699 // FinishAllThreads - exposed publicly in Thread.
700 void Thread::FinishAllThreads()
701 {
702 ThreadList::FinishAllThreads();
703 }
706 // *** Run override
708 int Thread::PRun()
709 {
710 // Suspend us on start, if requested
711 if (ThreadFlags & OVR_THREAD_START_SUSPENDED)
712 {
713 Suspend();
714 ThreadFlags &= (UInt32)~OVR_THREAD_START_SUSPENDED;
715 }
717 // Call the virtual run function
718 ExitCode = Run();
719 return ExitCode;
720 }
724 /* MA: Don't use TLS for now.
726 // Static function to return a pointer to the current thread
727 void Thread::InitCurrentThread(Thread *pthread)
728 {
729 pCurrentThread = pthread;
730 }
732 // Static function to return a pointer to the current thread
733 Thread* Thread::GetThread()
734 {
735 return pCurrentThread;
736 }
737 */
740 // *** User overridables
742 bool Thread::GetExitFlag() const
743 {
744 return (ThreadFlags & OVR_THREAD_EXIT) != 0;
745 }
747 void Thread::SetExitFlag(bool exitFlag)
748 {
749 // The below is atomic since ThreadFlags is AtomicInt.
750 if (exitFlag)
751 ThreadFlags |= OVR_THREAD_EXIT;
752 else
753 ThreadFlags &= (UInt32) ~OVR_THREAD_EXIT;
754 }
757 // Determines whether the thread was running and is now finished
758 bool Thread::IsFinished() const
759 {
760 return (ThreadFlags & OVR_THREAD_FINISHED) != 0;
761 }
762 // Determines whether the thread is suspended
763 bool Thread::IsSuspended() const
764 {
765 return SuspendCount > 0;
766 }
767 // Returns current thread state
768 Thread::ThreadState Thread::GetThreadState() const
769 {
770 if (IsSuspended())
771 return Suspended;
772 if (ThreadFlags & OVR_THREAD_STARTED)
773 return Running;
774 return NotRunning;
775 }
779 // ***** Thread management
780 /* static */
781 int Thread::GetOSPriority(ThreadPriority p)
782 {
783 switch(p)
784 {
785 case Thread::CriticalPriority: return THREAD_PRIORITY_TIME_CRITICAL;
786 case Thread::HighestPriority: return THREAD_PRIORITY_HIGHEST;
787 case Thread::AboveNormalPriority: return THREAD_PRIORITY_ABOVE_NORMAL;
788 case Thread::NormalPriority: return THREAD_PRIORITY_NORMAL;
789 case Thread::BelowNormalPriority: return THREAD_PRIORITY_BELOW_NORMAL;
790 case Thread::LowestPriority: return THREAD_PRIORITY_LOWEST;
791 case Thread::IdlePriority: return THREAD_PRIORITY_IDLE;
792 }
793 return THREAD_PRIORITY_NORMAL;
794 }
796 // The actual first function called on thread start
797 unsigned WINAPI Thread_Win32StartFn(void * phandle)
798 {
799 Thread * pthread = (Thread*)phandle;
800 if (pthread->Processor != -1)
801 {
802 DWORD_PTR ret = SetThreadAffinityMask(GetCurrentThread(), (DWORD)pthread->Processor);
803 if (ret == 0)
804 OVR_DEBUG_LOG(("Could not set hardware processor for the thread"));
805 }
806 BOOL ret = ::SetThreadPriority(GetCurrentThread(), Thread::GetOSPriority(pthread->Priority));
807 if (ret == 0)
808 OVR_DEBUG_LOG(("Could not set thread priority"));
809 OVR_UNUSED(ret);
811 // Ensure that ThreadId is assigned once thread is running, in case
812 // beginthread hasn't filled it in yet.
813 pthread->IdValue = (ThreadId)::GetCurrentThreadId();
815 DWORD result = pthread->PRun();
816 // Signal the thread as done and release it atomically.
817 pthread->FinishAndRelease();
818 // At this point Thread object might be dead; however we can still pass
819 // it to RemoveRunningThread since it is only used as a key there.
820 ThreadList::RemoveRunningThread(pthread);
821 return (unsigned) result;
822 }
824 bool Thread::Start(ThreadState initialState)
825 {
826 if (initialState == NotRunning)
827 return 0;
828 if (GetThreadState() != NotRunning)
829 {
830 OVR_DEBUG_LOG(("Thread::Start failed - thread %p already running", this));
831 return 0;
832 }
834 // Free old thread handle before creating the new one
835 CleanupSystemThread();
837 // AddRef to us until the thread is finished.
838 AddRef();
839 ThreadList::AddRunningThread(this);
841 ExitCode = 0;
842 SuspendCount = 0;
843 ThreadFlags = (initialState == Running) ? 0 : OVR_THREAD_START_SUSPENDED;
844 ThreadHandle = (HANDLE) _beginthreadex(0, (unsigned)StackSize,
845 Thread_Win32StartFn, this, 0, (unsigned*)&IdValue);
847 // Failed? Fail the function
848 if (ThreadHandle == 0)
849 {
850 ThreadFlags = 0;
851 Release();
852 ThreadList::RemoveRunningThread(this);
853 return 0;
854 }
855 return 1;
856 }
859 // Suspend the thread until resumed
860 bool Thread::Suspend()
861 {
862 // Can't suspend a thread that wasn't started
863 if (!(ThreadFlags & OVR_THREAD_STARTED))
864 return 0;
866 if (::SuspendThread(ThreadHandle) != 0xFFFFFFFF)
867 {
868 SuspendCount++;
869 return 1;
870 }
871 return 0;
872 }
874 // Resumes currently suspended thread
875 bool Thread::Resume()
876 {
877 // Can't suspend a thread that wasn't started
878 if (!(ThreadFlags & OVR_THREAD_STARTED))
879 return 0;
881 // Decrement count, and resume thread if it is 0
882 SInt32 oldCount = SuspendCount.ExchangeAdd_Acquire(-1);
883 if (oldCount >= 1)
884 {
885 if (oldCount == 1)
886 {
887 if (::ResumeThread(ThreadHandle) != 0xFFFFFFFF)
888 return 1;
889 }
890 else
891 {
892 return 1;
893 }
894 }
895 return 0;
896 }
899 // Quits with an exit code
900 void Thread::Exit(int exitCode)
901 {
902 // Can only exist the current thread.
903 // MA: Don't use TLS for now.
904 //if (GetThread() != this)
905 // return;
907 // Call the virtual OnExit function.
908 OnExit();
910 // Signal this thread object as done and release it's references.
911 FinishAndRelease();
912 ThreadList::RemoveRunningThread(this);
914 // Call the exit function.
915 _endthreadex((unsigned)exitCode);
916 }
919 void Thread::CleanupSystemThread()
920 {
921 if (ThreadHandle != 0)
922 {
923 ::CloseHandle(ThreadHandle);
924 ThreadHandle = 0;
925 }
926 }
928 // *** Sleep functions
929 // static
930 bool Thread::Sleep(unsigned secs)
931 {
932 ::Sleep(secs*1000);
933 return 1;
934 }
936 // static
937 bool Thread::MSleep(unsigned msecs)
938 {
939 ::Sleep(msecs);
940 return 1;
941 }
943 void Thread::SetThreadName( const char* name )
944 {
945 #if !defined(OVR_BUILD_SHIPPING) || defined(OVR_BUILD_PROFILING)
946 // Looks ugly, but it is the recommended way to name a thread.
947 typedef struct tagTHREADNAME_INFO {
948 DWORD dwType; // Must be 0x1000
949 LPCSTR szName; // Pointer to name (in user address space)
950 DWORD dwThreadID; // Thread ID (-1 for caller thread)
951 DWORD dwFlags; // Reserved for future use; must be zero
952 } THREADNAME_INFO;
954 THREADNAME_INFO info;
956 info.dwType = 0x1000;
957 info.szName = name;
958 info.dwThreadID = reinterpret_cast<DWORD>(GetThreadId());
959 info.dwFlags = 0;
961 __try
962 {
963 #ifdef _WIN64
964 RaiseException( 0x406D1388, 0, sizeof(info)/sizeof(DWORD), (const ULONG_PTR *)&info );
965 #else
966 RaiseException( 0x406D1388, 0, sizeof(info)/sizeof(DWORD), (DWORD *)&info );
967 #endif
968 }
969 __except( GetExceptionCode()==0x406D1388 ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_EXECUTE_HANDLER )
970 {
971 }
972 #endif // OVR_BUILD_SHIPPING
973 }
975 // static
976 int Thread::GetCPUCount()
977 {
978 SYSTEM_INFO sysInfo;
979 GetSystemInfo(&sysInfo);
980 return (int) sysInfo.dwNumberOfProcessors;
981 }
983 // Returns the unique Id of a thread it is called on, intended for
984 // comparison purposes.
985 ThreadId GetCurrentThreadId()
986 {
987 return (ThreadId)::GetCurrentThreadId();
988 }
990 } // OVR
992 #endif