ovr_sdk
diff LibOVR/Src/Kernel/OVR_ThreadsPthread.cpp @ 0:1b39a1b46319
initial 0.4.4
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Wed, 14 Jan 2015 06:51:16 +0200 |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/LibOVR/Src/Kernel/OVR_ThreadsPthread.cpp Wed Jan 14 06:51:16 2015 +0200 1.3 @@ -0,0 +1,984 @@ 1.4 +/************************************************************************************ 1.5 + 1.6 +Filename : OVR_ThreadsPthread.cpp 1.7 +Content : 1.8 +Created : 1.9 +Notes : 1.10 + 1.11 +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. 1.12 + 1.13 +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); 1.14 +you may not use the Oculus VR Rift SDK except in compliance with the License, 1.15 +which is 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 +You may obtain a copy of the License at 1.19 + 1.20 +http://www.oculusvr.com/licenses/LICENSE-3.2 1.21 + 1.22 +Unless required by applicable law or agreed to in writing, the Oculus VR SDK 1.23 +distributed under the License is distributed on an "AS IS" BASIS, 1.24 +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1.25 +See the License for the specific language governing permissions and 1.26 +limitations under the License. 1.27 + 1.28 +************************************************************************************/ 1.29 + 1.30 +#include "OVR_Threads.h" 1.31 +#include "OVR_Hash.h" 1.32 + 1.33 +#ifdef OVR_ENABLE_THREADS 1.34 + 1.35 +#include "OVR_Timer.h" 1.36 +#include "OVR_Log.h" 1.37 + 1.38 +#include <pthread.h> 1.39 +#include <sched.h> 1.40 +#include <time.h> 1.41 +#include <unistd.h> 1.42 +#include <sys/time.h> 1.43 +#include <errno.h> 1.44 + 1.45 +#if defined(OVR_OS_MAC) || defined(OVR_OS_BSD) 1.46 + #include <sys/sysctl.h> 1.47 + #include <sys/param.h> 1.48 + #if !defined(OVR_OS_MAC) 1.49 + #include <pthread_np.h> 1.50 + #endif 1.51 +#endif 1.52 + 1.53 + 1.54 + 1.55 +namespace OVR { 1.56 + 1.57 +// ***** Mutex implementation 1.58 + 1.59 + 1.60 +// *** Internal Mutex implementation structure 1.61 + 1.62 +class MutexImpl : public NewOverrideBase 1.63 +{ 1.64 + // System mutex or semaphore 1.65 + pthread_mutex_t SMutex; 1.66 + bool Recursive; 1.67 + unsigned LockCount; 1.68 + pthread_t LockedBy; 1.69 + 1.70 + friend class WaitConditionImpl; 1.71 + 1.72 +public: 1.73 + // Constructor/destructor 1.74 + MutexImpl(Mutex* pmutex, bool recursive = 1); 1.75 + ~MutexImpl(); 1.76 + 1.77 + // Locking functions 1.78 + void DoLock(); 1.79 + bool TryLock(); 1.80 + void Unlock(Mutex* pmutex); 1.81 + // Returns 1 if the mutes is currently locked 1.82 + bool IsLockedByAnotherThread(Mutex* pmutex); 1.83 + bool IsSignaled() const; 1.84 +}; 1.85 + 1.86 +pthread_mutexattr_t Lock::RecursiveAttr; 1.87 +bool Lock::RecursiveAttrInit = 0; 1.88 + 1.89 +// *** Constructor/destructor 1.90 +MutexImpl::MutexImpl(Mutex* pmutex, bool recursive) 1.91 +{ 1.92 + OVR_UNUSED(pmutex); 1.93 + Recursive = recursive; 1.94 + LockCount = 0; 1.95 + 1.96 + if (Recursive) 1.97 + { 1.98 + if (!Lock::RecursiveAttrInit) 1.99 + { 1.100 + pthread_mutexattr_init(&Lock::RecursiveAttr); 1.101 + pthread_mutexattr_settype(&Lock::RecursiveAttr, PTHREAD_MUTEX_RECURSIVE); 1.102 + Lock::RecursiveAttrInit = 1; 1.103 + } 1.104 + 1.105 + pthread_mutex_init(&SMutex, &Lock::RecursiveAttr); 1.106 + } 1.107 + else 1.108 + pthread_mutex_init(&SMutex, 0); 1.109 +} 1.110 + 1.111 +MutexImpl::~MutexImpl() 1.112 +{ 1.113 + pthread_mutex_destroy(&SMutex); 1.114 +} 1.115 + 1.116 + 1.117 +// Lock and try lock 1.118 +void MutexImpl::DoLock() 1.119 +{ 1.120 + while (pthread_mutex_lock(&SMutex)) 1.121 + ; 1.122 + LockCount++; 1.123 + LockedBy = pthread_self(); 1.124 +} 1.125 + 1.126 +bool MutexImpl::TryLock() 1.127 +{ 1.128 + if (!pthread_mutex_trylock(&SMutex)) 1.129 + { 1.130 + LockCount++; 1.131 + LockedBy = pthread_self(); 1.132 + return 1; 1.133 + } 1.134 + 1.135 + return 0; 1.136 +} 1.137 + 1.138 +void MutexImpl::Unlock(Mutex* pmutex) 1.139 +{ 1.140 + OVR_UNUSED(pmutex); 1.141 + OVR_ASSERT(pthread_self() == LockedBy && LockCount > 0); 1.142 + 1.143 + //unsigned lockCount; 1.144 + LockCount--; 1.145 + //lockCount = LockCount; 1.146 + 1.147 + pthread_mutex_unlock(&SMutex); 1.148 +} 1.149 + 1.150 +bool MutexImpl::IsLockedByAnotherThread(Mutex* pmutex) 1.151 +{ 1.152 + OVR_UNUSED(pmutex); 1.153 + // There could be multiple interpretations of IsLocked with respect to current thread 1.154 + if (LockCount == 0) 1.155 + return 0; 1.156 + if (pthread_self() != LockedBy) 1.157 + return 1; 1.158 + return 0; 1.159 +} 1.160 + 1.161 +bool MutexImpl::IsSignaled() const 1.162 +{ 1.163 + // An mutex is signaled if it is not locked ANYWHERE 1.164 + // Note that this is different from IsLockedByAnotherThread function, 1.165 + // that takes current thread into account 1.166 + return LockCount == 0; 1.167 +} 1.168 + 1.169 + 1.170 +// *** Actual Mutex class implementation 1.171 + 1.172 +Mutex::Mutex(bool recursive) 1.173 +{ 1.174 + // NOTE: RefCount mode already thread-safe for all waitables. 1.175 + pImpl = new MutexImpl(this, recursive); 1.176 +} 1.177 + 1.178 +Mutex::~Mutex() 1.179 +{ 1.180 + delete pImpl; 1.181 +} 1.182 + 1.183 +// Lock and try lock 1.184 +void Mutex::DoLock() 1.185 +{ 1.186 + pImpl->DoLock(); 1.187 +} 1.188 +bool Mutex::TryLock() 1.189 +{ 1.190 + return pImpl->TryLock(); 1.191 +} 1.192 +void Mutex::Unlock() 1.193 +{ 1.194 + pImpl->Unlock(this); 1.195 +} 1.196 +bool Mutex::IsLockedByAnotherThread() 1.197 +{ 1.198 + return pImpl->IsLockedByAnotherThread(this); 1.199 +} 1.200 + 1.201 + 1.202 + 1.203 +//----------------------------------------------------------------------------------- 1.204 +// ***** Event 1.205 + 1.206 +bool Event::Wait(unsigned delay) 1.207 +{ 1.208 + Mutex::Locker lock(&StateMutex); 1.209 + 1.210 + // Do the correct amount of waiting 1.211 + if (delay == OVR_WAIT_INFINITE) 1.212 + { 1.213 + while(!State) 1.214 + StateWaitCondition.Wait(&StateMutex); 1.215 + } 1.216 + else if (delay) 1.217 + { 1.218 + if (!State) 1.219 + StateWaitCondition.Wait(&StateMutex, delay); 1.220 + } 1.221 + 1.222 + bool state = State; 1.223 + // Take care of temporary 'pulsing' of a state 1.224 + if (Temporary) 1.225 + { 1.226 + Temporary = false; 1.227 + State = false; 1.228 + } 1.229 + return state; 1.230 +} 1.231 + 1.232 +void Event::updateState(bool newState, bool newTemp, bool mustNotify) 1.233 +{ 1.234 + Mutex::Locker lock(&StateMutex); 1.235 + State = newState; 1.236 + Temporary = newTemp; 1.237 + if (mustNotify) 1.238 + StateWaitCondition.NotifyAll(); 1.239 +} 1.240 + 1.241 + 1.242 + 1.243 +// ***** Wait Condition Implementation 1.244 + 1.245 +// Internal implementation class 1.246 +class WaitConditionImpl : public NewOverrideBase 1.247 +{ 1.248 + pthread_mutex_t SMutex; 1.249 + pthread_cond_t Condv; 1.250 + 1.251 +public: 1.252 + 1.253 + // Constructor/destructor 1.254 + WaitConditionImpl(); 1.255 + ~WaitConditionImpl(); 1.256 + 1.257 + // Release mutex and wait for condition. The mutex is re-aqured after the wait. 1.258 + bool Wait(Mutex *pmutex, unsigned delay = OVR_WAIT_INFINITE); 1.259 + 1.260 + // Notify a condition, releasing at one object waiting 1.261 + void Notify(); 1.262 + // Notify a condition, releasing all objects waiting 1.263 + void NotifyAll(); 1.264 +}; 1.265 + 1.266 + 1.267 +WaitConditionImpl::WaitConditionImpl() 1.268 +{ 1.269 + pthread_mutex_init(&SMutex, 0); 1.270 + pthread_cond_init(&Condv, 0); 1.271 +} 1.272 + 1.273 +WaitConditionImpl::~WaitConditionImpl() 1.274 +{ 1.275 + pthread_mutex_destroy(&SMutex); 1.276 + pthread_cond_destroy(&Condv); 1.277 +} 1.278 + 1.279 +bool WaitConditionImpl::Wait(Mutex *pmutex, unsigned delay) 1.280 +{ 1.281 + bool result = 1; 1.282 + unsigned lockCount = pmutex->pImpl->LockCount; 1.283 + 1.284 + // Mutex must have been locked 1.285 + if (lockCount == 0) 1.286 + return 0; 1.287 + 1.288 + pthread_mutex_lock(&SMutex); 1.289 + 1.290 + // Finally, release a mutex or semaphore 1.291 + if (pmutex->pImpl->Recursive) 1.292 + { 1.293 + // Release the recursive mutex N times 1.294 + pmutex->pImpl->LockCount = 0; 1.295 + for(unsigned i=0; i<lockCount; i++) 1.296 + pthread_mutex_unlock(&pmutex->pImpl->SMutex); 1.297 + } 1.298 + else 1.299 + { 1.300 + pmutex->pImpl->LockCount = 0; 1.301 + pthread_mutex_unlock(&pmutex->pImpl->SMutex); 1.302 + } 1.303 + 1.304 + // Note that there is a gap here between mutex.Unlock() and Wait(). 1.305 + // The other mutex protects this gap. 1.306 + 1.307 + if (delay == OVR_WAIT_INFINITE) 1.308 + pthread_cond_wait(&Condv,&SMutex); 1.309 + else 1.310 + { 1.311 + timespec ts; 1.312 + 1.313 + struct timeval tv; 1.314 + gettimeofday(&tv, 0); 1.315 + 1.316 + ts.tv_sec = tv.tv_sec + (delay / 1000); 1.317 + ts.tv_nsec = (tv.tv_usec + (delay % 1000) * 1000) * 1000; 1.318 + 1.319 + if (ts.tv_nsec > 999999999) 1.320 + { 1.321 + ts.tv_sec++; 1.322 + ts.tv_nsec -= 1000000000; 1.323 + } 1.324 + int r = pthread_cond_timedwait(&Condv,&SMutex, &ts); 1.325 + OVR_ASSERT(r == 0 || r == ETIMEDOUT); 1.326 + if (r) 1.327 + result = 0; 1.328 + } 1.329 + 1.330 + pthread_mutex_unlock(&SMutex); 1.331 + 1.332 + // Re-aquire the mutex 1.333 + for(unsigned i=0; i<lockCount; i++) 1.334 + pmutex->DoLock(); 1.335 + 1.336 + // Return the result 1.337 + return result; 1.338 +} 1.339 + 1.340 +// Notify a condition, releasing the least object in a queue 1.341 +void WaitConditionImpl::Notify() 1.342 +{ 1.343 + pthread_mutex_lock(&SMutex); 1.344 + pthread_cond_signal(&Condv); 1.345 + pthread_mutex_unlock(&SMutex); 1.346 +} 1.347 + 1.348 +// Notify a condition, releasing all objects waiting 1.349 +void WaitConditionImpl::NotifyAll() 1.350 +{ 1.351 + pthread_mutex_lock(&SMutex); 1.352 + pthread_cond_broadcast(&Condv); 1.353 + pthread_mutex_unlock(&SMutex); 1.354 +} 1.355 + 1.356 + 1.357 + 1.358 +// *** Actual implementation of WaitCondition 1.359 + 1.360 +WaitCondition::WaitCondition() 1.361 +{ 1.362 + pImpl = new WaitConditionImpl; 1.363 +} 1.364 +WaitCondition::~WaitCondition() 1.365 +{ 1.366 + delete pImpl; 1.367 +} 1.368 + 1.369 +bool WaitCondition::Wait(Mutex *pmutex, unsigned delay) 1.370 +{ 1.371 + return pImpl->Wait(pmutex, delay); 1.372 +} 1.373 +// Notification 1.374 +void WaitCondition::Notify() 1.375 +{ 1.376 + pImpl->Notify(); 1.377 +} 1.378 +void WaitCondition::NotifyAll() 1.379 +{ 1.380 + pImpl->NotifyAll(); 1.381 +} 1.382 + 1.383 + 1.384 +// ***** Current thread 1.385 + 1.386 +// Per-thread variable 1.387 +/* 1.388 +static __thread Thread* pCurrentThread = 0; 1.389 + 1.390 +// Static function to return a pointer to the current thread 1.391 +void Thread::InitCurrentThread(Thread *pthread) 1.392 +{ 1.393 + pCurrentThread = pthread; 1.394 +} 1.395 + 1.396 +// Static function to return a pointer to the current thread 1.397 +Thread* Thread::GetThread() 1.398 +{ 1.399 + return pCurrentThread; 1.400 +} 1.401 +*/ 1.402 + 1.403 + 1.404 +// *** Thread constructors. 1.405 + 1.406 +Thread::Thread(UPInt stackSize, int processor) 1.407 +{ 1.408 + // NOTE: RefCount mode already thread-safe for all Waitable objects. 1.409 + CreateParams params; 1.410 + params.stackSize = stackSize; 1.411 + params.processor = processor; 1.412 + Init(params); 1.413 +} 1.414 + 1.415 +Thread::Thread(Thread::ThreadFn threadFunction, void* userHandle, UPInt stackSize, 1.416 + int processor, Thread::ThreadState initialState) 1.417 +{ 1.418 + CreateParams params(threadFunction, userHandle, stackSize, processor, initialState); 1.419 + Init(params); 1.420 +} 1.421 + 1.422 +Thread::Thread(const CreateParams& params) 1.423 +{ 1.424 + Init(params); 1.425 +} 1.426 + 1.427 +void Thread::Init(const CreateParams& params) 1.428 +{ 1.429 + // Clear the variables 1.430 + ThreadFlags = 0; 1.431 + ThreadHandle = 0; 1.432 + ExitCode = 0; 1.433 + SuspendCount = 0; 1.434 + StackSize = params.stackSize; 1.435 + Processor = params.processor; 1.436 + Priority = params.priority; 1.437 + 1.438 + // Clear Function pointers 1.439 + ThreadFunction = params.threadFunction; 1.440 + UserHandle = params.userHandle; 1.441 + if (params.initialState != NotRunning) 1.442 + Start(params.initialState); 1.443 +} 1.444 + 1.445 +Thread::~Thread() 1.446 +{ 1.447 + // Thread should not running while object is being destroyed, 1.448 + // this would indicate ref-counting issue. 1.449 + //OVR_ASSERT(IsRunning() == 0); 1.450 + 1.451 + // Clean up thread. 1.452 + ThreadHandle = 0; 1.453 +} 1.454 + 1.455 + 1.456 + 1.457 +// *** Overridable User functions. 1.458 + 1.459 +// Default Run implementation 1.460 +int Thread::Run() 1.461 +{ 1.462 + // Call pointer to function, if available. 1.463 + return (ThreadFunction) ? ThreadFunction(this, UserHandle) : 0; 1.464 +} 1.465 +void Thread::OnExit() 1.466 +{ 1.467 +} 1.468 + 1.469 + 1.470 +// Finishes the thread and releases internal reference to it. 1.471 +void Thread::FinishAndRelease() 1.472 +{ 1.473 + // Note: thread must be US. 1.474 + ThreadFlags &= (UInt32)~(OVR_THREAD_STARTED); 1.475 + ThreadFlags |= OVR_THREAD_FINISHED; 1.476 + 1.477 + // Release our reference; this is equivalent to 'delete this' 1.478 + // from the point of view of our thread. 1.479 + Release(); 1.480 +} 1.481 + 1.482 + 1.483 + 1.484 +// *** ThreadList - used to track all created threads 1.485 + 1.486 +class ThreadList : public NewOverrideBase 1.487 +{ 1.488 + //------------------------------------------------------------------------ 1.489 + struct ThreadHashOp 1.490 + { 1.491 + size_t operator()(const Thread* ptr) 1.492 + { 1.493 + return (((size_t)ptr) >> 6) ^ (size_t)ptr; 1.494 + } 1.495 + }; 1.496 + 1.497 + HashSet<Thread*, ThreadHashOp> ThreadSet; 1.498 + Mutex ThreadMutex; 1.499 + WaitCondition ThreadsEmpty; 1.500 + // Track the root thread that created us. 1.501 + pthread_t RootThreadId; 1.502 + 1.503 + static ThreadList* volatile pRunningThreads; 1.504 + 1.505 + void addThread(Thread *pthread) 1.506 + { 1.507 + Mutex::Locker lock(&ThreadMutex); 1.508 + ThreadSet.Add(pthread); 1.509 + } 1.510 + 1.511 + void removeThread(Thread *pthread) 1.512 + { 1.513 + Mutex::Locker lock(&ThreadMutex); 1.514 + ThreadSet.Remove(pthread); 1.515 + if (ThreadSet.GetSize() == 0) 1.516 + ThreadsEmpty.Notify(); 1.517 + } 1.518 + 1.519 + void finishAllThreads() 1.520 + { 1.521 + // Only original root thread can call this. 1.522 + OVR_ASSERT(pthread_self() == RootThreadId); 1.523 + 1.524 + Mutex::Locker lock(&ThreadMutex); 1.525 + while (ThreadSet.GetSize() != 0) 1.526 + ThreadsEmpty.Wait(&ThreadMutex); 1.527 + } 1.528 + 1.529 +public: 1.530 + 1.531 + ThreadList() 1.532 + { 1.533 + RootThreadId = pthread_self(); 1.534 + } 1.535 + ~ThreadList() { } 1.536 + 1.537 + 1.538 + static void AddRunningThread(Thread *pthread) 1.539 + { 1.540 + // Non-atomic creation ok since only the root thread 1.541 + if (!pRunningThreads) 1.542 + { 1.543 + pRunningThreads = new ThreadList; 1.544 + OVR_ASSERT(pRunningThreads); 1.545 + } 1.546 + pRunningThreads->addThread(pthread); 1.547 + } 1.548 + 1.549 + // NOTE: 'pthread' might be a dead pointer when this is 1.550 + // called so it should not be accessed; it is only used 1.551 + // for removal. 1.552 + static void RemoveRunningThread(Thread *pthread) 1.553 + { 1.554 + OVR_ASSERT(pRunningThreads); 1.555 + pRunningThreads->removeThread(pthread); 1.556 + } 1.557 + 1.558 + static void FinishAllThreads() 1.559 + { 1.560 + // This is ok because only root thread can wait for other thread finish. 1.561 + if (pRunningThreads) 1.562 + { 1.563 + pRunningThreads->finishAllThreads(); 1.564 + delete pRunningThreads; 1.565 + pRunningThreads = 0; 1.566 + } 1.567 + } 1.568 +}; 1.569 + 1.570 +// By default, we have no thread list. 1.571 +ThreadList* volatile ThreadList::pRunningThreads = 0; 1.572 + 1.573 + 1.574 +// FinishAllThreads - exposed publicly in Thread. 1.575 +void Thread::FinishAllThreads() 1.576 +{ 1.577 + ThreadList::FinishAllThreads(); 1.578 +} 1.579 + 1.580 +// *** Run override 1.581 + 1.582 +int Thread::PRun() 1.583 +{ 1.584 + // Suspend us on start, if requested 1.585 + if (ThreadFlags & OVR_THREAD_START_SUSPENDED) 1.586 + { 1.587 + Suspend(); 1.588 + ThreadFlags &= (UInt32)~OVR_THREAD_START_SUSPENDED; 1.589 + } 1.590 + 1.591 + // Call the virtual run function 1.592 + ExitCode = Run(); 1.593 + return ExitCode; 1.594 +} 1.595 + 1.596 + 1.597 + 1.598 + 1.599 +// *** User overridables 1.600 + 1.601 +bool Thread::GetExitFlag() const 1.602 +{ 1.603 + return (ThreadFlags & OVR_THREAD_EXIT) != 0; 1.604 +} 1.605 + 1.606 +void Thread::SetExitFlag(bool exitFlag) 1.607 +{ 1.608 + // The below is atomic since ThreadFlags is AtomicInt. 1.609 + if (exitFlag) 1.610 + ThreadFlags |= OVR_THREAD_EXIT; 1.611 + else 1.612 + ThreadFlags &= (UInt32) ~OVR_THREAD_EXIT; 1.613 +} 1.614 + 1.615 + 1.616 +// Determines whether the thread was running and is now finished 1.617 +bool Thread::IsFinished() const 1.618 +{ 1.619 + return (ThreadFlags & OVR_THREAD_FINISHED) != 0; 1.620 +} 1.621 +// Determines whether the thread is suspended 1.622 +bool Thread::IsSuspended() const 1.623 +{ 1.624 + return SuspendCount > 0; 1.625 +} 1.626 +// Returns current thread state 1.627 +Thread::ThreadState Thread::GetThreadState() const 1.628 +{ 1.629 + if (IsSuspended()) 1.630 + return Suspended; 1.631 + if (ThreadFlags & OVR_THREAD_STARTED) 1.632 + return Running; 1.633 + return NotRunning; 1.634 +} 1.635 + 1.636 +// Join thread 1.637 +bool Thread::Join(int maxWaitMs) const 1.638 +{ 1.639 + // If polling, 1.640 + if (maxWaitMs == 0) 1.641 + { 1.642 + // Just return if finished 1.643 + return IsFinished(); 1.644 + } 1.645 + // If waiting forever, 1.646 + else if (maxWaitMs > 0) 1.647 + { 1.648 + UInt32 t0 = Timer::GetTicksMs(); 1.649 + 1.650 + while (!IsFinished()) 1.651 + { 1.652 + UInt32 t1 = Timer::GetTicksMs(); 1.653 + 1.654 + // If the wait has expired, 1.655 + int delta = (int)(t1 - t0); 1.656 + if (delta >= maxWaitMs) 1.657 + { 1.658 + return false; 1.659 + } 1.660 + 1.661 + Thread::MSleep(10); 1.662 + } 1.663 + 1.664 + return true; 1.665 + } 1.666 + else 1.667 + { 1.668 + while (!IsFinished()) 1.669 + { 1.670 + pthread_join(ThreadHandle, NULL); 1.671 + } 1.672 + } 1.673 + 1.674 + return true; 1.675 +} 1.676 + 1.677 +/* 1.678 +static const char* mapsched_policy(int policy) 1.679 +{ 1.680 + switch(policy) 1.681 + { 1.682 + case SCHED_OTHER: 1.683 + return "SCHED_OTHER"; 1.684 + case SCHED_RR: 1.685 + return "SCHED_RR"; 1.686 + case SCHED_FIFO: 1.687 + return "SCHED_FIFO"; 1.688 + 1.689 + } 1.690 + return "UNKNOWN"; 1.691 +} 1.692 + int policy; 1.693 + sched_param sparam; 1.694 + pthread_getschedparam(pthread_self(), &policy, &sparam); 1.695 + int max_prior = sched_get_priority_max(policy); 1.696 + int min_prior = sched_get_priority_min(policy); 1.697 + printf(" !!!! policy: %s, priority: %d, max priority: %d, min priority: %d\n", mapsched_policy(policy), sparam.sched_priority, max_prior, min_prior); 1.698 +#include <stdio.h> 1.699 +*/ 1.700 +// ***** Thread management 1.701 + 1.702 +// The actual first function called on thread start 1.703 +void* Thread_PthreadStartFn(void* phandle) 1.704 +{ 1.705 + Thread* pthread = (Thread*)phandle; 1.706 + int result = pthread->PRun(); 1.707 + // Signal the thread as done and release it atomically. 1.708 + pthread->FinishAndRelease(); 1.709 + // At this point Thread object might be dead; however we can still pass 1.710 + // it to RemoveRunningThread since it is only used as a key there. 1.711 + ThreadList::RemoveRunningThread(pthread); 1.712 + return reinterpret_cast<void*>(result); 1.713 +} 1.714 + 1.715 +int Thread::InitAttr = 0; 1.716 +pthread_attr_t Thread::Attr; 1.717 + 1.718 +/* static */ 1.719 +int Thread::GetOSPriority(ThreadPriority p) 1.720 +{ 1.721 + OVR_UNUSED(p); 1.722 + return -1; 1.723 +} 1.724 + 1.725 +/* static */ 1.726 +Thread::ThreadPriority Thread::GetOVRPriority(int osPriority) 1.727 +{ 1.728 + #if defined(OVR_OS_LINUX) 1.729 + return (ThreadPriority)(Thread::NormalPriority - osPriority); // This works for both SCHED_OTHER, SCHED_RR, and SCHED_FIFO. 1.730 + #else 1.731 + // Apple priorities are such that the min is a value less than the max. 1.732 + static int minPriority = sched_get_priority_min(SCHED_FIFO); // We don't have a means to pass a policy type to this function. 1.733 + static int maxPriority = sched_get_priority_max(SCHED_FIFO); 1.734 + 1.735 + return (ThreadPriority)(Thread::NormalPriority - (osPriority - ((minPriority + maxPriority) / 2))); 1.736 + #endif 1.737 +} 1.738 + 1.739 + 1.740 +Thread::ThreadPriority Thread::GetPriority() 1.741 +{ 1.742 + int policy; 1.743 + sched_param param; 1.744 + 1.745 + int result = pthread_getschedparam(ThreadHandle, &policy, ¶m); 1.746 + 1.747 + if(result == 0) 1.748 + { 1.749 + #if !defined(OVR_OS_LINUX) 1.750 + if(policy == SCHED_OTHER) 1.751 + { 1.752 + return Thread::NormalPriority; //SCHED_OTHER allows only normal priority on BSD-style Unix and Mac OS X. 1.753 + } 1.754 + #endif 1.755 + 1.756 + return GetOVRPriority(param.sched_priority); 1.757 + } 1.758 + 1.759 + return Thread::NormalPriority; 1.760 +} 1.761 + 1.762 +/* static */ 1.763 +Thread::ThreadPriority Thread::GetCurrentPriority() 1.764 +{ 1.765 + int policy; 1.766 + sched_param param; 1.767 + pthread_t currentThreadId = pthread_self(); 1.768 + 1.769 + int result = pthread_getschedparam(currentThreadId, &policy, ¶m); 1.770 + 1.771 + if(result == 0) 1.772 + { 1.773 + #if !defined(OVR_OS_LINUX) 1.774 + if(policy == SCHED_OTHER) 1.775 + { 1.776 + return Thread::NormalPriority; //SCHED_OTHER allows only normal priority on BSD-style Unix and Mac OS X. 1.777 + } 1.778 + #endif 1.779 + 1.780 + return GetOVRPriority(param.sched_priority); 1.781 + } 1.782 + 1.783 + return Thread::NormalPriority; 1.784 +} 1.785 + 1.786 + 1.787 +bool Thread::SetPriority(ThreadPriority) 1.788 +{ 1.789 + // We currently fail. To do: add code to support this via pthread_getschedparam/pthread_attr_setschedparam 1.790 + // This won't work unless using SCHED_FIFO or SCHED_RR anyway, which require root privileges. 1.791 + return false; 1.792 +} 1.793 + 1.794 +/* static */ 1.795 +bool Thread::SetCurrentPriority(ThreadPriority) 1.796 +{ 1.797 + // We currently fail. To do: add code to support this via pthread_getschedparam/pthread_attr_setschedparam 1.798 + // This won't work unless using SCHED_FIFO or SCHED_RR anyway, which require root privileges. 1.799 + return false; 1.800 +} 1.801 + 1.802 +bool Thread::Start(ThreadState initialState) 1.803 +{ 1.804 + if (initialState == NotRunning) 1.805 + return 0; 1.806 + if (GetThreadState() != NotRunning) 1.807 + { 1.808 + OVR_DEBUG_LOG(("Thread::Start failed - thread %p already running", this)); 1.809 + return 0; 1.810 + } 1.811 + 1.812 + if (!InitAttr) 1.813 + { 1.814 + pthread_attr_init(&Attr); 1.815 + pthread_attr_setdetachstate(&Attr, PTHREAD_CREATE_DETACHED); 1.816 + pthread_attr_setstacksize(&Attr, 128 * 1024); 1.817 + sched_param sparam; 1.818 + sparam.sched_priority = Thread::GetOSPriority(NormalPriority); 1.819 + pthread_attr_setschedparam(&Attr, &sparam); 1.820 + InitAttr = 1; 1.821 + } 1.822 + 1.823 + ExitCode = 0; 1.824 + SuspendCount = 0; 1.825 + ThreadFlags = (initialState == Running) ? 0 : OVR_THREAD_START_SUSPENDED; 1.826 + 1.827 + // AddRef to us until the thread is finished 1.828 + AddRef(); 1.829 + ThreadList::AddRunningThread(this); 1.830 + 1.831 + int result; 1.832 + if (StackSize != 128 * 1024 || Priority != NormalPriority) 1.833 + { 1.834 + pthread_attr_t attr; 1.835 + 1.836 + pthread_attr_init(&attr); 1.837 + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 1.838 + pthread_attr_setstacksize(&attr, StackSize); 1.839 + sched_param sparam; 1.840 + sparam.sched_priority = Thread::GetOSPriority(Priority); 1.841 + pthread_attr_setschedparam(&attr, &sparam); 1.842 + result = pthread_create(&ThreadHandle, &attr, Thread_PthreadStartFn, this); 1.843 + pthread_attr_destroy(&attr); 1.844 + } 1.845 + else 1.846 + result = pthread_create(&ThreadHandle, &Attr, Thread_PthreadStartFn, this); 1.847 + 1.848 + if (result) 1.849 + { 1.850 + ThreadFlags = 0; 1.851 + Release(); 1.852 + ThreadList::RemoveRunningThread(this); 1.853 + return 0; 1.854 + } 1.855 + return 1; 1.856 +} 1.857 + 1.858 + 1.859 +// Suspend the thread until resumed 1.860 +bool Thread::Suspend() 1.861 +{ 1.862 + OVR_DEBUG_LOG(("Thread::Suspend - cannot suspend threads on this system")); 1.863 + return 0; 1.864 +} 1.865 + 1.866 +// Resumes currently suspended thread 1.867 +bool Thread::Resume() 1.868 +{ 1.869 + return 0; 1.870 +} 1.871 + 1.872 + 1.873 +// Quits with an exit code 1.874 +void Thread::Exit(int exitCode) 1.875 +{ 1.876 + // Can only exist the current thread 1.877 + // if (GetThread() != this) 1.878 + // return; 1.879 + 1.880 + // Call the virtual OnExit function 1.881 + OnExit(); 1.882 + 1.883 + // Signal this thread object as done and release it's references. 1.884 + FinishAndRelease(); 1.885 + ThreadList::RemoveRunningThread(this); 1.886 + 1.887 + pthread_exit(reinterpret_cast<void*>(exitCode)); 1.888 +} 1.889 + 1.890 +ThreadId GetCurrentThreadId() 1.891 +{ 1.892 + return (void*)pthread_self(); 1.893 +} 1.894 + 1.895 +// *** Sleep functions 1.896 + 1.897 +/* static */ 1.898 +bool Thread::Sleep(unsigned secs) 1.899 +{ 1.900 + sleep(secs); 1.901 + return 1; 1.902 +} 1.903 +/* static */ 1.904 +bool Thread::MSleep(unsigned msecs) 1.905 +{ 1.906 + usleep(msecs*1000); 1.907 + return 1; 1.908 +} 1.909 + 1.910 +/* static */ 1.911 +int Thread::GetCPUCount() 1.912 +{ 1.913 + #if defined(OVR_OS_MAC) || defined(OVR_OS_BSD) 1.914 + // http://developer.apple.com/mac/library/documentation/Darwin/Reference/ManPages/man3/sysctlbyname.3.html 1.915 + int cpuCount = 0; 1.916 + size_t len = sizeof(cpuCount); 1.917 + 1.918 + if(sysctlbyname("hw.logicalcpu", &cpuCount, &len, NULL, 0) != 0) 1.919 + cpuCount = 1; 1.920 + 1.921 + return cpuCount; 1.922 + 1.923 + #else // Linux, Android 1.924 + 1.925 + // Alternative: read /proc/cpuinfo 1.926 + #ifdef _SC_NPROCESSORS_ONLN 1.927 + return (int)sysconf(_SC_NPROCESSORS_ONLN); 1.928 + #else 1.929 + return 1; 1.930 + #endif 1.931 + #endif 1.932 +} 1.933 + 1.934 + 1.935 +void Thread::SetThreadName( const char* name ) 1.936 +{ 1.937 + #if defined (OVR_OS_APPLE) 1.938 + if(ThreadHandle == pthread_self()) 1.939 + pthread_setname_np(name); 1.940 + // Else there's nothing we can do. 1.941 + #else 1.942 + if(ThreadHandle != 0) 1.943 + pthread_setname_np(ThreadHandle, name); 1.944 + // Else we can possibly save this name and set it later when the thread starts. 1.945 + #endif 1.946 +} 1.947 + 1.948 + 1.949 +void Thread::SetThreadName(const char* name, ThreadId threadId) 1.950 +{ 1.951 + #if defined (OVR_OS_APPLE) 1.952 + if(pthread_equal((pthread_t)threadId, pthread_self())) 1.953 + pthread_setname_np(name); 1.954 + // Else there's no way to set the name of another thread. 1.955 + #else 1.956 + pthread_setname_np((pthread_t)threadId, name); 1.957 + #endif 1.958 +} 1.959 + 1.960 + 1.961 +void Thread::SetCurrentThreadName(const char* name) 1.962 +{ 1.963 + #if defined (OVR_OS_APPLE) 1.964 + pthread_setname_np(name); 1.965 + #else 1.966 + pthread_setname_np(pthread_self(), name); 1.967 + #endif 1.968 +} 1.969 + 1.970 + 1.971 +void Thread::GetThreadName(char* name, size_t nameCapacity, ThreadId threadId) 1.972 +{ 1.973 + name[0] = 0; 1.974 + pthread_getname_np((pthread_t)threadId, name, nameCapacity); 1.975 +} 1.976 + 1.977 + 1.978 +void Thread::GetCurrentThreadName(char* name, size_t nameCapacity) 1.979 +{ 1.980 + name[0] = 0; 1.981 + pthread_getname_np(pthread_self(), name, nameCapacity); 1.982 +} 1.983 + 1.984 + 1.985 +} // namespace OVR 1.986 + 1.987 +#endif // OVR_ENABLE_THREADS