oculus1

annotate libovr/Src/linux/OVR_ThreadsPthread.cpp @ 1:e2f9e4603129

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