oculus1
diff libovr/Src/win32/OVR_ThreadsWinAPI.cpp @ 1:e2f9e4603129
added LibOVR and started a simple vr wrapper.
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sat, 14 Sep 2013 16:14:59 +0300 |
parents | |
children | b069a5c27388 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/libovr/Src/win32/OVR_ThreadsWinAPI.cpp Sat Sep 14 16:14:59 2013 +0300 1.3 @@ -0,0 +1,1 @@ 1.4 +/************************************************************************************ 1.5 1.6 Filename : OVR_ThreadsWinAPI.cpp 1.7 Platform : WinAPI 1.8 Content : Windows specific thread-related (safe) functionality 1.9 Created : September 19, 2012 1.10 Notes : 1.11 1.12 Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved. 1.13 1.14 Use of this software is subject to the terms of the Oculus license 1.15 agreement provided at the time of installation or download, or which 1.16 otherwise accompanies this software in either electronic or hard copy form. 1.17 1.18 ************************************************************************************/ 1.19 1.20 #include "OVR_Threads.h" 1.21 #include "OVR_Hash.h" 1.22 #include "OVR_Log.h" 1.23 1.24 #ifdef OVR_ENABLE_THREADS 1.25 1.26 // For _beginthreadex / _endtheadex 1.27 #include <process.h> 1.28 1.29 namespace OVR { 1.30 1.31 1.32 //----------------------------------------------------------------------------------- 1.33 // *** Internal Mutex implementation class 1.34 1.35 class MutexImpl : public NewOverrideBase 1.36 { 1.37 // System mutex or semaphore 1.38 HANDLE hMutexOrSemaphore; 1.39 bool Recursive; 1.40 volatile unsigned LockCount; 1.41 1.42 friend class WaitConditionImpl; 1.43 1.44 public: 1.45 // Constructor/destructor 1.46 MutexImpl(bool recursive = 1); 1.47 ~MutexImpl(); 1.48 1.49 // Locking functions 1.50 void DoLock(); 1.51 bool TryLock(); 1.52 void Unlock(Mutex* pmutex); 1.53 // Returns 1 if the mutes is currently locked 1.54 bool IsLockedByAnotherThread(Mutex* pmutex); 1.55 }; 1.56 1.57 // *** Constructor/destructor 1.58 MutexImpl::MutexImpl(bool recursive) 1.59 { 1.60 Recursive = recursive; 1.61 LockCount = 0; 1.62 hMutexOrSemaphore = Recursive ? CreateMutex(NULL, 0, NULL) : CreateSemaphore(NULL, 1, 1, NULL); 1.63 } 1.64 MutexImpl::~MutexImpl() 1.65 { 1.66 CloseHandle(hMutexOrSemaphore); 1.67 } 1.68 1.69 1.70 // Lock and try lock 1.71 void MutexImpl::DoLock() 1.72 { 1.73 if (::WaitForSingleObject(hMutexOrSemaphore, INFINITE) != WAIT_OBJECT_0) 1.74 return; 1.75 LockCount++; 1.76 } 1.77 1.78 bool MutexImpl::TryLock() 1.79 { 1.80 DWORD ret; 1.81 if ((ret=::WaitForSingleObject(hMutexOrSemaphore, 0)) != WAIT_OBJECT_0) 1.82 return 0; 1.83 LockCount++; 1.84 return 1; 1.85 } 1.86 1.87 void MutexImpl::Unlock(Mutex* pmutex) 1.88 { 1.89 OVR_UNUSED(pmutex); 1.90 1.91 unsigned lockCount; 1.92 LockCount--; 1.93 lockCount = LockCount; 1.94 1.95 // Release mutex 1.96 if ((Recursive ? ReleaseMutex(hMutexOrSemaphore) : 1.97 ReleaseSemaphore(hMutexOrSemaphore, 1, NULL)) != 0) 1.98 { 1.99 // This used to call Wait handlers if lockCount == 0. 1.100 } 1.101 } 1.102 1.103 bool MutexImpl::IsLockedByAnotherThread(Mutex* pmutex) 1.104 { 1.105 // There could be multiple interpretations of IsLocked with respect to current thread 1.106 if (LockCount == 0) 1.107 return 0; 1.108 if (!TryLock()) 1.109 return 1; 1.110 Unlock(pmutex); 1.111 return 0; 1.112 } 1.113 1.114 /* 1.115 bool MutexImpl::IsSignaled() const 1.116 { 1.117 // An mutex is signaled if it is not locked ANYWHERE 1.118 // Note that this is different from IsLockedByAnotherThread function, 1.119 // that takes current thread into account 1.120 return LockCount == 0; 1.121 } 1.122 */ 1.123 1.124 1.125 // *** Actual Mutex class implementation 1.126 1.127 Mutex::Mutex(bool recursive) 1.128 { 1.129 pImpl = new MutexImpl(recursive); 1.130 } 1.131 Mutex::~Mutex() 1.132 { 1.133 delete pImpl; 1.134 } 1.135 1.136 // Lock and try lock 1.137 void Mutex::DoLock() 1.138 { 1.139 pImpl->DoLock(); 1.140 } 1.141 bool Mutex::TryLock() 1.142 { 1.143 return pImpl->TryLock(); 1.144 } 1.145 void Mutex::Unlock() 1.146 { 1.147 pImpl->Unlock(this); 1.148 } 1.149 bool Mutex::IsLockedByAnotherThread() 1.150 { 1.151 return pImpl->IsLockedByAnotherThread(this); 1.152 } 1.153 1.154 //----------------------------------------------------------------------------------- 1.155 // ***** Event 1.156 1.157 bool Event::Wait(unsigned delay) 1.158 { 1.159 Mutex::Locker lock(&StateMutex); 1.160 1.161 // Do the correct amount of waiting 1.162 if (delay == OVR_WAIT_INFINITE) 1.163 { 1.164 while(!State) 1.165 StateWaitCondition.Wait(&StateMutex); 1.166 } 1.167 else if (delay) 1.168 { 1.169 if (!State) 1.170 StateWaitCondition.Wait(&StateMutex, delay); 1.171 } 1.172 1.173 bool state = State; 1.174 // Take care of temporary 'pulsing' of a state 1.175 if (Temporary) 1.176 { 1.177 Temporary = false; 1.178 State = false; 1.179 } 1.180 return state; 1.181 } 1.182 1.183 void Event::updateState(bool newState, bool newTemp, bool mustNotify) 1.184 { 1.185 Mutex::Locker lock(&StateMutex); 1.186 State = newState; 1.187 Temporary = newTemp; 1.188 if (mustNotify) 1.189 StateWaitCondition.NotifyAll(); 1.190 } 1.191 1.192 1.193 //----------------------------------------------------------------------------------- 1.194 // ***** Win32 Wait Condition Implementation 1.195 1.196 // Internal implementation class 1.197 class WaitConditionImpl : public NewOverrideBase 1.198 { 1.199 // Event pool entries for extra events 1.200 struct EventPoolEntry : public NewOverrideBase 1.201 { 1.202 HANDLE hEvent; 1.203 EventPoolEntry *pNext; 1.204 EventPoolEntry *pPrev; 1.205 }; 1.206 1.207 Lock WaitQueueLoc; 1.208 // Stores free events that can be used later 1.209 EventPoolEntry * pFreeEventList; 1.210 1.211 // A queue of waiting objects to be signaled 1.212 EventPoolEntry* pQueueHead; 1.213 EventPoolEntry* pQueueTail; 1.214 1.215 // Allocation functions for free events 1.216 EventPoolEntry* GetNewEvent(); 1.217 void ReleaseEvent(EventPoolEntry* pevent); 1.218 1.219 // Queue operations 1.220 void QueuePush(EventPoolEntry* pentry); 1.221 EventPoolEntry* QueuePop(); 1.222 void QueueFindAndRemove(EventPoolEntry* pentry); 1.223 1.224 public: 1.225 1.226 // Constructor/destructor 1.227 WaitConditionImpl(); 1.228 ~WaitConditionImpl(); 1.229 1.230 // Release mutex and wait for condition. The mutex is re-acqured after the wait. 1.231 bool Wait(Mutex *pmutex, unsigned delay = OVR_WAIT_INFINITE); 1.232 1.233 // Notify a condition, releasing at one object waiting 1.234 void Notify(); 1.235 // Notify a condition, releasing all objects waiting 1.236 void NotifyAll(); 1.237 }; 1.238 1.239 1.240 1.241 WaitConditionImpl::WaitConditionImpl() 1.242 { 1.243 pFreeEventList = 0; 1.244 pQueueHead = 1.245 pQueueTail = 0; 1.246 } 1.247 1.248 WaitConditionImpl::~WaitConditionImpl() 1.249 { 1.250 // Free all the resources 1.251 EventPoolEntry* p = pFreeEventList; 1.252 EventPoolEntry* pentry; 1.253 1.254 while(p) 1.255 { 1.256 // Move to next 1.257 pentry = p; 1.258 p = p->pNext; 1.259 // Delete old 1.260 ::CloseHandle(pentry->hEvent); 1.261 delete pentry; 1.262 } 1.263 // Shouldn't we also consider the queue? 1.264 1.265 // To be safe 1.266 pFreeEventList = 0; 1.267 pQueueHead = 1.268 pQueueTail = 0; 1.269 } 1.270 1.271 1.272 // Allocation functions for free events 1.273 WaitConditionImpl::EventPoolEntry* WaitConditionImpl::GetNewEvent() 1.274 { 1.275 EventPoolEntry* pentry; 1.276 1.277 // If there are any free nodes, use them 1.278 if (pFreeEventList) 1.279 { 1.280 pentry = pFreeEventList; 1.281 pFreeEventList = pFreeEventList->pNext; 1.282 } 1.283 else 1.284 { 1.285 // Allocate a new node 1.286 pentry = new EventPoolEntry; 1.287 pentry->pNext = 0; 1.288 pentry->pPrev = 0; 1.289 // Non-signaled manual event 1.290 pentry->hEvent = ::CreateEvent(NULL, TRUE, 0, NULL); 1.291 } 1.292 1.293 return pentry; 1.294 } 1.295 1.296 void WaitConditionImpl::ReleaseEvent(EventPoolEntry* pevent) 1.297 { 1.298 // Mark event as non-signaled 1.299 ::ResetEvent(pevent->hEvent); 1.300 // And add it to free pool 1.301 pevent->pNext = pFreeEventList; 1.302 pevent->pPrev = 0; 1.303 pFreeEventList = pevent; 1.304 } 1.305 1.306 // Queue operations 1.307 void WaitConditionImpl::QueuePush(EventPoolEntry* pentry) 1.308 { 1.309 // Items already exist? Just add to tail 1.310 if (pQueueTail) 1.311 { 1.312 pentry->pPrev = pQueueTail; 1.313 pQueueTail->pNext = pentry; 1.314 pentry->pNext = 0; 1.315 pQueueTail = pentry; 1.316 } 1.317 else 1.318 { 1.319 // No items in queue 1.320 pentry->pNext = 1.321 pentry->pPrev = 0; 1.322 pQueueHead = 1.323 pQueueTail = pentry; 1.324 } 1.325 } 1.326 1.327 WaitConditionImpl::EventPoolEntry* WaitConditionImpl::QueuePop() 1.328 { 1.329 EventPoolEntry* pentry = pQueueHead; 1.330 1.331 // No items, null pointer 1.332 if (pentry) 1.333 { 1.334 // More items after this one? just grab the first item 1.335 if (pQueueHead->pNext) 1.336 { 1.337 pQueueHead = pentry->pNext; 1.338 pQueueHead->pPrev = 0; 1.339 } 1.340 else 1.341 { 1.342 // Last item left 1.343 pQueueTail = 1.344 pQueueHead = 0; 1.345 } 1.346 } 1.347 return pentry; 1.348 } 1.349 1.350 void WaitConditionImpl::QueueFindAndRemove(EventPoolEntry* pentry) 1.351 { 1.352 // Do an exhaustive search looking for an entry 1.353 EventPoolEntry* p = pQueueHead; 1.354 1.355 while(p) 1.356 { 1.357 // Entry found? Remove. 1.358 if (p == pentry) 1.359 { 1.360 1.361 // Remove the node form the list 1.362 // Prev link 1.363 if (pentry->pPrev) 1.364 pentry->pPrev->pNext = pentry->pNext; 1.365 else 1.366 pQueueHead = pentry->pNext; 1.367 // Next link 1.368 if (pentry->pNext) 1.369 pentry->pNext->pPrev = pentry->pPrev; 1.370 else 1.371 pQueueTail = pentry->pPrev; 1.372 // Done 1.373 return; 1.374 } 1.375 1.376 // Move to next item 1.377 p = p->pNext; 1.378 } 1.379 } 1.380 1.381 1.382 bool WaitConditionImpl::Wait(Mutex *pmutex, unsigned delay) 1.383 { 1.384 bool result = 0; 1.385 unsigned i; 1.386 unsigned lockCount = pmutex->pImpl->LockCount; 1.387 EventPoolEntry* pentry; 1.388 1.389 // Mutex must have been locked 1.390 if (lockCount == 0) 1.391 return 0; 1.392 1.393 // Add an object to the wait queue 1.394 WaitQueueLoc.DoLock(); 1.395 QueuePush(pentry = GetNewEvent()); 1.396 WaitQueueLoc.Unlock(); 1.397 1.398 // Finally, release a mutex or semaphore 1.399 if (pmutex->pImpl->Recursive) 1.400 { 1.401 // Release the recursive mutex N times 1.402 pmutex->pImpl->LockCount = 0; 1.403 for(i=0; i<lockCount; i++) 1.404 ::ReleaseMutex(pmutex->pImpl->hMutexOrSemaphore); 1.405 } 1.406 else 1.407 { 1.408 pmutex->pImpl->LockCount = 0; 1.409 ::ReleaseSemaphore(pmutex->pImpl->hMutexOrSemaphore, 1, NULL); 1.410 } 1.411 1.412 // Note that there is a gap here between mutex.Unlock() and Wait(). However, 1.413 // if notify() comes in at this point in the other thread it will set our 1.414 // corresponding event so wait will just fall through, as expected. 1.415 1.416 // Block and wait on the event 1.417 DWORD waitResult = ::WaitForSingleObject(pentry->hEvent, 1.418 (delay == OVR_WAIT_INFINITE) ? INFINITE : delay); 1.419 /* 1.420 repeat_wait: 1.421 DWORD waitResult = 1.422 1.423 ::MsgWaitForMultipleObjects(1, &pentry->hEvent, FALSE, 1.424 (delay == OVR_WAIT_INFINITE) ? INFINITE : delay, 1.425 QS_ALLINPUT); 1.426 */ 1.427 1.428 WaitQueueLoc.DoLock(); 1.429 switch(waitResult) 1.430 { 1.431 case WAIT_ABANDONED: 1.432 case WAIT_OBJECT_0: 1.433 result = 1; 1.434 // Wait was successful, therefore the event entry should already be removed 1.435 // So just add entry back to a free list 1.436 ReleaseEvent(pentry); 1.437 break; 1.438 /* 1.439 case WAIT_OBJECT_0 + 1: 1.440 // Messages in WINDOWS queue 1.441 { 1.442 MSG msg; 1.443 PeekMessage(&msg, NULL, 0U, 0U, PM_NOREMOVE); 1.444 WaitQueueLoc.Unlock(); 1.445 goto repeat_wait; 1.446 } 1.447 break; */ 1.448 default: 1.449 // Timeout, our entry should still be in a queue 1.450 QueueFindAndRemove(pentry); 1.451 ReleaseEvent(pentry); 1.452 } 1.453 WaitQueueLoc.Unlock(); 1.454 1.455 // Re-aquire the mutex 1.456 for(i=0; i<lockCount; i++) 1.457 pmutex->DoLock(); 1.458 1.459 // Return the result 1.460 return result; 1.461 } 1.462 1.463 // Notify a condition, releasing the least object in a queue 1.464 void WaitConditionImpl::Notify() 1.465 { 1.466 Lock::Locker lock(&WaitQueueLoc); 1.467 1.468 // Pop last entry & signal it 1.469 EventPoolEntry* pentry = QueuePop(); 1.470 if (pentry) 1.471 ::SetEvent(pentry->hEvent); 1.472 } 1.473 1.474 // Notify a condition, releasing all objects waiting 1.475 void WaitConditionImpl::NotifyAll() 1.476 { 1.477 Lock::Locker lock(&WaitQueueLoc); 1.478 1.479 // Pop and signal all events 1.480 // NOTE : There is no need to release the events, it's the waiters job to do so 1.481 EventPoolEntry* pentry = QueuePop(); 1.482 while (pentry) 1.483 { 1.484 ::SetEvent(pentry->hEvent); 1.485 pentry = QueuePop(); 1.486 } 1.487 } 1.488 1.489 1.490 1.491 // *** Actual implementation of WaitCondition 1.492 1.493 WaitCondition::WaitCondition() 1.494 { 1.495 pImpl = new WaitConditionImpl; 1.496 } 1.497 WaitCondition::~WaitCondition() 1.498 { 1.499 delete pImpl; 1.500 } 1.501 1.502 // Wait without a mutex 1.503 bool WaitCondition::Wait(Mutex *pmutex, unsigned delay) 1.504 { 1.505 return pImpl->Wait(pmutex, delay); 1.506 } 1.507 // Notification 1.508 void WaitCondition::Notify() 1.509 { 1.510 pImpl->Notify(); 1.511 } 1.512 void WaitCondition::NotifyAll() 1.513 { 1.514 pImpl->NotifyAll(); 1.515 } 1.516 1.517 1.518 1.519 //----------------------------------------------------------------------------------- 1.520 // ***** Thread Class 1.521 1.522 // Per-thread variable 1.523 // MA: Don't use TLS for now - portability issues with DLLs, etc. 1.524 /* 1.525 #if !defined(OVR_CC_MSVC) || (OVR_CC_MSVC < 1300) 1.526 __declspec(thread) Thread* pCurrentThread = 0; 1.527 #else 1.528 #pragma data_seg(".tls$") 1.529 __declspec(thread) Thread* pCurrentThread = 0; 1.530 #pragma data_seg(".rwdata") 1.531 #endif 1.532 */ 1.533 1.534 // *** Thread constructors. 1.535 1.536 Thread::Thread(UPInt stackSize, int processor) 1.537 { 1.538 CreateParams params; 1.539 params.stackSize = stackSize; 1.540 params.processor = processor; 1.541 Init(params); 1.542 } 1.543 1.544 Thread::Thread(Thread::ThreadFn threadFunction, void* userHandle, UPInt stackSize, 1.545 int processor, Thread::ThreadState initialState) 1.546 { 1.547 CreateParams params(threadFunction, userHandle, stackSize, processor, initialState); 1.548 Init(params); 1.549 } 1.550 1.551 Thread::Thread(const CreateParams& params) 1.552 { 1.553 Init(params); 1.554 } 1.555 void Thread::Init(const CreateParams& params) 1.556 { 1.557 // Clear the variables 1.558 ThreadFlags = 0; 1.559 ThreadHandle = 0; 1.560 IdValue = 0; 1.561 ExitCode = 0; 1.562 SuspendCount = 0; 1.563 StackSize = params.stackSize; 1.564 Processor = params.processor; 1.565 Priority = params.priority; 1.566 1.567 // Clear Function pointers 1.568 ThreadFunction = params.threadFunction; 1.569 UserHandle = params.userHandle; 1.570 if (params.initialState != NotRunning) 1.571 Start(params.initialState); 1.572 1.573 } 1.574 1.575 Thread::~Thread() 1.576 { 1.577 // Thread should not running while object is being destroyed, 1.578 // this would indicate ref-counting issue. 1.579 //OVR_ASSERT(IsRunning() == 0); 1.580 1.581 // Clean up thread. 1.582 CleanupSystemThread(); 1.583 ThreadHandle = 0; 1.584 } 1.585 1.586 1.587 // *** Overridable User functions. 1.588 1.589 // Default Run implementation 1.590 int Thread::Run() 1.591 { 1.592 // Call pointer to function, if available. 1.593 return (ThreadFunction) ? ThreadFunction(this, UserHandle) : 0; 1.594 } 1.595 void Thread::OnExit() 1.596 { 1.597 } 1.598 1.599 // Finishes the thread and releases internal reference to it. 1.600 void Thread::FinishAndRelease() 1.601 { 1.602 // Note: thread must be US. 1.603 ThreadFlags &= (UInt32)~(OVR_THREAD_STARTED); 1.604 ThreadFlags |= OVR_THREAD_FINISHED; 1.605 1.606 // Release our reference; this is equivalent to 'delete this' 1.607 // from the point of view of our thread. 1.608 Release(); 1.609 } 1.610 1.611 1.612 // *** ThreadList - used to tack all created threads 1.613 1.614 class ThreadList : public NewOverrideBase 1.615 { 1.616 //------------------------------------------------------------------------ 1.617 struct ThreadHashOp 1.618 { 1.619 UPInt operator()(const Thread* ptr) 1.620 { 1.621 return (((UPInt)ptr) >> 6) ^ (UPInt)ptr; 1.622 } 1.623 }; 1.624 1.625 HashSet<Thread*, ThreadHashOp> ThreadSet; 1.626 Mutex ThreadMutex; 1.627 WaitCondition ThreadsEmpty; 1.628 // Track the root thread that created us. 1.629 ThreadId RootThreadId; 1.630 1.631 static ThreadList* volatile pRunningThreads; 1.632 1.633 void addThread(Thread *pthread) 1.634 { 1.635 Mutex::Locker lock(&ThreadMutex); 1.636 ThreadSet.Add(pthread); 1.637 } 1.638 1.639 void removeThread(Thread *pthread) 1.640 { 1.641 Mutex::Locker lock(&ThreadMutex); 1.642 ThreadSet.Remove(pthread); 1.643 if (ThreadSet.GetSize() == 0) 1.644 ThreadsEmpty.Notify(); 1.645 } 1.646 1.647 void finishAllThreads() 1.648 { 1.649 // Only original root thread can call this. 1.650 OVR_ASSERT(GetCurrentThreadId() == RootThreadId); 1.651 1.652 Mutex::Locker lock(&ThreadMutex); 1.653 while (ThreadSet.GetSize() != 0) 1.654 ThreadsEmpty.Wait(&ThreadMutex); 1.655 } 1.656 1.657 public: 1.658 1.659 ThreadList() 1.660 { 1.661 RootThreadId = GetCurrentThreadId(); 1.662 } 1.663 ~ThreadList() { } 1.664 1.665 1.666 static void AddRunningThread(Thread *pthread) 1.667 { 1.668 // Non-atomic creation ok since only the root thread 1.669 if (!pRunningThreads) 1.670 { 1.671 pRunningThreads = new ThreadList; 1.672 OVR_ASSERT(pRunningThreads); 1.673 } 1.674 pRunningThreads->addThread(pthread); 1.675 } 1.676 1.677 // NOTE: 'pthread' might be a dead pointer when this is 1.678 // called so it should not be accessed; it is only used 1.679 // for removal. 1.680 static void RemoveRunningThread(Thread *pthread) 1.681 { 1.682 OVR_ASSERT(pRunningThreads); 1.683 pRunningThreads->removeThread(pthread); 1.684 } 1.685 1.686 static void FinishAllThreads() 1.687 { 1.688 // This is ok because only root thread can wait for other thread finish. 1.689 if (pRunningThreads) 1.690 { 1.691 pRunningThreads->finishAllThreads(); 1.692 delete pRunningThreads; 1.693 pRunningThreads = 0; 1.694 } 1.695 } 1.696 }; 1.697 1.698 // By default, we have no thread list. 1.699 ThreadList* volatile ThreadList::pRunningThreads = 0; 1.700 1.701 1.702 // FinishAllThreads - exposed publicly in Thread. 1.703 void Thread::FinishAllThreads() 1.704 { 1.705 ThreadList::FinishAllThreads(); 1.706 } 1.707 1.708 1.709 // *** Run override 1.710 1.711 int Thread::PRun() 1.712 { 1.713 // Suspend us on start, if requested 1.714 if (ThreadFlags & OVR_THREAD_START_SUSPENDED) 1.715 { 1.716 Suspend(); 1.717 ThreadFlags &= (UInt32)~OVR_THREAD_START_SUSPENDED; 1.718 } 1.719 1.720 // Call the virtual run function 1.721 ExitCode = Run(); 1.722 return ExitCode; 1.723 } 1.724 1.725 1.726 1.727 /* MA: Don't use TLS for now. 1.728 1.729 // Static function to return a pointer to the current thread 1.730 void Thread::InitCurrentThread(Thread *pthread) 1.731 { 1.732 pCurrentThread = pthread; 1.733 } 1.734 1.735 // Static function to return a pointer to the current thread 1.736 Thread* Thread::GetThread() 1.737 { 1.738 return pCurrentThread; 1.739 } 1.740 */ 1.741 1.742 1.743 // *** User overridables 1.744 1.745 bool Thread::GetExitFlag() const 1.746 { 1.747 return (ThreadFlags & OVR_THREAD_EXIT) != 0; 1.748 } 1.749 1.750 void Thread::SetExitFlag(bool exitFlag) 1.751 { 1.752 // The below is atomic since ThreadFlags is AtomicInt. 1.753 if (exitFlag) 1.754 ThreadFlags |= OVR_THREAD_EXIT; 1.755 else 1.756 ThreadFlags &= (UInt32) ~OVR_THREAD_EXIT; 1.757 } 1.758 1.759 1.760 // Determines whether the thread was running and is now finished 1.761 bool Thread::IsFinished() const 1.762 { 1.763 return (ThreadFlags & OVR_THREAD_FINISHED) != 0; 1.764 } 1.765 // Determines whether the thread is suspended 1.766 bool Thread::IsSuspended() const 1.767 { 1.768 return SuspendCount > 0; 1.769 } 1.770 // Returns current thread state 1.771 Thread::ThreadState Thread::GetThreadState() const 1.772 { 1.773 if (IsSuspended()) 1.774 return Suspended; 1.775 if (ThreadFlags & OVR_THREAD_STARTED) 1.776 return Running; 1.777 return NotRunning; 1.778 } 1.779 1.780 1.781 1.782 // ***** Thread management 1.783 /* static */ 1.784 int Thread::GetOSPriority(ThreadPriority p) 1.785 { 1.786 switch(p) 1.787 { 1.788 case Thread::CriticalPriority: return THREAD_PRIORITY_TIME_CRITICAL; 1.789 case Thread::HighestPriority: return THREAD_PRIORITY_HIGHEST; 1.790 case Thread::AboveNormalPriority: return THREAD_PRIORITY_ABOVE_NORMAL; 1.791 case Thread::NormalPriority: return THREAD_PRIORITY_NORMAL; 1.792 case Thread::BelowNormalPriority: return THREAD_PRIORITY_BELOW_NORMAL; 1.793 case Thread::LowestPriority: return THREAD_PRIORITY_LOWEST; 1.794 case Thread::IdlePriority: return THREAD_PRIORITY_IDLE; 1.795 } 1.796 return THREAD_PRIORITY_NORMAL; 1.797 } 1.798 1.799 // The actual first function called on thread start 1.800 unsigned WINAPI Thread_Win32StartFn(void * phandle) 1.801 { 1.802 Thread * pthread = (Thread*)phandle; 1.803 if (pthread->Processor != -1) 1.804 { 1.805 DWORD_PTR ret = SetThreadAffinityMask(GetCurrentThread(), (DWORD)pthread->Processor); 1.806 if (ret == 0) 1.807 OVR_DEBUG_LOG(("Could not set hardware processor for the thread")); 1.808 } 1.809 BOOL ret = ::SetThreadPriority(GetCurrentThread(), Thread::GetOSPriority(pthread->Priority)); 1.810 if (ret == 0) 1.811 OVR_DEBUG_LOG(("Could not set thread priority")); 1.812 OVR_UNUSED(ret); 1.813 1.814 // Ensure that ThreadId is assigned once thread is running, in case 1.815 // beginthread hasn't filled it in yet. 1.816 pthread->IdValue = (ThreadId)::GetCurrentThreadId(); 1.817 1.818 DWORD result = pthread->PRun(); 1.819 // Signal the thread as done and release it atomically. 1.820 pthread->FinishAndRelease(); 1.821 // At this point Thread object might be dead; however we can still pass 1.822 // it to RemoveRunningThread since it is only used as a key there. 1.823 ThreadList::RemoveRunningThread(pthread); 1.824 return (unsigned) result; 1.825 } 1.826 1.827 bool Thread::Start(ThreadState initialState) 1.828 { 1.829 if (initialState == NotRunning) 1.830 return 0; 1.831 if (GetThreadState() != NotRunning) 1.832 { 1.833 OVR_DEBUG_LOG(("Thread::Start failed - thread %p already running", this)); 1.834 return 0; 1.835 } 1.836 1.837 // Free old thread handle before creating the new one 1.838 CleanupSystemThread(); 1.839 1.840 // AddRef to us until the thread is finished. 1.841 AddRef(); 1.842 ThreadList::AddRunningThread(this); 1.843 1.844 ExitCode = 0; 1.845 SuspendCount = 0; 1.846 ThreadFlags = (initialState == Running) ? 0 : OVR_THREAD_START_SUSPENDED; 1.847 ThreadHandle = (HANDLE) _beginthreadex(0, (unsigned)StackSize, 1.848 Thread_Win32StartFn, this, 0, (unsigned*)&IdValue); 1.849 1.850 // Failed? Fail the function 1.851 if (ThreadHandle == 0) 1.852 { 1.853 ThreadFlags = 0; 1.854 Release(); 1.855 ThreadList::RemoveRunningThread(this); 1.856 return 0; 1.857 } 1.858 return 1; 1.859 } 1.860 1.861 1.862 // Suspend the thread until resumed 1.863 bool Thread::Suspend() 1.864 { 1.865 // Can't suspend a thread that wasn't started 1.866 if (!(ThreadFlags & OVR_THREAD_STARTED)) 1.867 return 0; 1.868 1.869 if (::SuspendThread(ThreadHandle) != 0xFFFFFFFF) 1.870 { 1.871 SuspendCount++; 1.872 return 1; 1.873 } 1.874 return 0; 1.875 } 1.876 1.877 // Resumes currently suspended thread 1.878 bool Thread::Resume() 1.879 { 1.880 // Can't suspend a thread that wasn't started 1.881 if (!(ThreadFlags & OVR_THREAD_STARTED)) 1.882 return 0; 1.883 1.884 // Decrement count, and resume thread if it is 0 1.885 SInt32 oldCount = SuspendCount.ExchangeAdd_Acquire(-1); 1.886 if (oldCount >= 1) 1.887 { 1.888 if (oldCount == 1) 1.889 { 1.890 if (::ResumeThread(ThreadHandle) != 0xFFFFFFFF) 1.891 return 1; 1.892 } 1.893 else 1.894 { 1.895 return 1; 1.896 } 1.897 } 1.898 return 0; 1.899 } 1.900 1.901 1.902 // Quits with an exit code 1.903 void Thread::Exit(int exitCode) 1.904 { 1.905 // Can only exist the current thread. 1.906 // MA: Don't use TLS for now. 1.907 //if (GetThread() != this) 1.908 // return; 1.909 1.910 // Call the virtual OnExit function. 1.911 OnExit(); 1.912 1.913 // Signal this thread object as done and release it's references. 1.914 FinishAndRelease(); 1.915 ThreadList::RemoveRunningThread(this); 1.916 1.917 // Call the exit function. 1.918 _endthreadex((unsigned)exitCode); 1.919 } 1.920 1.921 1.922 void Thread::CleanupSystemThread() 1.923 { 1.924 if (ThreadHandle != 0) 1.925 { 1.926 ::CloseHandle(ThreadHandle); 1.927 ThreadHandle = 0; 1.928 } 1.929 } 1.930 1.931 // *** Sleep functions 1.932 // static 1.933 bool Thread::Sleep(unsigned secs) 1.934 { 1.935 ::Sleep(secs*1000); 1.936 return 1; 1.937 } 1.938 1.939 // static 1.940 bool Thread::MSleep(unsigned msecs) 1.941 { 1.942 ::Sleep(msecs); 1.943 return 1; 1.944 } 1.945 1.946 void Thread::SetThreadName( const char* name ) 1.947 { 1.948 #if !defined(OVR_BUILD_SHIPPING) || defined(OVR_BUILD_PROFILING) 1.949 // Looks ugly, but it is the recommended way to name a thread. 1.950 typedef struct tagTHREADNAME_INFO { 1.951 DWORD dwType; // Must be 0x1000 1.952 LPCSTR szName; // Pointer to name (in user address space) 1.953 DWORD dwThreadID; // Thread ID (-1 for caller thread) 1.954 DWORD dwFlags; // Reserved for future use; must be zero 1.955 } THREADNAME_INFO; 1.956 1.957 THREADNAME_INFO info; 1.958 1.959 info.dwType = 0x1000; 1.960 info.szName = name; 1.961 info.dwThreadID = reinterpret_cast<DWORD>(GetThreadId()); 1.962 info.dwFlags = 0; 1.963 1.964 __try 1.965 { 1.966 #ifdef _WIN64 1.967 RaiseException( 0x406D1388, 0, sizeof(info)/sizeof(DWORD), (const ULONG_PTR *)&info ); 1.968 #else 1.969 RaiseException( 0x406D1388, 0, sizeof(info)/sizeof(DWORD), (DWORD *)&info ); 1.970 #endif 1.971 } 1.972 __except( GetExceptionCode()==0x406D1388 ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_EXECUTE_HANDLER ) 1.973 { 1.974 } 1.975 #endif // OVR_BUILD_SHIPPING 1.976 } 1.977 1.978 // static 1.979 int Thread::GetCPUCount() 1.980 { 1.981 SYSTEM_INFO sysInfo; 1.982 GetSystemInfo(&sysInfo); 1.983 return (int) sysInfo.dwNumberOfProcessors; 1.984 } 1.985 1.986 // Returns the unique Id of a thread it is called on, intended for 1.987 // comparison purposes. 1.988 ThreadId GetCurrentThreadId() 1.989 { 1.990 return (ThreadId)::GetCurrentThreadId(); 1.991 } 1.992 1.993 } // OVR 1.994 1.995 #endif 1.996 1.997 1.998 \ No newline at end of file