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