nuclear@3: nuclear@3: #include "OVR_Threads.h" nuclear@3: #include "OVR_Hash.h" nuclear@3: nuclear@3: #ifdef OVR_ENABLE_THREADS nuclear@3: nuclear@3: #include "OVR_Timer.h" nuclear@3: #include "OVR_Log.h" nuclear@3: nuclear@3: #include nuclear@3: #include nuclear@3: nuclear@3: #ifdef OVR_OS_PS3 nuclear@3: #include nuclear@3: #include nuclear@3: #include nuclear@3: #define sleep(x) sys_timer_sleep(x) nuclear@3: #define usleep(x) sys_timer_usleep(x) nuclear@3: using std::timespec; nuclear@3: #else nuclear@3: #include nuclear@3: #include nuclear@3: #include nuclear@3: #endif nuclear@3: nuclear@3: namespace OVR { nuclear@3: nuclear@3: // ***** Mutex implementation nuclear@3: nuclear@3: nuclear@3: // *** Internal Mutex implementation structure nuclear@3: nuclear@3: class MutexImpl : public NewOverrideBase nuclear@3: { nuclear@3: // System mutex or semaphore nuclear@3: pthread_mutex_t SMutex; nuclear@3: bool Recursive; nuclear@3: unsigned LockCount; nuclear@3: pthread_t LockedBy; nuclear@3: nuclear@3: friend class WaitConditionImpl; nuclear@3: nuclear@3: public: nuclear@3: // Constructor/destructor nuclear@3: MutexImpl(Mutex* pmutex, bool recursive = 1); nuclear@3: ~MutexImpl(); nuclear@3: nuclear@3: // Locking functions nuclear@3: void DoLock(); nuclear@3: bool TryLock(); nuclear@3: void Unlock(Mutex* pmutex); nuclear@3: // Returns 1 if the mutes is currently locked nuclear@3: bool IsLockedByAnotherThread(Mutex* pmutex); nuclear@3: bool IsSignaled() const; nuclear@3: }; nuclear@3: nuclear@3: pthread_mutexattr_t Lock::RecursiveAttr; nuclear@3: bool Lock::RecursiveAttrInit = 0; nuclear@3: nuclear@3: // *** Constructor/destructor nuclear@3: MutexImpl::MutexImpl(Mutex* pmutex, bool recursive) nuclear@3: { nuclear@3: Recursive = recursive; nuclear@3: LockCount = 0; nuclear@3: nuclear@3: if (Recursive) nuclear@3: { nuclear@3: if (!Lock::RecursiveAttrInit) nuclear@3: { nuclear@3: pthread_mutexattr_init(&Lock::RecursiveAttr); nuclear@3: pthread_mutexattr_settype(&Lock::RecursiveAttr, PTHREAD_MUTEX_RECURSIVE); nuclear@3: Lock::RecursiveAttrInit = 1; nuclear@3: } nuclear@3: nuclear@3: pthread_mutex_init(&SMutex, &Lock::RecursiveAttr); nuclear@3: } nuclear@3: else nuclear@3: pthread_mutex_init(&SMutex, 0); nuclear@3: } nuclear@3: nuclear@3: MutexImpl::~MutexImpl() nuclear@3: { nuclear@3: pthread_mutex_destroy(&SMutex); nuclear@3: } nuclear@3: nuclear@3: nuclear@3: // Lock and try lock nuclear@3: void MutexImpl::DoLock() nuclear@3: { nuclear@3: while (pthread_mutex_lock(&SMutex)); nuclear@3: LockCount++; nuclear@3: LockedBy = pthread_self(); nuclear@3: } nuclear@3: nuclear@3: bool MutexImpl::TryLock() nuclear@3: { nuclear@3: if (!pthread_mutex_trylock(&SMutex)) nuclear@3: { nuclear@3: LockCount++; nuclear@3: LockedBy = pthread_self(); nuclear@3: return 1; nuclear@3: } nuclear@3: nuclear@3: return 0; nuclear@3: } nuclear@3: nuclear@3: void MutexImpl::Unlock(Mutex* pmutex) nuclear@3: { nuclear@3: OVR_ASSERT(pthread_self() == LockedBy && LockCount > 0); nuclear@3: nuclear@3: unsigned lockCount; nuclear@3: LockCount--; nuclear@3: lockCount = LockCount; nuclear@3: nuclear@3: pthread_mutex_unlock(&SMutex); nuclear@3: } nuclear@3: nuclear@3: bool MutexImpl::IsLockedByAnotherThread(Mutex* pmutex) nuclear@3: { nuclear@3: // There could be multiple interpretations of IsLocked with respect to current thread nuclear@3: if (LockCount == 0) nuclear@3: return 0; nuclear@3: if (pthread_self() != LockedBy) nuclear@3: return 1; nuclear@3: return 0; nuclear@3: } nuclear@3: nuclear@3: bool MutexImpl::IsSignaled() const nuclear@3: { nuclear@3: // An mutex is signaled if it is not locked ANYWHERE nuclear@3: // Note that this is different from IsLockedByAnotherThread function, nuclear@3: // that takes current thread into account nuclear@3: return LockCount == 0; nuclear@3: } nuclear@3: nuclear@3: nuclear@3: // *** Actual Mutex class implementation nuclear@3: nuclear@3: Mutex::Mutex(bool recursive) nuclear@3: { nuclear@3: // NOTE: RefCount mode already thread-safe for all waitables. nuclear@3: pImpl = new MutexImpl(this, recursive); nuclear@3: } nuclear@3: nuclear@3: Mutex::~Mutex() nuclear@3: { nuclear@3: delete pImpl; nuclear@3: } nuclear@3: nuclear@3: // Lock and try lock nuclear@3: void Mutex::DoLock() nuclear@3: { nuclear@3: pImpl->DoLock(); nuclear@3: } nuclear@3: bool Mutex::TryLock() nuclear@3: { nuclear@3: return pImpl->TryLock(); nuclear@3: } nuclear@3: void Mutex::Unlock() nuclear@3: { nuclear@3: pImpl->Unlock(this); nuclear@3: } nuclear@3: bool Mutex::IsLockedByAnotherThread() nuclear@3: { nuclear@3: return pImpl->IsLockedByAnotherThread(this); nuclear@3: } nuclear@3: nuclear@3: nuclear@3: nuclear@3: //----------------------------------------------------------------------------------- nuclear@3: // ***** Event nuclear@3: nuclear@3: bool Event::Wait(unsigned delay) nuclear@3: { nuclear@3: Mutex::Locker lock(&StateMutex); nuclear@3: nuclear@3: // Do the correct amount of waiting nuclear@3: if (delay == OVR_WAIT_INFINITE) nuclear@3: { nuclear@3: while(!State) nuclear@3: StateWaitCondition.Wait(&StateMutex); nuclear@3: } nuclear@3: else if (delay) nuclear@3: { nuclear@3: if (!State) nuclear@3: StateWaitCondition.Wait(&StateMutex, delay); nuclear@3: } nuclear@3: nuclear@3: bool state = State; nuclear@3: // Take care of temporary 'pulsing' of a state nuclear@3: if (Temporary) nuclear@3: { nuclear@3: Temporary = false; nuclear@3: State = false; nuclear@3: } nuclear@3: return state; nuclear@3: } nuclear@3: nuclear@3: void Event::updateState(bool newState, bool newTemp, bool mustNotify) nuclear@3: { nuclear@3: Mutex::Locker lock(&StateMutex); nuclear@3: State = newState; nuclear@3: Temporary = newTemp; nuclear@3: if (mustNotify) nuclear@3: StateWaitCondition.NotifyAll(); nuclear@3: } nuclear@3: nuclear@3: nuclear@3: nuclear@3: // ***** Wait Condition Implementation nuclear@3: nuclear@3: // Internal implementation class nuclear@3: class WaitConditionImpl : public NewOverrideBase nuclear@3: { nuclear@3: pthread_mutex_t SMutex; nuclear@3: pthread_cond_t Condv; nuclear@3: nuclear@3: public: nuclear@3: nuclear@3: // Constructor/destructor nuclear@3: WaitConditionImpl(); nuclear@3: ~WaitConditionImpl(); nuclear@3: nuclear@3: // Release mutex and wait for condition. The mutex is re-aqured after the wait. nuclear@3: bool Wait(Mutex *pmutex, unsigned delay = OVR_WAIT_INFINITE); nuclear@3: nuclear@3: // Notify a condition, releasing at one object waiting nuclear@3: void Notify(); nuclear@3: // Notify a condition, releasing all objects waiting nuclear@3: void NotifyAll(); nuclear@3: }; nuclear@3: nuclear@3: nuclear@3: WaitConditionImpl::WaitConditionImpl() nuclear@3: { nuclear@3: pthread_mutex_init(&SMutex, 0); nuclear@3: pthread_cond_init(&Condv, 0); nuclear@3: } nuclear@3: nuclear@3: WaitConditionImpl::~WaitConditionImpl() nuclear@3: { nuclear@3: pthread_mutex_destroy(&SMutex); nuclear@3: pthread_cond_destroy(&Condv); nuclear@3: } nuclear@3: nuclear@3: bool WaitConditionImpl::Wait(Mutex *pmutex, unsigned delay) nuclear@3: { nuclear@3: bool result = 1; nuclear@3: unsigned lockCount = pmutex->pImpl->LockCount; nuclear@3: nuclear@3: // Mutex must have been locked nuclear@3: if (lockCount == 0) nuclear@3: return 0; nuclear@3: nuclear@3: pthread_mutex_lock(&SMutex); nuclear@3: nuclear@3: // Finally, release a mutex or semaphore nuclear@3: if (pmutex->pImpl->Recursive) nuclear@3: { nuclear@3: // Release the recursive mutex N times nuclear@3: pmutex->pImpl->LockCount = 0; nuclear@3: for(unsigned i=0; ipImpl->SMutex); nuclear@3: } nuclear@3: else nuclear@3: { nuclear@3: pmutex->pImpl->LockCount = 0; nuclear@3: pthread_mutex_unlock(&pmutex->pImpl->SMutex); nuclear@3: } nuclear@3: nuclear@3: // Note that there is a gap here between mutex.Unlock() and Wait(). nuclear@3: // The other mutex protects this gap. nuclear@3: nuclear@3: if (delay == OVR_WAIT_INFINITE) nuclear@3: pthread_cond_wait(&Condv,&SMutex); nuclear@3: else nuclear@3: { nuclear@3: timespec ts; nuclear@3: #ifdef OVR_OS_PS3 nuclear@3: sys_time_sec_t s; nuclear@3: sys_time_nsec_t ns; nuclear@3: sys_time_get_current_time(&s, &ns); nuclear@3: nuclear@3: ts.tv_sec = s + (delay / 1000); nuclear@3: ts.tv_nsec = ns + (delay % 1000) * 1000000; nuclear@3: nuclear@3: #else nuclear@3: struct timeval tv; nuclear@3: gettimeofday(&tv, 0); nuclear@3: nuclear@3: ts.tv_sec = tv.tv_sec + (delay / 1000); nuclear@3: ts.tv_nsec = (tv.tv_usec + (delay % 1000) * 1000) * 1000; nuclear@3: #endif nuclear@3: if (ts.tv_nsec > 999999999) nuclear@3: { nuclear@3: ts.tv_sec++; nuclear@3: ts.tv_nsec -= 1000000000; nuclear@3: } nuclear@3: int r = pthread_cond_timedwait(&Condv,&SMutex, &ts); nuclear@3: OVR_ASSERT(r == 0 || r == ETIMEDOUT); nuclear@3: if (r) nuclear@3: result = 0; nuclear@3: } nuclear@3: nuclear@3: pthread_mutex_unlock(&SMutex); nuclear@3: nuclear@3: // Re-aquire the mutex nuclear@3: for(unsigned i=0; iDoLock(); nuclear@3: nuclear@3: // Return the result nuclear@3: return result; nuclear@3: } nuclear@3: nuclear@3: // Notify a condition, releasing the least object in a queue nuclear@3: void WaitConditionImpl::Notify() nuclear@3: { nuclear@3: pthread_mutex_lock(&SMutex); nuclear@3: pthread_cond_signal(&Condv); nuclear@3: pthread_mutex_unlock(&SMutex); nuclear@3: } nuclear@3: nuclear@3: // Notify a condition, releasing all objects waiting nuclear@3: void WaitConditionImpl::NotifyAll() nuclear@3: { nuclear@3: pthread_mutex_lock(&SMutex); nuclear@3: pthread_cond_broadcast(&Condv); nuclear@3: pthread_mutex_unlock(&SMutex); nuclear@3: } nuclear@3: nuclear@3: nuclear@3: nuclear@3: // *** Actual implementation of WaitCondition nuclear@3: nuclear@3: WaitCondition::WaitCondition() nuclear@3: { nuclear@3: pImpl = new WaitConditionImpl; nuclear@3: } nuclear@3: WaitCondition::~WaitCondition() nuclear@3: { nuclear@3: delete pImpl; nuclear@3: } nuclear@3: nuclear@3: bool WaitCondition::Wait(Mutex *pmutex, unsigned delay) nuclear@3: { nuclear@3: return pImpl->Wait(pmutex, delay); nuclear@3: } nuclear@3: // Notification nuclear@3: void WaitCondition::Notify() nuclear@3: { nuclear@3: pImpl->Notify(); nuclear@3: } nuclear@3: void WaitCondition::NotifyAll() nuclear@3: { nuclear@3: pImpl->NotifyAll(); nuclear@3: } nuclear@3: nuclear@3: nuclear@3: // ***** Current thread nuclear@3: nuclear@3: // Per-thread variable nuclear@3: /* nuclear@3: static __thread Thread* pCurrentThread = 0; nuclear@3: nuclear@3: // Static function to return a pointer to the current thread nuclear@3: void Thread::InitCurrentThread(Thread *pthread) nuclear@3: { nuclear@3: pCurrentThread = pthread; nuclear@3: } nuclear@3: nuclear@3: // Static function to return a pointer to the current thread nuclear@3: Thread* Thread::GetThread() nuclear@3: { nuclear@3: return pCurrentThread; nuclear@3: } nuclear@3: */ nuclear@3: nuclear@3: nuclear@3: // *** Thread constructors. nuclear@3: nuclear@3: Thread::Thread(UPInt stackSize, int processor) nuclear@3: { nuclear@3: // NOTE: RefCount mode already thread-safe for all Waitable objects. nuclear@3: CreateParams params; nuclear@3: params.stackSize = stackSize; nuclear@3: params.processor = processor; nuclear@3: Init(params); nuclear@3: } nuclear@3: nuclear@3: Thread::Thread(Thread::ThreadFn threadFunction, void* userHandle, UPInt stackSize, nuclear@3: int processor, Thread::ThreadState initialState) nuclear@3: { nuclear@3: CreateParams params(threadFunction, userHandle, stackSize, processor, initialState); nuclear@3: Init(params); nuclear@3: } nuclear@3: nuclear@3: Thread::Thread(const CreateParams& params) nuclear@3: { nuclear@3: Init(params); nuclear@3: } nuclear@3: nuclear@3: void Thread::Init(const CreateParams& params) nuclear@3: { nuclear@3: // Clear the variables nuclear@3: ThreadFlags = 0; nuclear@3: ThreadHandle = 0; nuclear@3: ExitCode = 0; nuclear@3: SuspendCount = 0; nuclear@3: StackSize = params.stackSize; nuclear@3: Processor = params.processor; nuclear@3: Priority = params.priority; nuclear@3: nuclear@3: // Clear Function pointers nuclear@3: ThreadFunction = params.threadFunction; nuclear@3: UserHandle = params.userHandle; nuclear@3: if (params.initialState != NotRunning) nuclear@3: Start(params.initialState); nuclear@3: } nuclear@3: nuclear@3: Thread::~Thread() nuclear@3: { nuclear@3: // Thread should not running while object is being destroyed, nuclear@3: // this would indicate ref-counting issue. nuclear@3: //OVR_ASSERT(IsRunning() == 0); nuclear@3: nuclear@3: // Clean up thread. nuclear@3: ThreadHandle = 0; nuclear@3: } nuclear@3: nuclear@3: nuclear@3: nuclear@3: // *** Overridable User functions. nuclear@3: nuclear@3: // Default Run implementation nuclear@3: int Thread::Run() nuclear@3: { nuclear@3: // Call pointer to function, if available. nuclear@3: return (ThreadFunction) ? ThreadFunction(this, UserHandle) : 0; nuclear@3: } nuclear@3: void Thread::OnExit() nuclear@3: { nuclear@3: } nuclear@3: nuclear@3: nuclear@3: // Finishes the thread and releases internal reference to it. nuclear@3: void Thread::FinishAndRelease() nuclear@3: { nuclear@3: // Note: thread must be US. nuclear@3: ThreadFlags &= (UInt32)~(OVR_THREAD_STARTED); nuclear@3: ThreadFlags |= OVR_THREAD_FINISHED; nuclear@3: nuclear@3: // Release our reference; this is equivalent to 'delete this' nuclear@3: // from the point of view of our thread. nuclear@3: Release(); nuclear@3: } nuclear@3: nuclear@3: nuclear@3: nuclear@3: // *** ThreadList - used to track all created threads nuclear@3: nuclear@3: class ThreadList : public NewOverrideBase nuclear@3: { nuclear@3: //------------------------------------------------------------------------ nuclear@3: struct ThreadHashOp nuclear@3: { nuclear@3: size_t operator()(const Thread* ptr) nuclear@3: { nuclear@3: return (((size_t)ptr) >> 6) ^ (size_t)ptr; nuclear@3: } nuclear@3: }; nuclear@3: nuclear@3: HashSet ThreadSet; nuclear@3: Mutex ThreadMutex; nuclear@3: WaitCondition ThreadsEmpty; nuclear@3: // Track the root thread that created us. nuclear@3: pthread_t RootThreadId; nuclear@3: nuclear@3: static ThreadList* volatile pRunningThreads; nuclear@3: nuclear@3: void addThread(Thread *pthread) nuclear@3: { nuclear@3: Mutex::Locker lock(&ThreadMutex); nuclear@3: ThreadSet.Add(pthread); nuclear@3: } nuclear@3: nuclear@3: void removeThread(Thread *pthread) nuclear@3: { nuclear@3: Mutex::Locker lock(&ThreadMutex); nuclear@3: ThreadSet.Remove(pthread); nuclear@3: if (ThreadSet.GetSize() == 0) nuclear@3: ThreadsEmpty.Notify(); nuclear@3: } nuclear@3: nuclear@3: void finishAllThreads() nuclear@3: { nuclear@3: // Only original root thread can call this. nuclear@3: OVR_ASSERT(pthread_self() == RootThreadId); nuclear@3: nuclear@3: Mutex::Locker lock(&ThreadMutex); nuclear@3: while (ThreadSet.GetSize() != 0) nuclear@3: ThreadsEmpty.Wait(&ThreadMutex); nuclear@3: } nuclear@3: nuclear@3: public: nuclear@3: nuclear@3: ThreadList() nuclear@3: { nuclear@3: RootThreadId = pthread_self(); nuclear@3: } nuclear@3: ~ThreadList() { } nuclear@3: nuclear@3: nuclear@3: static void AddRunningThread(Thread *pthread) nuclear@3: { nuclear@3: // Non-atomic creation ok since only the root thread nuclear@3: if (!pRunningThreads) nuclear@3: { nuclear@3: pRunningThreads = new ThreadList; nuclear@3: OVR_ASSERT(pRunningThreads); nuclear@3: } nuclear@3: pRunningThreads->addThread(pthread); nuclear@3: } nuclear@3: nuclear@3: // NOTE: 'pthread' might be a dead pointer when this is nuclear@3: // called so it should not be accessed; it is only used nuclear@3: // for removal. nuclear@3: static void RemoveRunningThread(Thread *pthread) nuclear@3: { nuclear@3: OVR_ASSERT(pRunningThreads); nuclear@3: pRunningThreads->removeThread(pthread); nuclear@3: } nuclear@3: nuclear@3: static void FinishAllThreads() nuclear@3: { nuclear@3: // This is ok because only root thread can wait for other thread finish. nuclear@3: if (pRunningThreads) nuclear@3: { nuclear@3: pRunningThreads->finishAllThreads(); nuclear@3: delete pRunningThreads; nuclear@3: pRunningThreads = 0; nuclear@3: } nuclear@3: } nuclear@3: }; nuclear@3: nuclear@3: // By default, we have no thread list. nuclear@3: ThreadList* volatile ThreadList::pRunningThreads = 0; nuclear@3: nuclear@3: nuclear@3: // FinishAllThreads - exposed publicly in Thread. nuclear@3: void Thread::FinishAllThreads() nuclear@3: { nuclear@3: ThreadList::FinishAllThreads(); nuclear@3: } nuclear@3: nuclear@3: // *** Run override nuclear@3: nuclear@3: int Thread::PRun() nuclear@3: { nuclear@3: // Suspend us on start, if requested nuclear@3: if (ThreadFlags & OVR_THREAD_START_SUSPENDED) nuclear@3: { nuclear@3: Suspend(); nuclear@3: ThreadFlags &= (UInt32)~OVR_THREAD_START_SUSPENDED; nuclear@3: } nuclear@3: nuclear@3: // Call the virtual run function nuclear@3: ExitCode = Run(); nuclear@3: return ExitCode; nuclear@3: } nuclear@3: nuclear@3: nuclear@3: nuclear@3: nuclear@3: // *** User overridables nuclear@3: nuclear@3: bool Thread::GetExitFlag() const nuclear@3: { nuclear@3: return (ThreadFlags & OVR_THREAD_EXIT) != 0; nuclear@3: } nuclear@3: nuclear@3: void Thread::SetExitFlag(bool exitFlag) nuclear@3: { nuclear@3: // The below is atomic since ThreadFlags is AtomicInt. nuclear@3: if (exitFlag) nuclear@3: ThreadFlags |= OVR_THREAD_EXIT; nuclear@3: else nuclear@3: ThreadFlags &= (UInt32) ~OVR_THREAD_EXIT; nuclear@3: } nuclear@3: nuclear@3: nuclear@3: // Determines whether the thread was running and is now finished nuclear@3: bool Thread::IsFinished() const nuclear@3: { nuclear@3: return (ThreadFlags & OVR_THREAD_FINISHED) != 0; nuclear@3: } nuclear@3: // Determines whether the thread is suspended nuclear@3: bool Thread::IsSuspended() const nuclear@3: { nuclear@3: return SuspendCount > 0; nuclear@3: } nuclear@3: // Returns current thread state nuclear@3: Thread::ThreadState Thread::GetThreadState() const nuclear@3: { nuclear@3: if (IsSuspended()) nuclear@3: return Suspended; nuclear@3: if (ThreadFlags & OVR_THREAD_STARTED) nuclear@3: return Running; nuclear@3: return NotRunning; nuclear@3: } nuclear@3: /* nuclear@3: static const char* mapsched_policy(int policy) nuclear@3: { nuclear@3: switch(policy) nuclear@3: { nuclear@3: case SCHED_OTHER: nuclear@3: return "SCHED_OTHER"; nuclear@3: case SCHED_RR: nuclear@3: return "SCHED_RR"; nuclear@3: case SCHED_FIFO: nuclear@3: return "SCHED_FIFO"; nuclear@3: nuclear@3: } nuclear@3: return "UNKNOWN"; nuclear@3: } nuclear@3: int policy; nuclear@3: sched_param sparam; nuclear@3: pthread_getschedparam(pthread_self(), &policy, &sparam); nuclear@3: int max_prior = sched_get_priority_max(policy); nuclear@3: int min_prior = sched_get_priority_min(policy); nuclear@3: printf(" !!!! policy: %s, priority: %d, max priority: %d, min priority: %d\n", mapsched_policy(policy), sparam.sched_priority, max_prior, min_prior); nuclear@3: #include nuclear@3: */ nuclear@3: // ***** Thread management nuclear@3: nuclear@3: // The actual first function called on thread start nuclear@3: void* Thread_PthreadStartFn(void* phandle) nuclear@3: { nuclear@3: Thread* pthread = (Thread*)phandle; nuclear@3: int result = pthread->PRun(); nuclear@3: // Signal the thread as done and release it atomically. nuclear@3: pthread->FinishAndRelease(); nuclear@3: // At this point Thread object might be dead; however we can still pass nuclear@3: // it to RemoveRunningThread since it is only used as a key there. nuclear@3: ThreadList::RemoveRunningThread(pthread); nuclear@3: return (void*) result; nuclear@3: } nuclear@3: nuclear@3: int Thread::InitAttr = 0; nuclear@3: pthread_attr_t Thread::Attr; nuclear@3: nuclear@3: /* static */ nuclear@3: int Thread::GetOSPriority(ThreadPriority p) nuclear@3: //static inline int MapToSystemPrority(Thread::ThreadPriority p) nuclear@3: { nuclear@3: #ifdef OVR_OS_PS3 nuclear@3: switch(p) nuclear@3: { nuclear@3: case Thread::CriticalPriority: return 0; nuclear@3: case Thread::HighestPriority: return 300; nuclear@3: case Thread::AboveNormalPriority: return 600; nuclear@3: case Thread::NormalPriority: return 1000; nuclear@3: case Thread::BelowNormalPriority: return 1500; nuclear@3: case Thread::LowestPriority: return 2500; nuclear@3: case Thread::IdlePriority: return 3071; nuclear@3: } return 1000; nuclear@3: #else nuclear@3: OVR_UNUSED(p); nuclear@3: return -1; nuclear@3: #endif nuclear@3: } nuclear@3: nuclear@3: bool Thread::Start(ThreadState initialState) nuclear@3: { nuclear@3: if (initialState == NotRunning) nuclear@3: return 0; nuclear@3: if (GetThreadState() != NotRunning) nuclear@3: { nuclear@3: OVR_DEBUG_LOG(("Thread::Start failed - thread %p already running", this)); nuclear@3: return 0; nuclear@3: } nuclear@3: nuclear@3: if (!InitAttr) nuclear@3: { nuclear@3: pthread_attr_init(&Attr); nuclear@3: pthread_attr_setdetachstate(&Attr, PTHREAD_CREATE_DETACHED); nuclear@3: pthread_attr_setstacksize(&Attr, 128 * 1024); nuclear@3: sched_param sparam; nuclear@3: sparam.sched_priority = Thread::GetOSPriority(NormalPriority); nuclear@3: pthread_attr_setschedparam(&Attr, &sparam); nuclear@3: InitAttr = 1; nuclear@3: } nuclear@3: nuclear@3: ExitCode = 0; nuclear@3: SuspendCount = 0; nuclear@3: ThreadFlags = (initialState == Running) ? 0 : OVR_THREAD_START_SUSPENDED; nuclear@3: nuclear@3: // AddRef to us until the thread is finished nuclear@3: AddRef(); nuclear@3: ThreadList::AddRunningThread(this); nuclear@3: nuclear@3: int result; nuclear@3: if (StackSize != 128 * 1024 || Priority != NormalPriority) nuclear@3: { nuclear@3: pthread_attr_t attr; nuclear@3: nuclear@3: pthread_attr_init(&attr); nuclear@3: pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); nuclear@3: pthread_attr_setstacksize(&attr, StackSize); nuclear@3: sched_param sparam; nuclear@3: sparam.sched_priority = Thread::GetOSPriority(Priority); nuclear@3: pthread_attr_setschedparam(&attr, &sparam); nuclear@3: result = pthread_create(&ThreadHandle, &attr, Thread_PthreadStartFn, this); nuclear@3: pthread_attr_destroy(&attr); nuclear@3: } nuclear@3: else nuclear@3: result = pthread_create(&ThreadHandle, &Attr, Thread_PthreadStartFn, this); nuclear@3: nuclear@3: if (result) nuclear@3: { nuclear@3: ThreadFlags = 0; nuclear@3: Release(); nuclear@3: ThreadList::RemoveRunningThread(this); nuclear@3: return 0; nuclear@3: } nuclear@3: return 1; nuclear@3: } nuclear@3: nuclear@3: nuclear@3: // Suspend the thread until resumed nuclear@3: bool Thread::Suspend() nuclear@3: { nuclear@3: OVR_DEBUG_LOG(("Thread::Suspend - cannot suspend threads on this system")); nuclear@3: return 0; nuclear@3: } nuclear@3: nuclear@3: // Resumes currently suspended thread nuclear@3: bool Thread::Resume() nuclear@3: { nuclear@3: return 0; nuclear@3: } nuclear@3: nuclear@3: nuclear@3: // Quits with an exit code nuclear@3: void Thread::Exit(int exitCode) nuclear@3: { nuclear@3: // Can only exist the current thread nuclear@3: // if (GetThread() != this) nuclear@3: // return; nuclear@3: nuclear@3: // Call the virtual OnExit function nuclear@3: OnExit(); nuclear@3: nuclear@3: // Signal this thread object as done and release it's references. nuclear@3: FinishAndRelease(); nuclear@3: ThreadList::RemoveRunningThread(this); nuclear@3: nuclear@3: pthread_exit((void *) exitCode); nuclear@3: } nuclear@3: nuclear@3: ThreadId GetCurrentThreadId() nuclear@3: { nuclear@3: return (void*)pthread_self(); nuclear@3: } nuclear@3: nuclear@3: // *** Sleep functions nuclear@3: nuclear@3: /* static */ nuclear@3: bool Thread::Sleep(unsigned secs) nuclear@3: { nuclear@3: sleep(secs); nuclear@3: return 1; nuclear@3: } nuclear@3: /* static */ nuclear@3: bool Thread::MSleep(unsigned msecs) nuclear@3: { nuclear@3: usleep(msecs*1000); nuclear@3: return 1; nuclear@3: } nuclear@3: nuclear@3: /* static */ nuclear@3: int Thread::GetCPUCount() nuclear@3: { nuclear@3: return 1; nuclear@3: } nuclear@3: nuclear@3: nuclear@3: #ifdef OVR_OS_PS3 nuclear@3: nuclear@3: sys_lwmutex_attribute_t Lock::LockAttr = { SYS_SYNC_PRIORITY, SYS_SYNC_RECURSIVE }; nuclear@3: nuclear@3: #endif nuclear@3: nuclear@3: } nuclear@3: nuclear@3: #endif // OVR_ENABLE_THREADS