oculus1
diff libovr/Src/win32/OVR_ThreadsWinAPI.cpp @ 3:b069a5c27388
added a couple more stuff, fixed all the LibOVR line endings
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sun, 15 Sep 2013 04:10:05 +0300 |
parents | e2f9e4603129 |
children |
line diff
1.1 --- a/libovr/Src/win32/OVR_ThreadsWinAPI.cpp Sat Sep 14 17:51:03 2013 +0300 1.2 +++ b/libovr/Src/win32/OVR_ThreadsWinAPI.cpp Sun Sep 15 04:10:05 2013 +0300 1.3 @@ -1,1 +1,994 @@ 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 1.999 +/************************************************************************************ 1.1000 + 1.1001 +Filename : OVR_ThreadsWinAPI.cpp 1.1002 +Platform : WinAPI 1.1003 +Content : Windows specific thread-related (safe) functionality 1.1004 +Created : September 19, 2012 1.1005 +Notes : 1.1006 + 1.1007 +Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved. 1.1008 + 1.1009 +Use of this software is subject to the terms of the Oculus license 1.1010 +agreement provided at the time of installation or download, or which 1.1011 +otherwise accompanies this software in either electronic or hard copy form. 1.1012 + 1.1013 +************************************************************************************/ 1.1014 + 1.1015 +#include "OVR_Threads.h" 1.1016 +#include "OVR_Hash.h" 1.1017 +#include "OVR_Log.h" 1.1018 + 1.1019 +#ifdef OVR_ENABLE_THREADS 1.1020 + 1.1021 +// For _beginthreadex / _endtheadex 1.1022 +#include <process.h> 1.1023 + 1.1024 +namespace OVR { 1.1025 + 1.1026 + 1.1027 +//----------------------------------------------------------------------------------- 1.1028 +// *** Internal Mutex implementation class 1.1029 + 1.1030 +class MutexImpl : public NewOverrideBase 1.1031 +{ 1.1032 + // System mutex or semaphore 1.1033 + HANDLE hMutexOrSemaphore; 1.1034 + bool Recursive; 1.1035 + volatile unsigned LockCount; 1.1036 + 1.1037 + friend class WaitConditionImpl; 1.1038 + 1.1039 +public: 1.1040 + // Constructor/destructor 1.1041 + MutexImpl(bool recursive = 1); 1.1042 + ~MutexImpl(); 1.1043 + 1.1044 + // Locking functions 1.1045 + void DoLock(); 1.1046 + bool TryLock(); 1.1047 + void Unlock(Mutex* pmutex); 1.1048 + // Returns 1 if the mutes is currently locked 1.1049 + bool IsLockedByAnotherThread(Mutex* pmutex); 1.1050 +}; 1.1051 + 1.1052 +// *** Constructor/destructor 1.1053 +MutexImpl::MutexImpl(bool recursive) 1.1054 +{ 1.1055 + Recursive = recursive; 1.1056 + LockCount = 0; 1.1057 + hMutexOrSemaphore = Recursive ? CreateMutex(NULL, 0, NULL) : CreateSemaphore(NULL, 1, 1, NULL); 1.1058 +} 1.1059 +MutexImpl::~MutexImpl() 1.1060 +{ 1.1061 + CloseHandle(hMutexOrSemaphore); 1.1062 +} 1.1063 + 1.1064 + 1.1065 +// Lock and try lock 1.1066 +void MutexImpl::DoLock() 1.1067 +{ 1.1068 + if (::WaitForSingleObject(hMutexOrSemaphore, INFINITE) != WAIT_OBJECT_0) 1.1069 + return; 1.1070 + LockCount++; 1.1071 +} 1.1072 + 1.1073 +bool MutexImpl::TryLock() 1.1074 +{ 1.1075 + DWORD ret; 1.1076 + if ((ret=::WaitForSingleObject(hMutexOrSemaphore, 0)) != WAIT_OBJECT_0) 1.1077 + return 0; 1.1078 + LockCount++; 1.1079 + return 1; 1.1080 +} 1.1081 + 1.1082 +void MutexImpl::Unlock(Mutex* pmutex) 1.1083 +{ 1.1084 + OVR_UNUSED(pmutex); 1.1085 + 1.1086 + unsigned lockCount; 1.1087 + LockCount--; 1.1088 + lockCount = LockCount; 1.1089 + 1.1090 + // Release mutex 1.1091 + if ((Recursive ? ReleaseMutex(hMutexOrSemaphore) : 1.1092 + ReleaseSemaphore(hMutexOrSemaphore, 1, NULL)) != 0) 1.1093 + { 1.1094 + // This used to call Wait handlers if lockCount == 0. 1.1095 + } 1.1096 +} 1.1097 + 1.1098 +bool MutexImpl::IsLockedByAnotherThread(Mutex* pmutex) 1.1099 +{ 1.1100 + // There could be multiple interpretations of IsLocked with respect to current thread 1.1101 + if (LockCount == 0) 1.1102 + return 0; 1.1103 + if (!TryLock()) 1.1104 + return 1; 1.1105 + Unlock(pmutex); 1.1106 + return 0; 1.1107 +} 1.1108 + 1.1109 +/* 1.1110 +bool MutexImpl::IsSignaled() const 1.1111 +{ 1.1112 + // An mutex is signaled if it is not locked ANYWHERE 1.1113 + // Note that this is different from IsLockedByAnotherThread function, 1.1114 + // that takes current thread into account 1.1115 + return LockCount == 0; 1.1116 +} 1.1117 +*/ 1.1118 + 1.1119 + 1.1120 +// *** Actual Mutex class implementation 1.1121 + 1.1122 +Mutex::Mutex(bool recursive) 1.1123 +{ 1.1124 + pImpl = new MutexImpl(recursive); 1.1125 +} 1.1126 +Mutex::~Mutex() 1.1127 +{ 1.1128 + delete pImpl; 1.1129 +} 1.1130 + 1.1131 +// Lock and try lock 1.1132 +void Mutex::DoLock() 1.1133 +{ 1.1134 + pImpl->DoLock(); 1.1135 +} 1.1136 +bool Mutex::TryLock() 1.1137 +{ 1.1138 + return pImpl->TryLock(); 1.1139 +} 1.1140 +void Mutex::Unlock() 1.1141 +{ 1.1142 + pImpl->Unlock(this); 1.1143 +} 1.1144 +bool Mutex::IsLockedByAnotherThread() 1.1145 +{ 1.1146 + return pImpl->IsLockedByAnotherThread(this); 1.1147 +} 1.1148 + 1.1149 +//----------------------------------------------------------------------------------- 1.1150 +// ***** Event 1.1151 + 1.1152 +bool Event::Wait(unsigned delay) 1.1153 +{ 1.1154 + Mutex::Locker lock(&StateMutex); 1.1155 + 1.1156 + // Do the correct amount of waiting 1.1157 + if (delay == OVR_WAIT_INFINITE) 1.1158 + { 1.1159 + while(!State) 1.1160 + StateWaitCondition.Wait(&StateMutex); 1.1161 + } 1.1162 + else if (delay) 1.1163 + { 1.1164 + if (!State) 1.1165 + StateWaitCondition.Wait(&StateMutex, delay); 1.1166 + } 1.1167 + 1.1168 + bool state = State; 1.1169 + // Take care of temporary 'pulsing' of a state 1.1170 + if (Temporary) 1.1171 + { 1.1172 + Temporary = false; 1.1173 + State = false; 1.1174 + } 1.1175 + return state; 1.1176 +} 1.1177 + 1.1178 +void Event::updateState(bool newState, bool newTemp, bool mustNotify) 1.1179 +{ 1.1180 + Mutex::Locker lock(&StateMutex); 1.1181 + State = newState; 1.1182 + Temporary = newTemp; 1.1183 + if (mustNotify) 1.1184 + StateWaitCondition.NotifyAll(); 1.1185 +} 1.1186 + 1.1187 + 1.1188 +//----------------------------------------------------------------------------------- 1.1189 +// ***** Win32 Wait Condition Implementation 1.1190 + 1.1191 +// Internal implementation class 1.1192 +class WaitConditionImpl : public NewOverrideBase 1.1193 +{ 1.1194 + // Event pool entries for extra events 1.1195 + struct EventPoolEntry : public NewOverrideBase 1.1196 + { 1.1197 + HANDLE hEvent; 1.1198 + EventPoolEntry *pNext; 1.1199 + EventPoolEntry *pPrev; 1.1200 + }; 1.1201 + 1.1202 + Lock WaitQueueLoc; 1.1203 + // Stores free events that can be used later 1.1204 + EventPoolEntry * pFreeEventList; 1.1205 + 1.1206 + // A queue of waiting objects to be signaled 1.1207 + EventPoolEntry* pQueueHead; 1.1208 + EventPoolEntry* pQueueTail; 1.1209 + 1.1210 + // Allocation functions for free events 1.1211 + EventPoolEntry* GetNewEvent(); 1.1212 + void ReleaseEvent(EventPoolEntry* pevent); 1.1213 + 1.1214 + // Queue operations 1.1215 + void QueuePush(EventPoolEntry* pentry); 1.1216 + EventPoolEntry* QueuePop(); 1.1217 + void QueueFindAndRemove(EventPoolEntry* pentry); 1.1218 + 1.1219 +public: 1.1220 + 1.1221 + // Constructor/destructor 1.1222 + WaitConditionImpl(); 1.1223 + ~WaitConditionImpl(); 1.1224 + 1.1225 + // Release mutex and wait for condition. The mutex is re-acqured after the wait. 1.1226 + bool Wait(Mutex *pmutex, unsigned delay = OVR_WAIT_INFINITE); 1.1227 + 1.1228 + // Notify a condition, releasing at one object waiting 1.1229 + void Notify(); 1.1230 + // Notify a condition, releasing all objects waiting 1.1231 + void NotifyAll(); 1.1232 +}; 1.1233 + 1.1234 + 1.1235 + 1.1236 +WaitConditionImpl::WaitConditionImpl() 1.1237 +{ 1.1238 + pFreeEventList = 0; 1.1239 + pQueueHead = 1.1240 + pQueueTail = 0; 1.1241 +} 1.1242 + 1.1243 +WaitConditionImpl::~WaitConditionImpl() 1.1244 +{ 1.1245 + // Free all the resources 1.1246 + EventPoolEntry* p = pFreeEventList; 1.1247 + EventPoolEntry* pentry; 1.1248 + 1.1249 + while(p) 1.1250 + { 1.1251 + // Move to next 1.1252 + pentry = p; 1.1253 + p = p->pNext; 1.1254 + // Delete old 1.1255 + ::CloseHandle(pentry->hEvent); 1.1256 + delete pentry; 1.1257 + } 1.1258 + // Shouldn't we also consider the queue? 1.1259 + 1.1260 + // To be safe 1.1261 + pFreeEventList = 0; 1.1262 + pQueueHead = 1.1263 + pQueueTail = 0; 1.1264 +} 1.1265 + 1.1266 + 1.1267 +// Allocation functions for free events 1.1268 +WaitConditionImpl::EventPoolEntry* WaitConditionImpl::GetNewEvent() 1.1269 +{ 1.1270 + EventPoolEntry* pentry; 1.1271 + 1.1272 + // If there are any free nodes, use them 1.1273 + if (pFreeEventList) 1.1274 + { 1.1275 + pentry = pFreeEventList; 1.1276 + pFreeEventList = pFreeEventList->pNext; 1.1277 + } 1.1278 + else 1.1279 + { 1.1280 + // Allocate a new node 1.1281 + pentry = new EventPoolEntry; 1.1282 + pentry->pNext = 0; 1.1283 + pentry->pPrev = 0; 1.1284 + // Non-signaled manual event 1.1285 + pentry->hEvent = ::CreateEvent(NULL, TRUE, 0, NULL); 1.1286 + } 1.1287 + 1.1288 + return pentry; 1.1289 +} 1.1290 + 1.1291 +void WaitConditionImpl::ReleaseEvent(EventPoolEntry* pevent) 1.1292 +{ 1.1293 + // Mark event as non-signaled 1.1294 + ::ResetEvent(pevent->hEvent); 1.1295 + // And add it to free pool 1.1296 + pevent->pNext = pFreeEventList; 1.1297 + pevent->pPrev = 0; 1.1298 + pFreeEventList = pevent; 1.1299 +} 1.1300 + 1.1301 +// Queue operations 1.1302 +void WaitConditionImpl::QueuePush(EventPoolEntry* pentry) 1.1303 +{ 1.1304 + // Items already exist? Just add to tail 1.1305 + if (pQueueTail) 1.1306 + { 1.1307 + pentry->pPrev = pQueueTail; 1.1308 + pQueueTail->pNext = pentry; 1.1309 + pentry->pNext = 0; 1.1310 + pQueueTail = pentry; 1.1311 + } 1.1312 + else 1.1313 + { 1.1314 + // No items in queue 1.1315 + pentry->pNext = 1.1316 + pentry->pPrev = 0; 1.1317 + pQueueHead = 1.1318 + pQueueTail = pentry; 1.1319 + } 1.1320 +} 1.1321 + 1.1322 +WaitConditionImpl::EventPoolEntry* WaitConditionImpl::QueuePop() 1.1323 +{ 1.1324 + EventPoolEntry* pentry = pQueueHead; 1.1325 + 1.1326 + // No items, null pointer 1.1327 + if (pentry) 1.1328 + { 1.1329 + // More items after this one? just grab the first item 1.1330 + if (pQueueHead->pNext) 1.1331 + { 1.1332 + pQueueHead = pentry->pNext; 1.1333 + pQueueHead->pPrev = 0; 1.1334 + } 1.1335 + else 1.1336 + { 1.1337 + // Last item left 1.1338 + pQueueTail = 1.1339 + pQueueHead = 0; 1.1340 + } 1.1341 + } 1.1342 + return pentry; 1.1343 +} 1.1344 + 1.1345 +void WaitConditionImpl::QueueFindAndRemove(EventPoolEntry* pentry) 1.1346 +{ 1.1347 + // Do an exhaustive search looking for an entry 1.1348 + EventPoolEntry* p = pQueueHead; 1.1349 + 1.1350 + while(p) 1.1351 + { 1.1352 + // Entry found? Remove. 1.1353 + if (p == pentry) 1.1354 + { 1.1355 + 1.1356 + // Remove the node form the list 1.1357 + // Prev link 1.1358 + if (pentry->pPrev) 1.1359 + pentry->pPrev->pNext = pentry->pNext; 1.1360 + else 1.1361 + pQueueHead = pentry->pNext; 1.1362 + // Next link 1.1363 + if (pentry->pNext) 1.1364 + pentry->pNext->pPrev = pentry->pPrev; 1.1365 + else 1.1366 + pQueueTail = pentry->pPrev; 1.1367 + // Done 1.1368 + return; 1.1369 + } 1.1370 + 1.1371 + // Move to next item 1.1372 + p = p->pNext; 1.1373 + } 1.1374 +} 1.1375 + 1.1376 + 1.1377 +bool WaitConditionImpl::Wait(Mutex *pmutex, unsigned delay) 1.1378 +{ 1.1379 + bool result = 0; 1.1380 + unsigned i; 1.1381 + unsigned lockCount = pmutex->pImpl->LockCount; 1.1382 + EventPoolEntry* pentry; 1.1383 + 1.1384 + // Mutex must have been locked 1.1385 + if (lockCount == 0) 1.1386 + return 0; 1.1387 + 1.1388 + // Add an object to the wait queue 1.1389 + WaitQueueLoc.DoLock(); 1.1390 + QueuePush(pentry = GetNewEvent()); 1.1391 + WaitQueueLoc.Unlock(); 1.1392 + 1.1393 + // Finally, release a mutex or semaphore 1.1394 + if (pmutex->pImpl->Recursive) 1.1395 + { 1.1396 + // Release the recursive mutex N times 1.1397 + pmutex->pImpl->LockCount = 0; 1.1398 + for(i=0; i<lockCount; i++) 1.1399 + ::ReleaseMutex(pmutex->pImpl->hMutexOrSemaphore); 1.1400 + } 1.1401 + else 1.1402 + { 1.1403 + pmutex->pImpl->LockCount = 0; 1.1404 + ::ReleaseSemaphore(pmutex->pImpl->hMutexOrSemaphore, 1, NULL); 1.1405 + } 1.1406 + 1.1407 + // Note that there is a gap here between mutex.Unlock() and Wait(). However, 1.1408 + // if notify() comes in at this point in the other thread it will set our 1.1409 + // corresponding event so wait will just fall through, as expected. 1.1410 + 1.1411 + // Block and wait on the event 1.1412 + DWORD waitResult = ::WaitForSingleObject(pentry->hEvent, 1.1413 + (delay == OVR_WAIT_INFINITE) ? INFINITE : delay); 1.1414 + /* 1.1415 +repeat_wait: 1.1416 + DWORD waitResult = 1.1417 + 1.1418 + ::MsgWaitForMultipleObjects(1, &pentry->hEvent, FALSE, 1.1419 + (delay == OVR_WAIT_INFINITE) ? INFINITE : delay, 1.1420 + QS_ALLINPUT); 1.1421 + */ 1.1422 + 1.1423 + WaitQueueLoc.DoLock(); 1.1424 + switch(waitResult) 1.1425 + { 1.1426 + case WAIT_ABANDONED: 1.1427 + case WAIT_OBJECT_0: 1.1428 + result = 1; 1.1429 + // Wait was successful, therefore the event entry should already be removed 1.1430 + // So just add entry back to a free list 1.1431 + ReleaseEvent(pentry); 1.1432 + break; 1.1433 + /* 1.1434 + case WAIT_OBJECT_0 + 1: 1.1435 + // Messages in WINDOWS queue 1.1436 + { 1.1437 + MSG msg; 1.1438 + PeekMessage(&msg, NULL, 0U, 0U, PM_NOREMOVE); 1.1439 + WaitQueueLoc.Unlock(); 1.1440 + goto repeat_wait; 1.1441 + } 1.1442 + break; */ 1.1443 + default: 1.1444 + // Timeout, our entry should still be in a queue 1.1445 + QueueFindAndRemove(pentry); 1.1446 + ReleaseEvent(pentry); 1.1447 + } 1.1448 + WaitQueueLoc.Unlock(); 1.1449 + 1.1450 + // Re-aquire the mutex 1.1451 + for(i=0; i<lockCount; i++) 1.1452 + pmutex->DoLock(); 1.1453 + 1.1454 + // Return the result 1.1455 + return result; 1.1456 +} 1.1457 + 1.1458 +// Notify a condition, releasing the least object in a queue 1.1459 +void WaitConditionImpl::Notify() 1.1460 +{ 1.1461 + Lock::Locker lock(&WaitQueueLoc); 1.1462 + 1.1463 + // Pop last entry & signal it 1.1464 + EventPoolEntry* pentry = QueuePop(); 1.1465 + if (pentry) 1.1466 + ::SetEvent(pentry->hEvent); 1.1467 +} 1.1468 + 1.1469 +// Notify a condition, releasing all objects waiting 1.1470 +void WaitConditionImpl::NotifyAll() 1.1471 +{ 1.1472 + Lock::Locker lock(&WaitQueueLoc); 1.1473 + 1.1474 + // Pop and signal all events 1.1475 + // NOTE : There is no need to release the events, it's the waiters job to do so 1.1476 + EventPoolEntry* pentry = QueuePop(); 1.1477 + while (pentry) 1.1478 + { 1.1479 + ::SetEvent(pentry->hEvent); 1.1480 + pentry = QueuePop(); 1.1481 + } 1.1482 +} 1.1483 + 1.1484 + 1.1485 + 1.1486 +// *** Actual implementation of WaitCondition 1.1487 + 1.1488 +WaitCondition::WaitCondition() 1.1489 +{ 1.1490 + pImpl = new WaitConditionImpl; 1.1491 +} 1.1492 +WaitCondition::~WaitCondition() 1.1493 +{ 1.1494 + delete pImpl; 1.1495 +} 1.1496 + 1.1497 +// Wait without a mutex 1.1498 +bool WaitCondition::Wait(Mutex *pmutex, unsigned delay) 1.1499 +{ 1.1500 + return pImpl->Wait(pmutex, delay); 1.1501 +} 1.1502 +// Notification 1.1503 +void WaitCondition::Notify() 1.1504 +{ 1.1505 + pImpl->Notify(); 1.1506 +} 1.1507 +void WaitCondition::NotifyAll() 1.1508 +{ 1.1509 + pImpl->NotifyAll(); 1.1510 +} 1.1511 + 1.1512 + 1.1513 + 1.1514 +//----------------------------------------------------------------------------------- 1.1515 +// ***** Thread Class 1.1516 + 1.1517 +// Per-thread variable 1.1518 +// MA: Don't use TLS for now - portability issues with DLLs, etc. 1.1519 +/* 1.1520 +#if !defined(OVR_CC_MSVC) || (OVR_CC_MSVC < 1300) 1.1521 +__declspec(thread) Thread* pCurrentThread = 0; 1.1522 +#else 1.1523 +#pragma data_seg(".tls$") 1.1524 +__declspec(thread) Thread* pCurrentThread = 0; 1.1525 +#pragma data_seg(".rwdata") 1.1526 +#endif 1.1527 +*/ 1.1528 + 1.1529 +// *** Thread constructors. 1.1530 + 1.1531 +Thread::Thread(UPInt stackSize, int processor) 1.1532 +{ 1.1533 + CreateParams params; 1.1534 + params.stackSize = stackSize; 1.1535 + params.processor = processor; 1.1536 + Init(params); 1.1537 +} 1.1538 + 1.1539 +Thread::Thread(Thread::ThreadFn threadFunction, void* userHandle, UPInt stackSize, 1.1540 + int processor, Thread::ThreadState initialState) 1.1541 +{ 1.1542 + CreateParams params(threadFunction, userHandle, stackSize, processor, initialState); 1.1543 + Init(params); 1.1544 +} 1.1545 + 1.1546 +Thread::Thread(const CreateParams& params) 1.1547 +{ 1.1548 + Init(params); 1.1549 +} 1.1550 +void Thread::Init(const CreateParams& params) 1.1551 +{ 1.1552 + // Clear the variables 1.1553 + ThreadFlags = 0; 1.1554 + ThreadHandle = 0; 1.1555 + IdValue = 0; 1.1556 + ExitCode = 0; 1.1557 + SuspendCount = 0; 1.1558 + StackSize = params.stackSize; 1.1559 + Processor = params.processor; 1.1560 + Priority = params.priority; 1.1561 + 1.1562 + // Clear Function pointers 1.1563 + ThreadFunction = params.threadFunction; 1.1564 + UserHandle = params.userHandle; 1.1565 + if (params.initialState != NotRunning) 1.1566 + Start(params.initialState); 1.1567 + 1.1568 +} 1.1569 + 1.1570 +Thread::~Thread() 1.1571 +{ 1.1572 + // Thread should not running while object is being destroyed, 1.1573 + // this would indicate ref-counting issue. 1.1574 + //OVR_ASSERT(IsRunning() == 0); 1.1575 + 1.1576 + // Clean up thread. 1.1577 + CleanupSystemThread(); 1.1578 + ThreadHandle = 0; 1.1579 +} 1.1580 + 1.1581 + 1.1582 +// *** Overridable User functions. 1.1583 + 1.1584 +// Default Run implementation 1.1585 +int Thread::Run() 1.1586 +{ 1.1587 + // Call pointer to function, if available. 1.1588 + return (ThreadFunction) ? ThreadFunction(this, UserHandle) : 0; 1.1589 +} 1.1590 +void Thread::OnExit() 1.1591 +{ 1.1592 +} 1.1593 + 1.1594 +// Finishes the thread and releases internal reference to it. 1.1595 +void Thread::FinishAndRelease() 1.1596 +{ 1.1597 + // Note: thread must be US. 1.1598 + ThreadFlags &= (UInt32)~(OVR_THREAD_STARTED); 1.1599 + ThreadFlags |= OVR_THREAD_FINISHED; 1.1600 + 1.1601 + // Release our reference; this is equivalent to 'delete this' 1.1602 + // from the point of view of our thread. 1.1603 + Release(); 1.1604 +} 1.1605 + 1.1606 + 1.1607 +// *** ThreadList - used to tack all created threads 1.1608 + 1.1609 +class ThreadList : public NewOverrideBase 1.1610 +{ 1.1611 + //------------------------------------------------------------------------ 1.1612 + struct ThreadHashOp 1.1613 + { 1.1614 + UPInt operator()(const Thread* ptr) 1.1615 + { 1.1616 + return (((UPInt)ptr) >> 6) ^ (UPInt)ptr; 1.1617 + } 1.1618 + }; 1.1619 + 1.1620 + HashSet<Thread*, ThreadHashOp> ThreadSet; 1.1621 + Mutex ThreadMutex; 1.1622 + WaitCondition ThreadsEmpty; 1.1623 + // Track the root thread that created us. 1.1624 + ThreadId RootThreadId; 1.1625 + 1.1626 + static ThreadList* volatile pRunningThreads; 1.1627 + 1.1628 + void addThread(Thread *pthread) 1.1629 + { 1.1630 + Mutex::Locker lock(&ThreadMutex); 1.1631 + ThreadSet.Add(pthread); 1.1632 + } 1.1633 + 1.1634 + void removeThread(Thread *pthread) 1.1635 + { 1.1636 + Mutex::Locker lock(&ThreadMutex); 1.1637 + ThreadSet.Remove(pthread); 1.1638 + if (ThreadSet.GetSize() == 0) 1.1639 + ThreadsEmpty.Notify(); 1.1640 + } 1.1641 + 1.1642 + void finishAllThreads() 1.1643 + { 1.1644 + // Only original root thread can call this. 1.1645 + OVR_ASSERT(GetCurrentThreadId() == RootThreadId); 1.1646 + 1.1647 + Mutex::Locker lock(&ThreadMutex); 1.1648 + while (ThreadSet.GetSize() != 0) 1.1649 + ThreadsEmpty.Wait(&ThreadMutex); 1.1650 + } 1.1651 + 1.1652 +public: 1.1653 + 1.1654 + ThreadList() 1.1655 + { 1.1656 + RootThreadId = GetCurrentThreadId(); 1.1657 + } 1.1658 + ~ThreadList() { } 1.1659 + 1.1660 + 1.1661 + static void AddRunningThread(Thread *pthread) 1.1662 + { 1.1663 + // Non-atomic creation ok since only the root thread 1.1664 + if (!pRunningThreads) 1.1665 + { 1.1666 + pRunningThreads = new ThreadList; 1.1667 + OVR_ASSERT(pRunningThreads); 1.1668 + } 1.1669 + pRunningThreads->addThread(pthread); 1.1670 + } 1.1671 + 1.1672 + // NOTE: 'pthread' might be a dead pointer when this is 1.1673 + // called so it should not be accessed; it is only used 1.1674 + // for removal. 1.1675 + static void RemoveRunningThread(Thread *pthread) 1.1676 + { 1.1677 + OVR_ASSERT(pRunningThreads); 1.1678 + pRunningThreads->removeThread(pthread); 1.1679 + } 1.1680 + 1.1681 + static void FinishAllThreads() 1.1682 + { 1.1683 + // This is ok because only root thread can wait for other thread finish. 1.1684 + if (pRunningThreads) 1.1685 + { 1.1686 + pRunningThreads->finishAllThreads(); 1.1687 + delete pRunningThreads; 1.1688 + pRunningThreads = 0; 1.1689 + } 1.1690 + } 1.1691 +}; 1.1692 + 1.1693 +// By default, we have no thread list. 1.1694 +ThreadList* volatile ThreadList::pRunningThreads = 0; 1.1695 + 1.1696 + 1.1697 +// FinishAllThreads - exposed publicly in Thread. 1.1698 +void Thread::FinishAllThreads() 1.1699 +{ 1.1700 + ThreadList::FinishAllThreads(); 1.1701 +} 1.1702 + 1.1703 + 1.1704 +// *** Run override 1.1705 + 1.1706 +int Thread::PRun() 1.1707 +{ 1.1708 + // Suspend us on start, if requested 1.1709 + if (ThreadFlags & OVR_THREAD_START_SUSPENDED) 1.1710 + { 1.1711 + Suspend(); 1.1712 + ThreadFlags &= (UInt32)~OVR_THREAD_START_SUSPENDED; 1.1713 + } 1.1714 + 1.1715 + // Call the virtual run function 1.1716 + ExitCode = Run(); 1.1717 + return ExitCode; 1.1718 +} 1.1719 + 1.1720 + 1.1721 + 1.1722 +/* MA: Don't use TLS for now. 1.1723 + 1.1724 +// Static function to return a pointer to the current thread 1.1725 +void Thread::InitCurrentThread(Thread *pthread) 1.1726 +{ 1.1727 + pCurrentThread = pthread; 1.1728 +} 1.1729 + 1.1730 +// Static function to return a pointer to the current thread 1.1731 +Thread* Thread::GetThread() 1.1732 +{ 1.1733 + return pCurrentThread; 1.1734 +} 1.1735 +*/ 1.1736 + 1.1737 + 1.1738 +// *** User overridables 1.1739 + 1.1740 +bool Thread::GetExitFlag() const 1.1741 +{ 1.1742 + return (ThreadFlags & OVR_THREAD_EXIT) != 0; 1.1743 +} 1.1744 + 1.1745 +void Thread::SetExitFlag(bool exitFlag) 1.1746 +{ 1.1747 + // The below is atomic since ThreadFlags is AtomicInt. 1.1748 + if (exitFlag) 1.1749 + ThreadFlags |= OVR_THREAD_EXIT; 1.1750 + else 1.1751 + ThreadFlags &= (UInt32) ~OVR_THREAD_EXIT; 1.1752 +} 1.1753 + 1.1754 + 1.1755 +// Determines whether the thread was running and is now finished 1.1756 +bool Thread::IsFinished() const 1.1757 +{ 1.1758 + return (ThreadFlags & OVR_THREAD_FINISHED) != 0; 1.1759 +} 1.1760 +// Determines whether the thread is suspended 1.1761 +bool Thread::IsSuspended() const 1.1762 +{ 1.1763 + return SuspendCount > 0; 1.1764 +} 1.1765 +// Returns current thread state 1.1766 +Thread::ThreadState Thread::GetThreadState() const 1.1767 +{ 1.1768 + if (IsSuspended()) 1.1769 + return Suspended; 1.1770 + if (ThreadFlags & OVR_THREAD_STARTED) 1.1771 + return Running; 1.1772 + return NotRunning; 1.1773 +} 1.1774 + 1.1775 + 1.1776 + 1.1777 +// ***** Thread management 1.1778 +/* static */ 1.1779 +int Thread::GetOSPriority(ThreadPriority p) 1.1780 +{ 1.1781 + switch(p) 1.1782 + { 1.1783 + case Thread::CriticalPriority: return THREAD_PRIORITY_TIME_CRITICAL; 1.1784 + case Thread::HighestPriority: return THREAD_PRIORITY_HIGHEST; 1.1785 + case Thread::AboveNormalPriority: return THREAD_PRIORITY_ABOVE_NORMAL; 1.1786 + case Thread::NormalPriority: return THREAD_PRIORITY_NORMAL; 1.1787 + case Thread::BelowNormalPriority: return THREAD_PRIORITY_BELOW_NORMAL; 1.1788 + case Thread::LowestPriority: return THREAD_PRIORITY_LOWEST; 1.1789 + case Thread::IdlePriority: return THREAD_PRIORITY_IDLE; 1.1790 + } 1.1791 + return THREAD_PRIORITY_NORMAL; 1.1792 +} 1.1793 + 1.1794 +// The actual first function called on thread start 1.1795 +unsigned WINAPI Thread_Win32StartFn(void * phandle) 1.1796 +{ 1.1797 + Thread * pthread = (Thread*)phandle; 1.1798 + if (pthread->Processor != -1) 1.1799 + { 1.1800 + DWORD_PTR ret = SetThreadAffinityMask(GetCurrentThread(), (DWORD)pthread->Processor); 1.1801 + if (ret == 0) 1.1802 + OVR_DEBUG_LOG(("Could not set hardware processor for the thread")); 1.1803 + } 1.1804 + BOOL ret = ::SetThreadPriority(GetCurrentThread(), Thread::GetOSPriority(pthread->Priority)); 1.1805 + if (ret == 0) 1.1806 + OVR_DEBUG_LOG(("Could not set thread priority")); 1.1807 + OVR_UNUSED(ret); 1.1808 + 1.1809 + // Ensure that ThreadId is assigned once thread is running, in case 1.1810 + // beginthread hasn't filled it in yet. 1.1811 + pthread->IdValue = (ThreadId)::GetCurrentThreadId(); 1.1812 + 1.1813 + DWORD result = pthread->PRun(); 1.1814 + // Signal the thread as done and release it atomically. 1.1815 + pthread->FinishAndRelease(); 1.1816 + // At this point Thread object might be dead; however we can still pass 1.1817 + // it to RemoveRunningThread since it is only used as a key there. 1.1818 + ThreadList::RemoveRunningThread(pthread); 1.1819 + return (unsigned) result; 1.1820 +} 1.1821 + 1.1822 +bool Thread::Start(ThreadState initialState) 1.1823 +{ 1.1824 + if (initialState == NotRunning) 1.1825 + return 0; 1.1826 + if (GetThreadState() != NotRunning) 1.1827 + { 1.1828 + OVR_DEBUG_LOG(("Thread::Start failed - thread %p already running", this)); 1.1829 + return 0; 1.1830 + } 1.1831 + 1.1832 + // Free old thread handle before creating the new one 1.1833 + CleanupSystemThread(); 1.1834 + 1.1835 + // AddRef to us until the thread is finished. 1.1836 + AddRef(); 1.1837 + ThreadList::AddRunningThread(this); 1.1838 + 1.1839 + ExitCode = 0; 1.1840 + SuspendCount = 0; 1.1841 + ThreadFlags = (initialState == Running) ? 0 : OVR_THREAD_START_SUSPENDED; 1.1842 + ThreadHandle = (HANDLE) _beginthreadex(0, (unsigned)StackSize, 1.1843 + Thread_Win32StartFn, this, 0, (unsigned*)&IdValue); 1.1844 + 1.1845 + // Failed? Fail the function 1.1846 + if (ThreadHandle == 0) 1.1847 + { 1.1848 + ThreadFlags = 0; 1.1849 + Release(); 1.1850 + ThreadList::RemoveRunningThread(this); 1.1851 + return 0; 1.1852 + } 1.1853 + return 1; 1.1854 +} 1.1855 + 1.1856 + 1.1857 +// Suspend the thread until resumed 1.1858 +bool Thread::Suspend() 1.1859 +{ 1.1860 + // Can't suspend a thread that wasn't started 1.1861 + if (!(ThreadFlags & OVR_THREAD_STARTED)) 1.1862 + return 0; 1.1863 + 1.1864 + if (::SuspendThread(ThreadHandle) != 0xFFFFFFFF) 1.1865 + { 1.1866 + SuspendCount++; 1.1867 + return 1; 1.1868 + } 1.1869 + return 0; 1.1870 +} 1.1871 + 1.1872 +// Resumes currently suspended thread 1.1873 +bool Thread::Resume() 1.1874 +{ 1.1875 + // Can't suspend a thread that wasn't started 1.1876 + if (!(ThreadFlags & OVR_THREAD_STARTED)) 1.1877 + return 0; 1.1878 + 1.1879 + // Decrement count, and resume thread if it is 0 1.1880 + SInt32 oldCount = SuspendCount.ExchangeAdd_Acquire(-1); 1.1881 + if (oldCount >= 1) 1.1882 + { 1.1883 + if (oldCount == 1) 1.1884 + { 1.1885 + if (::ResumeThread(ThreadHandle) != 0xFFFFFFFF) 1.1886 + return 1; 1.1887 + } 1.1888 + else 1.1889 + { 1.1890 + return 1; 1.1891 + } 1.1892 + } 1.1893 + return 0; 1.1894 +} 1.1895 + 1.1896 + 1.1897 +// Quits with an exit code 1.1898 +void Thread::Exit(int exitCode) 1.1899 +{ 1.1900 + // Can only exist the current thread. 1.1901 + // MA: Don't use TLS for now. 1.1902 + //if (GetThread() != this) 1.1903 + // return; 1.1904 + 1.1905 + // Call the virtual OnExit function. 1.1906 + OnExit(); 1.1907 + 1.1908 + // Signal this thread object as done and release it's references. 1.1909 + FinishAndRelease(); 1.1910 + ThreadList::RemoveRunningThread(this); 1.1911 + 1.1912 + // Call the exit function. 1.1913 + _endthreadex((unsigned)exitCode); 1.1914 +} 1.1915 + 1.1916 + 1.1917 +void Thread::CleanupSystemThread() 1.1918 +{ 1.1919 + if (ThreadHandle != 0) 1.1920 + { 1.1921 + ::CloseHandle(ThreadHandle); 1.1922 + ThreadHandle = 0; 1.1923 + } 1.1924 +} 1.1925 + 1.1926 +// *** Sleep functions 1.1927 +// static 1.1928 +bool Thread::Sleep(unsigned secs) 1.1929 +{ 1.1930 + ::Sleep(secs*1000); 1.1931 + return 1; 1.1932 +} 1.1933 + 1.1934 +// static 1.1935 +bool Thread::MSleep(unsigned msecs) 1.1936 +{ 1.1937 + ::Sleep(msecs); 1.1938 + return 1; 1.1939 +} 1.1940 + 1.1941 +void Thread::SetThreadName( const char* name ) 1.1942 +{ 1.1943 +#if !defined(OVR_BUILD_SHIPPING) || defined(OVR_BUILD_PROFILING) 1.1944 + // Looks ugly, but it is the recommended way to name a thread. 1.1945 + typedef struct tagTHREADNAME_INFO { 1.1946 + DWORD dwType; // Must be 0x1000 1.1947 + LPCSTR szName; // Pointer to name (in user address space) 1.1948 + DWORD dwThreadID; // Thread ID (-1 for caller thread) 1.1949 + DWORD dwFlags; // Reserved for future use; must be zero 1.1950 + } THREADNAME_INFO; 1.1951 + 1.1952 + THREADNAME_INFO info; 1.1953 + 1.1954 + info.dwType = 0x1000; 1.1955 + info.szName = name; 1.1956 + info.dwThreadID = reinterpret_cast<DWORD>(GetThreadId()); 1.1957 + info.dwFlags = 0; 1.1958 + 1.1959 + __try 1.1960 + { 1.1961 +#ifdef _WIN64 1.1962 + RaiseException( 0x406D1388, 0, sizeof(info)/sizeof(DWORD), (const ULONG_PTR *)&info ); 1.1963 +#else 1.1964 + RaiseException( 0x406D1388, 0, sizeof(info)/sizeof(DWORD), (DWORD *)&info ); 1.1965 +#endif 1.1966 + } 1.1967 + __except( GetExceptionCode()==0x406D1388 ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_EXECUTE_HANDLER ) 1.1968 + { 1.1969 + } 1.1970 +#endif // OVR_BUILD_SHIPPING 1.1971 +} 1.1972 + 1.1973 +// static 1.1974 +int Thread::GetCPUCount() 1.1975 +{ 1.1976 + SYSTEM_INFO sysInfo; 1.1977 + GetSystemInfo(&sysInfo); 1.1978 + return (int) sysInfo.dwNumberOfProcessors; 1.1979 +} 1.1980 + 1.1981 +// Returns the unique Id of a thread it is called on, intended for 1.1982 +// comparison purposes. 1.1983 +ThreadId GetCurrentThreadId() 1.1984 +{ 1.1985 + return (ThreadId)::GetCurrentThreadId(); 1.1986 +} 1.1987 + 1.1988 +} // OVR 1.1989 + 1.1990 +#endif 1.1991 + 1.1992 +