oculus1

annotate libovr/Src/osx/OVR_ThreadsPthread.cpp @ 10:b2abb08c8f94

proper FPS-style vr tracking
author John Tsiombikas <nuclear@member.fsf.org>
date Fri, 20 Sep 2013 06:49:39 +0300
parents e2f9e4603129
children
rev   line source
nuclear@3 1
nuclear@3 2 #include "OVR_Threads.h"
nuclear@3 3 #include "OVR_Hash.h"
nuclear@3 4
nuclear@3 5 #ifdef OVR_ENABLE_THREADS
nuclear@3 6
nuclear@3 7 #include "OVR_Timer.h"
nuclear@3 8 #include "OVR_Log.h"
nuclear@3 9
nuclear@3 10 #include <pthread.h>
nuclear@3 11 #include <time.h>
nuclear@3 12
nuclear@3 13 #ifdef OVR_OS_PS3
nuclear@3 14 #include <sys/sys_time.h>
nuclear@3 15 #include <sys/timer.h>
nuclear@3 16 #include <sys/synchronization.h>
nuclear@3 17 #define sleep(x) sys_timer_sleep(x)
nuclear@3 18 #define usleep(x) sys_timer_usleep(x)
nuclear@3 19 using std::timespec;
nuclear@3 20 #else
nuclear@3 21 #include <unistd.h>
nuclear@3 22 #include <sys/time.h>
nuclear@3 23 #include <errno.h>
nuclear@3 24 #endif
nuclear@3 25
nuclear@3 26 namespace OVR {
nuclear@3 27
nuclear@3 28 // ***** Mutex implementation
nuclear@3 29
nuclear@3 30
nuclear@3 31 // *** Internal Mutex implementation structure
nuclear@3 32
nuclear@3 33 class MutexImpl : public NewOverrideBase
nuclear@3 34 {
nuclear@3 35 // System mutex or semaphore
nuclear@3 36 pthread_mutex_t SMutex;
nuclear@3 37 bool Recursive;
nuclear@3 38 unsigned LockCount;
nuclear@3 39 pthread_t LockedBy;
nuclear@3 40
nuclear@3 41 friend class WaitConditionImpl;
nuclear@3 42
nuclear@3 43 public:
nuclear@3 44 // Constructor/destructor
nuclear@3 45 MutexImpl(Mutex* pmutex, bool recursive = 1);
nuclear@3 46 ~MutexImpl();
nuclear@3 47
nuclear@3 48 // Locking functions
nuclear@3 49 void DoLock();
nuclear@3 50 bool TryLock();
nuclear@3 51 void Unlock(Mutex* pmutex);
nuclear@3 52 // Returns 1 if the mutes is currently locked
nuclear@3 53 bool IsLockedByAnotherThread(Mutex* pmutex);
nuclear@3 54 bool IsSignaled() const;
nuclear@3 55 };
nuclear@3 56
nuclear@3 57 pthread_mutexattr_t Lock::RecursiveAttr;
nuclear@3 58 bool Lock::RecursiveAttrInit = 0;
nuclear@3 59
nuclear@3 60 // *** Constructor/destructor
nuclear@3 61 MutexImpl::MutexImpl(Mutex* pmutex, bool recursive)
nuclear@3 62 {
nuclear@3 63 Recursive = recursive;
nuclear@3 64 LockCount = 0;
nuclear@3 65
nuclear@3 66 if (Recursive)
nuclear@3 67 {
nuclear@3 68 if (!Lock::RecursiveAttrInit)
nuclear@3 69 {
nuclear@3 70 pthread_mutexattr_init(&Lock::RecursiveAttr);
nuclear@3 71 pthread_mutexattr_settype(&Lock::RecursiveAttr, PTHREAD_MUTEX_RECURSIVE);
nuclear@3 72 Lock::RecursiveAttrInit = 1;
nuclear@3 73 }
nuclear@3 74
nuclear@3 75 pthread_mutex_init(&SMutex, &Lock::RecursiveAttr);
nuclear@3 76 }
nuclear@3 77 else
nuclear@3 78 pthread_mutex_init(&SMutex, 0);
nuclear@3 79 }
nuclear@3 80
nuclear@3 81 MutexImpl::~MutexImpl()
nuclear@3 82 {
nuclear@3 83 pthread_mutex_destroy(&SMutex);
nuclear@3 84 }
nuclear@3 85
nuclear@3 86
nuclear@3 87 // Lock and try lock
nuclear@3 88 void MutexImpl::DoLock()
nuclear@3 89 {
nuclear@3 90 while (pthread_mutex_lock(&SMutex));
nuclear@3 91 LockCount++;
nuclear@3 92 LockedBy = pthread_self();
nuclear@3 93 }
nuclear@3 94
nuclear@3 95 bool MutexImpl::TryLock()
nuclear@3 96 {
nuclear@3 97 if (!pthread_mutex_trylock(&SMutex))
nuclear@3 98 {
nuclear@3 99 LockCount++;
nuclear@3 100 LockedBy = pthread_self();
nuclear@3 101 return 1;
nuclear@3 102 }
nuclear@3 103
nuclear@3 104 return 0;
nuclear@3 105 }
nuclear@3 106
nuclear@3 107 void MutexImpl::Unlock(Mutex* pmutex)
nuclear@3 108 {
nuclear@3 109 OVR_ASSERT(pthread_self() == LockedBy && LockCount > 0);
nuclear@3 110
nuclear@3 111 unsigned lockCount;
nuclear@3 112 LockCount--;
nuclear@3 113 lockCount = LockCount;
nuclear@3 114
nuclear@3 115 pthread_mutex_unlock(&SMutex);
nuclear@3 116 }
nuclear@3 117
nuclear@3 118 bool MutexImpl::IsLockedByAnotherThread(Mutex* pmutex)
nuclear@3 119 {
nuclear@3 120 // There could be multiple interpretations of IsLocked with respect to current thread
nuclear@3 121 if (LockCount == 0)
nuclear@3 122 return 0;
nuclear@3 123 if (pthread_self() != LockedBy)
nuclear@3 124 return 1;
nuclear@3 125 return 0;
nuclear@3 126 }
nuclear@3 127
nuclear@3 128 bool MutexImpl::IsSignaled() const
nuclear@3 129 {
nuclear@3 130 // An mutex is signaled if it is not locked ANYWHERE
nuclear@3 131 // Note that this is different from IsLockedByAnotherThread function,
nuclear@3 132 // that takes current thread into account
nuclear@3 133 return LockCount == 0;
nuclear@3 134 }
nuclear@3 135
nuclear@3 136
nuclear@3 137 // *** Actual Mutex class implementation
nuclear@3 138
nuclear@3 139 Mutex::Mutex(bool recursive)
nuclear@3 140 {
nuclear@3 141 // NOTE: RefCount mode already thread-safe for all waitables.
nuclear@3 142 pImpl = new MutexImpl(this, recursive);
nuclear@3 143 }
nuclear@3 144
nuclear@3 145 Mutex::~Mutex()
nuclear@3 146 {
nuclear@3 147 delete pImpl;
nuclear@3 148 }
nuclear@3 149
nuclear@3 150 // Lock and try lock
nuclear@3 151 void Mutex::DoLock()
nuclear@3 152 {
nuclear@3 153 pImpl->DoLock();
nuclear@3 154 }
nuclear@3 155 bool Mutex::TryLock()
nuclear@3 156 {
nuclear@3 157 return pImpl->TryLock();
nuclear@3 158 }
nuclear@3 159 void Mutex::Unlock()
nuclear@3 160 {
nuclear@3 161 pImpl->Unlock(this);
nuclear@3 162 }
nuclear@3 163 bool Mutex::IsLockedByAnotherThread()
nuclear@3 164 {
nuclear@3 165 return pImpl->IsLockedByAnotherThread(this);
nuclear@3 166 }
nuclear@3 167
nuclear@3 168
nuclear@3 169
nuclear@3 170 //-----------------------------------------------------------------------------------
nuclear@3 171 // ***** Event
nuclear@3 172
nuclear@3 173 bool Event::Wait(unsigned delay)
nuclear@3 174 {
nuclear@3 175 Mutex::Locker lock(&StateMutex);
nuclear@3 176
nuclear@3 177 // Do the correct amount of waiting
nuclear@3 178 if (delay == OVR_WAIT_INFINITE)
nuclear@3 179 {
nuclear@3 180 while(!State)
nuclear@3 181 StateWaitCondition.Wait(&StateMutex);
nuclear@3 182 }
nuclear@3 183 else if (delay)
nuclear@3 184 {
nuclear@3 185 if (!State)
nuclear@3 186 StateWaitCondition.Wait(&StateMutex, delay);
nuclear@3 187 }
nuclear@3 188
nuclear@3 189 bool state = State;
nuclear@3 190 // Take care of temporary 'pulsing' of a state
nuclear@3 191 if (Temporary)
nuclear@3 192 {
nuclear@3 193 Temporary = false;
nuclear@3 194 State = false;
nuclear@3 195 }
nuclear@3 196 return state;
nuclear@3 197 }
nuclear@3 198
nuclear@3 199 void Event::updateState(bool newState, bool newTemp, bool mustNotify)
nuclear@3 200 {
nuclear@3 201 Mutex::Locker lock(&StateMutex);
nuclear@3 202 State = newState;
nuclear@3 203 Temporary = newTemp;
nuclear@3 204 if (mustNotify)
nuclear@3 205 StateWaitCondition.NotifyAll();
nuclear@3 206 }
nuclear@3 207
nuclear@3 208
nuclear@3 209
nuclear@3 210 // ***** Wait Condition Implementation
nuclear@3 211
nuclear@3 212 // Internal implementation class
nuclear@3 213 class WaitConditionImpl : public NewOverrideBase
nuclear@3 214 {
nuclear@3 215 pthread_mutex_t SMutex;
nuclear@3 216 pthread_cond_t Condv;
nuclear@3 217
nuclear@3 218 public:
nuclear@3 219
nuclear@3 220 // Constructor/destructor
nuclear@3 221 WaitConditionImpl();
nuclear@3 222 ~WaitConditionImpl();
nuclear@3 223
nuclear@3 224 // Release mutex and wait for condition. The mutex is re-aqured after the wait.
nuclear@3 225 bool Wait(Mutex *pmutex, unsigned delay = OVR_WAIT_INFINITE);
nuclear@3 226
nuclear@3 227 // Notify a condition, releasing at one object waiting
nuclear@3 228 void Notify();
nuclear@3 229 // Notify a condition, releasing all objects waiting
nuclear@3 230 void NotifyAll();
nuclear@3 231 };
nuclear@3 232
nuclear@3 233
nuclear@3 234 WaitConditionImpl::WaitConditionImpl()
nuclear@3 235 {
nuclear@3 236 pthread_mutex_init(&SMutex, 0);
nuclear@3 237 pthread_cond_init(&Condv, 0);
nuclear@3 238 }
nuclear@3 239
nuclear@3 240 WaitConditionImpl::~WaitConditionImpl()
nuclear@3 241 {
nuclear@3 242 pthread_mutex_destroy(&SMutex);
nuclear@3 243 pthread_cond_destroy(&Condv);
nuclear@3 244 }
nuclear@3 245
nuclear@3 246 bool WaitConditionImpl::Wait(Mutex *pmutex, unsigned delay)
nuclear@3 247 {
nuclear@3 248 bool result = 1;
nuclear@3 249 unsigned lockCount = pmutex->pImpl->LockCount;
nuclear@3 250
nuclear@3 251 // Mutex must have been locked
nuclear@3 252 if (lockCount == 0)
nuclear@3 253 return 0;
nuclear@3 254
nuclear@3 255 pthread_mutex_lock(&SMutex);
nuclear@3 256
nuclear@3 257 // Finally, release a mutex or semaphore
nuclear@3 258 if (pmutex->pImpl->Recursive)
nuclear@3 259 {
nuclear@3 260 // Release the recursive mutex N times
nuclear@3 261 pmutex->pImpl->LockCount = 0;
nuclear@3 262 for(unsigned i=0; i<lockCount; i++)
nuclear@3 263 pthread_mutex_unlock(&pmutex->pImpl->SMutex);
nuclear@3 264 }
nuclear@3 265 else
nuclear@3 266 {
nuclear@3 267 pmutex->pImpl->LockCount = 0;
nuclear@3 268 pthread_mutex_unlock(&pmutex->pImpl->SMutex);
nuclear@3 269 }
nuclear@3 270
nuclear@3 271 // Note that there is a gap here between mutex.Unlock() and Wait().
nuclear@3 272 // The other mutex protects this gap.
nuclear@3 273
nuclear@3 274 if (delay == OVR_WAIT_INFINITE)
nuclear@3 275 pthread_cond_wait(&Condv,&SMutex);
nuclear@3 276 else
nuclear@3 277 {
nuclear@3 278 timespec ts;
nuclear@3 279 #ifdef OVR_OS_PS3
nuclear@3 280 sys_time_sec_t s;
nuclear@3 281 sys_time_nsec_t ns;
nuclear@3 282 sys_time_get_current_time(&s, &ns);
nuclear@3 283
nuclear@3 284 ts.tv_sec = s + (delay / 1000);
nuclear@3 285 ts.tv_nsec = ns + (delay % 1000) * 1000000;
nuclear@3 286
nuclear@3 287 #else
nuclear@3 288 struct timeval tv;
nuclear@3 289 gettimeofday(&tv, 0);
nuclear@3 290
nuclear@3 291 ts.tv_sec = tv.tv_sec + (delay / 1000);
nuclear@3 292 ts.tv_nsec = (tv.tv_usec + (delay % 1000) * 1000) * 1000;
nuclear@3 293 #endif
nuclear@3 294 if (ts.tv_nsec > 999999999)
nuclear@3 295 {
nuclear@3 296 ts.tv_sec++;
nuclear@3 297 ts.tv_nsec -= 1000000000;
nuclear@3 298 }
nuclear@3 299 int r = pthread_cond_timedwait(&Condv,&SMutex, &ts);
nuclear@3 300 OVR_ASSERT(r == 0 || r == ETIMEDOUT);
nuclear@3 301 if (r)
nuclear@3 302 result = 0;
nuclear@3 303 }
nuclear@3 304
nuclear@3 305 pthread_mutex_unlock(&SMutex);
nuclear@3 306
nuclear@3 307 // Re-aquire the mutex
nuclear@3 308 for(unsigned i=0; i<lockCount; i++)
nuclear@3 309 pmutex->DoLock();
nuclear@3 310
nuclear@3 311 // Return the result
nuclear@3 312 return result;
nuclear@3 313 }
nuclear@3 314
nuclear@3 315 // Notify a condition, releasing the least object in a queue
nuclear@3 316 void WaitConditionImpl::Notify()
nuclear@3 317 {
nuclear@3 318 pthread_mutex_lock(&SMutex);
nuclear@3 319 pthread_cond_signal(&Condv);
nuclear@3 320 pthread_mutex_unlock(&SMutex);
nuclear@3 321 }
nuclear@3 322
nuclear@3 323 // Notify a condition, releasing all objects waiting
nuclear@3 324 void WaitConditionImpl::NotifyAll()
nuclear@3 325 {
nuclear@3 326 pthread_mutex_lock(&SMutex);
nuclear@3 327 pthread_cond_broadcast(&Condv);
nuclear@3 328 pthread_mutex_unlock(&SMutex);
nuclear@3 329 }
nuclear@3 330
nuclear@3 331
nuclear@3 332
nuclear@3 333 // *** Actual implementation of WaitCondition
nuclear@3 334
nuclear@3 335 WaitCondition::WaitCondition()
nuclear@3 336 {
nuclear@3 337 pImpl = new WaitConditionImpl;
nuclear@3 338 }
nuclear@3 339 WaitCondition::~WaitCondition()
nuclear@3 340 {
nuclear@3 341 delete pImpl;
nuclear@3 342 }
nuclear@3 343
nuclear@3 344 bool WaitCondition::Wait(Mutex *pmutex, unsigned delay)
nuclear@3 345 {
nuclear@3 346 return pImpl->Wait(pmutex, delay);
nuclear@3 347 }
nuclear@3 348 // Notification
nuclear@3 349 void WaitCondition::Notify()
nuclear@3 350 {
nuclear@3 351 pImpl->Notify();
nuclear@3 352 }
nuclear@3 353 void WaitCondition::NotifyAll()
nuclear@3 354 {
nuclear@3 355 pImpl->NotifyAll();
nuclear@3 356 }
nuclear@3 357
nuclear@3 358
nuclear@3 359 // ***** Current thread
nuclear@3 360
nuclear@3 361 // Per-thread variable
nuclear@3 362 /*
nuclear@3 363 static __thread Thread* pCurrentThread = 0;
nuclear@3 364
nuclear@3 365 // Static function to return a pointer to the current thread
nuclear@3 366 void Thread::InitCurrentThread(Thread *pthread)
nuclear@3 367 {
nuclear@3 368 pCurrentThread = pthread;
nuclear@3 369 }
nuclear@3 370
nuclear@3 371 // Static function to return a pointer to the current thread
nuclear@3 372 Thread* Thread::GetThread()
nuclear@3 373 {
nuclear@3 374 return pCurrentThread;
nuclear@3 375 }
nuclear@3 376 */
nuclear@3 377
nuclear@3 378
nuclear@3 379 // *** Thread constructors.
nuclear@3 380
nuclear@3 381 Thread::Thread(UPInt stackSize, int processor)
nuclear@3 382 {
nuclear@3 383 // NOTE: RefCount mode already thread-safe for all Waitable objects.
nuclear@3 384 CreateParams params;
nuclear@3 385 params.stackSize = stackSize;
nuclear@3 386 params.processor = processor;
nuclear@3 387 Init(params);
nuclear@3 388 }
nuclear@3 389
nuclear@3 390 Thread::Thread(Thread::ThreadFn threadFunction, void* userHandle, UPInt stackSize,
nuclear@3 391 int processor, Thread::ThreadState initialState)
nuclear@3 392 {
nuclear@3 393 CreateParams params(threadFunction, userHandle, stackSize, processor, initialState);
nuclear@3 394 Init(params);
nuclear@3 395 }
nuclear@3 396
nuclear@3 397 Thread::Thread(const CreateParams& params)
nuclear@3 398 {
nuclear@3 399 Init(params);
nuclear@3 400 }
nuclear@3 401
nuclear@3 402 void Thread::Init(const CreateParams& params)
nuclear@3 403 {
nuclear@3 404 // Clear the variables
nuclear@3 405 ThreadFlags = 0;
nuclear@3 406 ThreadHandle = 0;
nuclear@3 407 ExitCode = 0;
nuclear@3 408 SuspendCount = 0;
nuclear@3 409 StackSize = params.stackSize;
nuclear@3 410 Processor = params.processor;
nuclear@3 411 Priority = params.priority;
nuclear@3 412
nuclear@3 413 // Clear Function pointers
nuclear@3 414 ThreadFunction = params.threadFunction;
nuclear@3 415 UserHandle = params.userHandle;
nuclear@3 416 if (params.initialState != NotRunning)
nuclear@3 417 Start(params.initialState);
nuclear@3 418 }
nuclear@3 419
nuclear@3 420 Thread::~Thread()
nuclear@3 421 {
nuclear@3 422 // Thread should not running while object is being destroyed,
nuclear@3 423 // this would indicate ref-counting issue.
nuclear@3 424 //OVR_ASSERT(IsRunning() == 0);
nuclear@3 425
nuclear@3 426 // Clean up thread.
nuclear@3 427 ThreadHandle = 0;
nuclear@3 428 }
nuclear@3 429
nuclear@3 430
nuclear@3 431
nuclear@3 432 // *** Overridable User functions.
nuclear@3 433
nuclear@3 434 // Default Run implementation
nuclear@3 435 int Thread::Run()
nuclear@3 436 {
nuclear@3 437 // Call pointer to function, if available.
nuclear@3 438 return (ThreadFunction) ? ThreadFunction(this, UserHandle) : 0;
nuclear@3 439 }
nuclear@3 440 void Thread::OnExit()
nuclear@3 441 {
nuclear@3 442 }
nuclear@3 443
nuclear@3 444
nuclear@3 445 // Finishes the thread and releases internal reference to it.
nuclear@3 446 void Thread::FinishAndRelease()
nuclear@3 447 {
nuclear@3 448 // Note: thread must be US.
nuclear@3 449 ThreadFlags &= (UInt32)~(OVR_THREAD_STARTED);
nuclear@3 450 ThreadFlags |= OVR_THREAD_FINISHED;
nuclear@3 451
nuclear@3 452 // Release our reference; this is equivalent to 'delete this'
nuclear@3 453 // from the point of view of our thread.
nuclear@3 454 Release();
nuclear@3 455 }
nuclear@3 456
nuclear@3 457
nuclear@3 458
nuclear@3 459 // *** ThreadList - used to track all created threads
nuclear@3 460
nuclear@3 461 class ThreadList : public NewOverrideBase
nuclear@3 462 {
nuclear@3 463 //------------------------------------------------------------------------
nuclear@3 464 struct ThreadHashOp
nuclear@3 465 {
nuclear@3 466 size_t operator()(const Thread* ptr)
nuclear@3 467 {
nuclear@3 468 return (((size_t)ptr) >> 6) ^ (size_t)ptr;
nuclear@3 469 }
nuclear@3 470 };
nuclear@3 471
nuclear@3 472 HashSet<Thread*, ThreadHashOp> ThreadSet;
nuclear@3 473 Mutex ThreadMutex;
nuclear@3 474 WaitCondition ThreadsEmpty;
nuclear@3 475 // Track the root thread that created us.
nuclear@3 476 pthread_t RootThreadId;
nuclear@3 477
nuclear@3 478 static ThreadList* volatile pRunningThreads;
nuclear@3 479
nuclear@3 480 void addThread(Thread *pthread)
nuclear@3 481 {
nuclear@3 482 Mutex::Locker lock(&ThreadMutex);
nuclear@3 483 ThreadSet.Add(pthread);
nuclear@3 484 }
nuclear@3 485
nuclear@3 486 void removeThread(Thread *pthread)
nuclear@3 487 {
nuclear@3 488 Mutex::Locker lock(&ThreadMutex);
nuclear@3 489 ThreadSet.Remove(pthread);
nuclear@3 490 if (ThreadSet.GetSize() == 0)
nuclear@3 491 ThreadsEmpty.Notify();
nuclear@3 492 }
nuclear@3 493
nuclear@3 494 void finishAllThreads()
nuclear@3 495 {
nuclear@3 496 // Only original root thread can call this.
nuclear@3 497 OVR_ASSERT(pthread_self() == RootThreadId);
nuclear@3 498
nuclear@3 499 Mutex::Locker lock(&ThreadMutex);
nuclear@3 500 while (ThreadSet.GetSize() != 0)
nuclear@3 501 ThreadsEmpty.Wait(&ThreadMutex);
nuclear@3 502 }
nuclear@3 503
nuclear@3 504 public:
nuclear@3 505
nuclear@3 506 ThreadList()
nuclear@3 507 {
nuclear@3 508 RootThreadId = pthread_self();
nuclear@3 509 }
nuclear@3 510 ~ThreadList() { }
nuclear@3 511
nuclear@3 512
nuclear@3 513 static void AddRunningThread(Thread *pthread)
nuclear@3 514 {
nuclear@3 515 // Non-atomic creation ok since only the root thread
nuclear@3 516 if (!pRunningThreads)
nuclear@3 517 {
nuclear@3 518 pRunningThreads = new ThreadList;
nuclear@3 519 OVR_ASSERT(pRunningThreads);
nuclear@3 520 }
nuclear@3 521 pRunningThreads->addThread(pthread);
nuclear@3 522 }
nuclear@3 523
nuclear@3 524 // NOTE: 'pthread' might be a dead pointer when this is
nuclear@3 525 // called so it should not be accessed; it is only used
nuclear@3 526 // for removal.
nuclear@3 527 static void RemoveRunningThread(Thread *pthread)
nuclear@3 528 {
nuclear@3 529 OVR_ASSERT(pRunningThreads);
nuclear@3 530 pRunningThreads->removeThread(pthread);
nuclear@3 531 }
nuclear@3 532
nuclear@3 533 static void FinishAllThreads()
nuclear@3 534 {
nuclear@3 535 // This is ok because only root thread can wait for other thread finish.
nuclear@3 536 if (pRunningThreads)
nuclear@3 537 {
nuclear@3 538 pRunningThreads->finishAllThreads();
nuclear@3 539 delete pRunningThreads;
nuclear@3 540 pRunningThreads = 0;
nuclear@3 541 }
nuclear@3 542 }
nuclear@3 543 };
nuclear@3 544
nuclear@3 545 // By default, we have no thread list.
nuclear@3 546 ThreadList* volatile ThreadList::pRunningThreads = 0;
nuclear@3 547
nuclear@3 548
nuclear@3 549 // FinishAllThreads - exposed publicly in Thread.
nuclear@3 550 void Thread::FinishAllThreads()
nuclear@3 551 {
nuclear@3 552 ThreadList::FinishAllThreads();
nuclear@3 553 }
nuclear@3 554
nuclear@3 555 // *** Run override
nuclear@3 556
nuclear@3 557 int Thread::PRun()
nuclear@3 558 {
nuclear@3 559 // Suspend us on start, if requested
nuclear@3 560 if (ThreadFlags & OVR_THREAD_START_SUSPENDED)
nuclear@3 561 {
nuclear@3 562 Suspend();
nuclear@3 563 ThreadFlags &= (UInt32)~OVR_THREAD_START_SUSPENDED;
nuclear@3 564 }
nuclear@3 565
nuclear@3 566 // Call the virtual run function
nuclear@3 567 ExitCode = Run();
nuclear@3 568 return ExitCode;
nuclear@3 569 }
nuclear@3 570
nuclear@3 571
nuclear@3 572
nuclear@3 573
nuclear@3 574 // *** User overridables
nuclear@3 575
nuclear@3 576 bool Thread::GetExitFlag() const
nuclear@3 577 {
nuclear@3 578 return (ThreadFlags & OVR_THREAD_EXIT) != 0;
nuclear@3 579 }
nuclear@3 580
nuclear@3 581 void Thread::SetExitFlag(bool exitFlag)
nuclear@3 582 {
nuclear@3 583 // The below is atomic since ThreadFlags is AtomicInt.
nuclear@3 584 if (exitFlag)
nuclear@3 585 ThreadFlags |= OVR_THREAD_EXIT;
nuclear@3 586 else
nuclear@3 587 ThreadFlags &= (UInt32) ~OVR_THREAD_EXIT;
nuclear@3 588 }
nuclear@3 589
nuclear@3 590
nuclear@3 591 // Determines whether the thread was running and is now finished
nuclear@3 592 bool Thread::IsFinished() const
nuclear@3 593 {
nuclear@3 594 return (ThreadFlags & OVR_THREAD_FINISHED) != 0;
nuclear@3 595 }
nuclear@3 596 // Determines whether the thread is suspended
nuclear@3 597 bool Thread::IsSuspended() const
nuclear@3 598 {
nuclear@3 599 return SuspendCount > 0;
nuclear@3 600 }
nuclear@3 601 // Returns current thread state
nuclear@3 602 Thread::ThreadState Thread::GetThreadState() const
nuclear@3 603 {
nuclear@3 604 if (IsSuspended())
nuclear@3 605 return Suspended;
nuclear@3 606 if (ThreadFlags & OVR_THREAD_STARTED)
nuclear@3 607 return Running;
nuclear@3 608 return NotRunning;
nuclear@3 609 }
nuclear@3 610 /*
nuclear@3 611 static const char* mapsched_policy(int policy)
nuclear@3 612 {
nuclear@3 613 switch(policy)
nuclear@3 614 {
nuclear@3 615 case SCHED_OTHER:
nuclear@3 616 return "SCHED_OTHER";
nuclear@3 617 case SCHED_RR:
nuclear@3 618 return "SCHED_RR";
nuclear@3 619 case SCHED_FIFO:
nuclear@3 620 return "SCHED_FIFO";
nuclear@3 621
nuclear@3 622 }
nuclear@3 623 return "UNKNOWN";
nuclear@3 624 }
nuclear@3 625 int policy;
nuclear@3 626 sched_param sparam;
nuclear@3 627 pthread_getschedparam(pthread_self(), &policy, &sparam);
nuclear@3 628 int max_prior = sched_get_priority_max(policy);
nuclear@3 629 int min_prior = sched_get_priority_min(policy);
nuclear@3 630 printf(" !!!! policy: %s, priority: %d, max priority: %d, min priority: %d\n", mapsched_policy(policy), sparam.sched_priority, max_prior, min_prior);
nuclear@3 631 #include <stdio.h>
nuclear@3 632 */
nuclear@3 633 // ***** Thread management
nuclear@3 634
nuclear@3 635 // The actual first function called on thread start
nuclear@3 636 void* Thread_PthreadStartFn(void* phandle)
nuclear@3 637 {
nuclear@3 638 Thread* pthread = (Thread*)phandle;
nuclear@3 639 int result = pthread->PRun();
nuclear@3 640 // Signal the thread as done and release it atomically.
nuclear@3 641 pthread->FinishAndRelease();
nuclear@3 642 // At this point Thread object might be dead; however we can still pass
nuclear@3 643 // it to RemoveRunningThread since it is only used as a key there.
nuclear@3 644 ThreadList::RemoveRunningThread(pthread);
nuclear@3 645 return (void*) result;
nuclear@3 646 }
nuclear@3 647
nuclear@3 648 int Thread::InitAttr = 0;
nuclear@3 649 pthread_attr_t Thread::Attr;
nuclear@3 650
nuclear@3 651 /* static */
nuclear@3 652 int Thread::GetOSPriority(ThreadPriority p)
nuclear@3 653 //static inline int MapToSystemPrority(Thread::ThreadPriority p)
nuclear@3 654 {
nuclear@3 655 #ifdef OVR_OS_PS3
nuclear@3 656 switch(p)
nuclear@3 657 {
nuclear@3 658 case Thread::CriticalPriority: return 0;
nuclear@3 659 case Thread::HighestPriority: return 300;
nuclear@3 660 case Thread::AboveNormalPriority: return 600;
nuclear@3 661 case Thread::NormalPriority: return 1000;
nuclear@3 662 case Thread::BelowNormalPriority: return 1500;
nuclear@3 663 case Thread::LowestPriority: return 2500;
nuclear@3 664 case Thread::IdlePriority: return 3071;
nuclear@3 665 } return 1000;
nuclear@3 666 #else
nuclear@3 667 OVR_UNUSED(p);
nuclear@3 668 return -1;
nuclear@3 669 #endif
nuclear@3 670 }
nuclear@3 671
nuclear@3 672 bool Thread::Start(ThreadState initialState)
nuclear@3 673 {
nuclear@3 674 if (initialState == NotRunning)
nuclear@3 675 return 0;
nuclear@3 676 if (GetThreadState() != NotRunning)
nuclear@3 677 {
nuclear@3 678 OVR_DEBUG_LOG(("Thread::Start failed - thread %p already running", this));
nuclear@3 679 return 0;
nuclear@3 680 }
nuclear@3 681
nuclear@3 682 if (!InitAttr)
nuclear@3 683 {
nuclear@3 684 pthread_attr_init(&Attr);
nuclear@3 685 pthread_attr_setdetachstate(&Attr, PTHREAD_CREATE_DETACHED);
nuclear@3 686 pthread_attr_setstacksize(&Attr, 128 * 1024);
nuclear@3 687 sched_param sparam;
nuclear@3 688 sparam.sched_priority = Thread::GetOSPriority(NormalPriority);
nuclear@3 689 pthread_attr_setschedparam(&Attr, &sparam);
nuclear@3 690 InitAttr = 1;
nuclear@3 691 }
nuclear@3 692
nuclear@3 693 ExitCode = 0;
nuclear@3 694 SuspendCount = 0;
nuclear@3 695 ThreadFlags = (initialState == Running) ? 0 : OVR_THREAD_START_SUSPENDED;
nuclear@3 696
nuclear@3 697 // AddRef to us until the thread is finished
nuclear@3 698 AddRef();
nuclear@3 699 ThreadList::AddRunningThread(this);
nuclear@3 700
nuclear@3 701 int result;
nuclear@3 702 if (StackSize != 128 * 1024 || Priority != NormalPriority)
nuclear@3 703 {
nuclear@3 704 pthread_attr_t attr;
nuclear@3 705
nuclear@3 706 pthread_attr_init(&attr);
nuclear@3 707 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
nuclear@3 708 pthread_attr_setstacksize(&attr, StackSize);
nuclear@3 709 sched_param sparam;
nuclear@3 710 sparam.sched_priority = Thread::GetOSPriority(Priority);
nuclear@3 711 pthread_attr_setschedparam(&attr, &sparam);
nuclear@3 712 result = pthread_create(&ThreadHandle, &attr, Thread_PthreadStartFn, this);
nuclear@3 713 pthread_attr_destroy(&attr);
nuclear@3 714 }
nuclear@3 715 else
nuclear@3 716 result = pthread_create(&ThreadHandle, &Attr, Thread_PthreadStartFn, this);
nuclear@3 717
nuclear@3 718 if (result)
nuclear@3 719 {
nuclear@3 720 ThreadFlags = 0;
nuclear@3 721 Release();
nuclear@3 722 ThreadList::RemoveRunningThread(this);
nuclear@3 723 return 0;
nuclear@3 724 }
nuclear@3 725 return 1;
nuclear@3 726 }
nuclear@3 727
nuclear@3 728
nuclear@3 729 // Suspend the thread until resumed
nuclear@3 730 bool Thread::Suspend()
nuclear@3 731 {
nuclear@3 732 OVR_DEBUG_LOG(("Thread::Suspend - cannot suspend threads on this system"));
nuclear@3 733 return 0;
nuclear@3 734 }
nuclear@3 735
nuclear@3 736 // Resumes currently suspended thread
nuclear@3 737 bool Thread::Resume()
nuclear@3 738 {
nuclear@3 739 return 0;
nuclear@3 740 }
nuclear@3 741
nuclear@3 742
nuclear@3 743 // Quits with an exit code
nuclear@3 744 void Thread::Exit(int exitCode)
nuclear@3 745 {
nuclear@3 746 // Can only exist the current thread
nuclear@3 747 // if (GetThread() != this)
nuclear@3 748 // return;
nuclear@3 749
nuclear@3 750 // Call the virtual OnExit function
nuclear@3 751 OnExit();
nuclear@3 752
nuclear@3 753 // Signal this thread object as done and release it's references.
nuclear@3 754 FinishAndRelease();
nuclear@3 755 ThreadList::RemoveRunningThread(this);
nuclear@3 756
nuclear@3 757 pthread_exit((void *) exitCode);
nuclear@3 758 }
nuclear@3 759
nuclear@3 760 ThreadId GetCurrentThreadId()
nuclear@3 761 {
nuclear@3 762 return (void*)pthread_self();
nuclear@3 763 }
nuclear@3 764
nuclear@3 765 // *** Sleep functions
nuclear@3 766
nuclear@3 767 /* static */
nuclear@3 768 bool Thread::Sleep(unsigned secs)
nuclear@3 769 {
nuclear@3 770 sleep(secs);
nuclear@3 771 return 1;
nuclear@3 772 }
nuclear@3 773 /* static */
nuclear@3 774 bool Thread::MSleep(unsigned msecs)
nuclear@3 775 {
nuclear@3 776 usleep(msecs*1000);
nuclear@3 777 return 1;
nuclear@3 778 }
nuclear@3 779
nuclear@3 780 /* static */
nuclear@3 781 int Thread::GetCPUCount()
nuclear@3 782 {
nuclear@3 783 return 1;
nuclear@3 784 }
nuclear@3 785
nuclear@3 786
nuclear@3 787 #ifdef OVR_OS_PS3
nuclear@3 788
nuclear@3 789 sys_lwmutex_attribute_t Lock::LockAttr = { SYS_SYNC_PRIORITY, SYS_SYNC_RECURSIVE };
nuclear@3 790
nuclear@3 791 #endif
nuclear@3 792
nuclear@3 793 }
nuclear@3 794
nuclear@3 795 #endif // OVR_ENABLE_THREADS