ovr_sdk

annotate LibOVR/Src/Kernel/OVR_ThreadsPthread.cpp @ 0:1b39a1b46319

initial 0.4.4
author John Tsiombikas <nuclear@member.fsf.org>
date Wed, 14 Jan 2015 06:51:16 +0200
parents
children
rev   line source
nuclear@0 1 /************************************************************************************
nuclear@0 2
nuclear@0 3 Filename : OVR_ThreadsPthread.cpp
nuclear@0 4 Content :
nuclear@0 5 Created :
nuclear@0 6 Notes :
nuclear@0 7
nuclear@0 8 Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved.
nuclear@0 9
nuclear@0 10 Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License");
nuclear@0 11 you may not use the Oculus VR Rift SDK except in compliance with the License,
nuclear@0 12 which is provided at the time of installation or download, or which
nuclear@0 13 otherwise accompanies this software in either electronic or hard copy form.
nuclear@0 14
nuclear@0 15 You may obtain a copy of the License at
nuclear@0 16
nuclear@0 17 http://www.oculusvr.com/licenses/LICENSE-3.2
nuclear@0 18
nuclear@0 19 Unless required by applicable law or agreed to in writing, the Oculus VR SDK
nuclear@0 20 distributed under the License is distributed on an "AS IS" BASIS,
nuclear@0 21 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
nuclear@0 22 See the License for the specific language governing permissions and
nuclear@0 23 limitations under the License.
nuclear@0 24
nuclear@0 25 ************************************************************************************/
nuclear@0 26
nuclear@0 27 #include "OVR_Threads.h"
nuclear@0 28 #include "OVR_Hash.h"
nuclear@0 29
nuclear@0 30 #ifdef OVR_ENABLE_THREADS
nuclear@0 31
nuclear@0 32 #include "OVR_Timer.h"
nuclear@0 33 #include "OVR_Log.h"
nuclear@0 34
nuclear@0 35 #include <pthread.h>
nuclear@0 36 #include <sched.h>
nuclear@0 37 #include <time.h>
nuclear@0 38 #include <unistd.h>
nuclear@0 39 #include <sys/time.h>
nuclear@0 40 #include <errno.h>
nuclear@0 41
nuclear@0 42 #if defined(OVR_OS_MAC) || defined(OVR_OS_BSD)
nuclear@0 43 #include <sys/sysctl.h>
nuclear@0 44 #include <sys/param.h>
nuclear@0 45 #if !defined(OVR_OS_MAC)
nuclear@0 46 #include <pthread_np.h>
nuclear@0 47 #endif
nuclear@0 48 #endif
nuclear@0 49
nuclear@0 50
nuclear@0 51
nuclear@0 52 namespace OVR {
nuclear@0 53
nuclear@0 54 // ***** Mutex implementation
nuclear@0 55
nuclear@0 56
nuclear@0 57 // *** Internal Mutex implementation structure
nuclear@0 58
nuclear@0 59 class MutexImpl : public NewOverrideBase
nuclear@0 60 {
nuclear@0 61 // System mutex or semaphore
nuclear@0 62 pthread_mutex_t SMutex;
nuclear@0 63 bool Recursive;
nuclear@0 64 unsigned LockCount;
nuclear@0 65 pthread_t LockedBy;
nuclear@0 66
nuclear@0 67 friend class WaitConditionImpl;
nuclear@0 68
nuclear@0 69 public:
nuclear@0 70 // Constructor/destructor
nuclear@0 71 MutexImpl(Mutex* pmutex, bool recursive = 1);
nuclear@0 72 ~MutexImpl();
nuclear@0 73
nuclear@0 74 // Locking functions
nuclear@0 75 void DoLock();
nuclear@0 76 bool TryLock();
nuclear@0 77 void Unlock(Mutex* pmutex);
nuclear@0 78 // Returns 1 if the mutes is currently locked
nuclear@0 79 bool IsLockedByAnotherThread(Mutex* pmutex);
nuclear@0 80 bool IsSignaled() const;
nuclear@0 81 };
nuclear@0 82
nuclear@0 83 pthread_mutexattr_t Lock::RecursiveAttr;
nuclear@0 84 bool Lock::RecursiveAttrInit = 0;
nuclear@0 85
nuclear@0 86 // *** Constructor/destructor
nuclear@0 87 MutexImpl::MutexImpl(Mutex* pmutex, bool recursive)
nuclear@0 88 {
nuclear@0 89 OVR_UNUSED(pmutex);
nuclear@0 90 Recursive = recursive;
nuclear@0 91 LockCount = 0;
nuclear@0 92
nuclear@0 93 if (Recursive)
nuclear@0 94 {
nuclear@0 95 if (!Lock::RecursiveAttrInit)
nuclear@0 96 {
nuclear@0 97 pthread_mutexattr_init(&Lock::RecursiveAttr);
nuclear@0 98 pthread_mutexattr_settype(&Lock::RecursiveAttr, PTHREAD_MUTEX_RECURSIVE);
nuclear@0 99 Lock::RecursiveAttrInit = 1;
nuclear@0 100 }
nuclear@0 101
nuclear@0 102 pthread_mutex_init(&SMutex, &Lock::RecursiveAttr);
nuclear@0 103 }
nuclear@0 104 else
nuclear@0 105 pthread_mutex_init(&SMutex, 0);
nuclear@0 106 }
nuclear@0 107
nuclear@0 108 MutexImpl::~MutexImpl()
nuclear@0 109 {
nuclear@0 110 pthread_mutex_destroy(&SMutex);
nuclear@0 111 }
nuclear@0 112
nuclear@0 113
nuclear@0 114 // Lock and try lock
nuclear@0 115 void MutexImpl::DoLock()
nuclear@0 116 {
nuclear@0 117 while (pthread_mutex_lock(&SMutex))
nuclear@0 118 ;
nuclear@0 119 LockCount++;
nuclear@0 120 LockedBy = pthread_self();
nuclear@0 121 }
nuclear@0 122
nuclear@0 123 bool MutexImpl::TryLock()
nuclear@0 124 {
nuclear@0 125 if (!pthread_mutex_trylock(&SMutex))
nuclear@0 126 {
nuclear@0 127 LockCount++;
nuclear@0 128 LockedBy = pthread_self();
nuclear@0 129 return 1;
nuclear@0 130 }
nuclear@0 131
nuclear@0 132 return 0;
nuclear@0 133 }
nuclear@0 134
nuclear@0 135 void MutexImpl::Unlock(Mutex* pmutex)
nuclear@0 136 {
nuclear@0 137 OVR_UNUSED(pmutex);
nuclear@0 138 OVR_ASSERT(pthread_self() == LockedBy && LockCount > 0);
nuclear@0 139
nuclear@0 140 //unsigned lockCount;
nuclear@0 141 LockCount--;
nuclear@0 142 //lockCount = LockCount;
nuclear@0 143
nuclear@0 144 pthread_mutex_unlock(&SMutex);
nuclear@0 145 }
nuclear@0 146
nuclear@0 147 bool MutexImpl::IsLockedByAnotherThread(Mutex* pmutex)
nuclear@0 148 {
nuclear@0 149 OVR_UNUSED(pmutex);
nuclear@0 150 // There could be multiple interpretations of IsLocked with respect to current thread
nuclear@0 151 if (LockCount == 0)
nuclear@0 152 return 0;
nuclear@0 153 if (pthread_self() != LockedBy)
nuclear@0 154 return 1;
nuclear@0 155 return 0;
nuclear@0 156 }
nuclear@0 157
nuclear@0 158 bool MutexImpl::IsSignaled() const
nuclear@0 159 {
nuclear@0 160 // An mutex is signaled if it is not locked ANYWHERE
nuclear@0 161 // Note that this is different from IsLockedByAnotherThread function,
nuclear@0 162 // that takes current thread into account
nuclear@0 163 return LockCount == 0;
nuclear@0 164 }
nuclear@0 165
nuclear@0 166
nuclear@0 167 // *** Actual Mutex class implementation
nuclear@0 168
nuclear@0 169 Mutex::Mutex(bool recursive)
nuclear@0 170 {
nuclear@0 171 // NOTE: RefCount mode already thread-safe for all waitables.
nuclear@0 172 pImpl = new MutexImpl(this, recursive);
nuclear@0 173 }
nuclear@0 174
nuclear@0 175 Mutex::~Mutex()
nuclear@0 176 {
nuclear@0 177 delete pImpl;
nuclear@0 178 }
nuclear@0 179
nuclear@0 180 // Lock and try lock
nuclear@0 181 void Mutex::DoLock()
nuclear@0 182 {
nuclear@0 183 pImpl->DoLock();
nuclear@0 184 }
nuclear@0 185 bool Mutex::TryLock()
nuclear@0 186 {
nuclear@0 187 return pImpl->TryLock();
nuclear@0 188 }
nuclear@0 189 void Mutex::Unlock()
nuclear@0 190 {
nuclear@0 191 pImpl->Unlock(this);
nuclear@0 192 }
nuclear@0 193 bool Mutex::IsLockedByAnotherThread()
nuclear@0 194 {
nuclear@0 195 return pImpl->IsLockedByAnotherThread(this);
nuclear@0 196 }
nuclear@0 197
nuclear@0 198
nuclear@0 199
nuclear@0 200 //-----------------------------------------------------------------------------------
nuclear@0 201 // ***** Event
nuclear@0 202
nuclear@0 203 bool Event::Wait(unsigned delay)
nuclear@0 204 {
nuclear@0 205 Mutex::Locker lock(&StateMutex);
nuclear@0 206
nuclear@0 207 // Do the correct amount of waiting
nuclear@0 208 if (delay == OVR_WAIT_INFINITE)
nuclear@0 209 {
nuclear@0 210 while(!State)
nuclear@0 211 StateWaitCondition.Wait(&StateMutex);
nuclear@0 212 }
nuclear@0 213 else if (delay)
nuclear@0 214 {
nuclear@0 215 if (!State)
nuclear@0 216 StateWaitCondition.Wait(&StateMutex, delay);
nuclear@0 217 }
nuclear@0 218
nuclear@0 219 bool state = State;
nuclear@0 220 // Take care of temporary 'pulsing' of a state
nuclear@0 221 if (Temporary)
nuclear@0 222 {
nuclear@0 223 Temporary = false;
nuclear@0 224 State = false;
nuclear@0 225 }
nuclear@0 226 return state;
nuclear@0 227 }
nuclear@0 228
nuclear@0 229 void Event::updateState(bool newState, bool newTemp, bool mustNotify)
nuclear@0 230 {
nuclear@0 231 Mutex::Locker lock(&StateMutex);
nuclear@0 232 State = newState;
nuclear@0 233 Temporary = newTemp;
nuclear@0 234 if (mustNotify)
nuclear@0 235 StateWaitCondition.NotifyAll();
nuclear@0 236 }
nuclear@0 237
nuclear@0 238
nuclear@0 239
nuclear@0 240 // ***** Wait Condition Implementation
nuclear@0 241
nuclear@0 242 // Internal implementation class
nuclear@0 243 class WaitConditionImpl : public NewOverrideBase
nuclear@0 244 {
nuclear@0 245 pthread_mutex_t SMutex;
nuclear@0 246 pthread_cond_t Condv;
nuclear@0 247
nuclear@0 248 public:
nuclear@0 249
nuclear@0 250 // Constructor/destructor
nuclear@0 251 WaitConditionImpl();
nuclear@0 252 ~WaitConditionImpl();
nuclear@0 253
nuclear@0 254 // Release mutex and wait for condition. The mutex is re-aqured after the wait.
nuclear@0 255 bool Wait(Mutex *pmutex, unsigned delay = OVR_WAIT_INFINITE);
nuclear@0 256
nuclear@0 257 // Notify a condition, releasing at one object waiting
nuclear@0 258 void Notify();
nuclear@0 259 // Notify a condition, releasing all objects waiting
nuclear@0 260 void NotifyAll();
nuclear@0 261 };
nuclear@0 262
nuclear@0 263
nuclear@0 264 WaitConditionImpl::WaitConditionImpl()
nuclear@0 265 {
nuclear@0 266 pthread_mutex_init(&SMutex, 0);
nuclear@0 267 pthread_cond_init(&Condv, 0);
nuclear@0 268 }
nuclear@0 269
nuclear@0 270 WaitConditionImpl::~WaitConditionImpl()
nuclear@0 271 {
nuclear@0 272 pthread_mutex_destroy(&SMutex);
nuclear@0 273 pthread_cond_destroy(&Condv);
nuclear@0 274 }
nuclear@0 275
nuclear@0 276 bool WaitConditionImpl::Wait(Mutex *pmutex, unsigned delay)
nuclear@0 277 {
nuclear@0 278 bool result = 1;
nuclear@0 279 unsigned lockCount = pmutex->pImpl->LockCount;
nuclear@0 280
nuclear@0 281 // Mutex must have been locked
nuclear@0 282 if (lockCount == 0)
nuclear@0 283 return 0;
nuclear@0 284
nuclear@0 285 pthread_mutex_lock(&SMutex);
nuclear@0 286
nuclear@0 287 // Finally, release a mutex or semaphore
nuclear@0 288 if (pmutex->pImpl->Recursive)
nuclear@0 289 {
nuclear@0 290 // Release the recursive mutex N times
nuclear@0 291 pmutex->pImpl->LockCount = 0;
nuclear@0 292 for(unsigned i=0; i<lockCount; i++)
nuclear@0 293 pthread_mutex_unlock(&pmutex->pImpl->SMutex);
nuclear@0 294 }
nuclear@0 295 else
nuclear@0 296 {
nuclear@0 297 pmutex->pImpl->LockCount = 0;
nuclear@0 298 pthread_mutex_unlock(&pmutex->pImpl->SMutex);
nuclear@0 299 }
nuclear@0 300
nuclear@0 301 // Note that there is a gap here between mutex.Unlock() and Wait().
nuclear@0 302 // The other mutex protects this gap.
nuclear@0 303
nuclear@0 304 if (delay == OVR_WAIT_INFINITE)
nuclear@0 305 pthread_cond_wait(&Condv,&SMutex);
nuclear@0 306 else
nuclear@0 307 {
nuclear@0 308 timespec ts;
nuclear@0 309
nuclear@0 310 struct timeval tv;
nuclear@0 311 gettimeofday(&tv, 0);
nuclear@0 312
nuclear@0 313 ts.tv_sec = tv.tv_sec + (delay / 1000);
nuclear@0 314 ts.tv_nsec = (tv.tv_usec + (delay % 1000) * 1000) * 1000;
nuclear@0 315
nuclear@0 316 if (ts.tv_nsec > 999999999)
nuclear@0 317 {
nuclear@0 318 ts.tv_sec++;
nuclear@0 319 ts.tv_nsec -= 1000000000;
nuclear@0 320 }
nuclear@0 321 int r = pthread_cond_timedwait(&Condv,&SMutex, &ts);
nuclear@0 322 OVR_ASSERT(r == 0 || r == ETIMEDOUT);
nuclear@0 323 if (r)
nuclear@0 324 result = 0;
nuclear@0 325 }
nuclear@0 326
nuclear@0 327 pthread_mutex_unlock(&SMutex);
nuclear@0 328
nuclear@0 329 // Re-aquire the mutex
nuclear@0 330 for(unsigned i=0; i<lockCount; i++)
nuclear@0 331 pmutex->DoLock();
nuclear@0 332
nuclear@0 333 // Return the result
nuclear@0 334 return result;
nuclear@0 335 }
nuclear@0 336
nuclear@0 337 // Notify a condition, releasing the least object in a queue
nuclear@0 338 void WaitConditionImpl::Notify()
nuclear@0 339 {
nuclear@0 340 pthread_mutex_lock(&SMutex);
nuclear@0 341 pthread_cond_signal(&Condv);
nuclear@0 342 pthread_mutex_unlock(&SMutex);
nuclear@0 343 }
nuclear@0 344
nuclear@0 345 // Notify a condition, releasing all objects waiting
nuclear@0 346 void WaitConditionImpl::NotifyAll()
nuclear@0 347 {
nuclear@0 348 pthread_mutex_lock(&SMutex);
nuclear@0 349 pthread_cond_broadcast(&Condv);
nuclear@0 350 pthread_mutex_unlock(&SMutex);
nuclear@0 351 }
nuclear@0 352
nuclear@0 353
nuclear@0 354
nuclear@0 355 // *** Actual implementation of WaitCondition
nuclear@0 356
nuclear@0 357 WaitCondition::WaitCondition()
nuclear@0 358 {
nuclear@0 359 pImpl = new WaitConditionImpl;
nuclear@0 360 }
nuclear@0 361 WaitCondition::~WaitCondition()
nuclear@0 362 {
nuclear@0 363 delete pImpl;
nuclear@0 364 }
nuclear@0 365
nuclear@0 366 bool WaitCondition::Wait(Mutex *pmutex, unsigned delay)
nuclear@0 367 {
nuclear@0 368 return pImpl->Wait(pmutex, delay);
nuclear@0 369 }
nuclear@0 370 // Notification
nuclear@0 371 void WaitCondition::Notify()
nuclear@0 372 {
nuclear@0 373 pImpl->Notify();
nuclear@0 374 }
nuclear@0 375 void WaitCondition::NotifyAll()
nuclear@0 376 {
nuclear@0 377 pImpl->NotifyAll();
nuclear@0 378 }
nuclear@0 379
nuclear@0 380
nuclear@0 381 // ***** Current thread
nuclear@0 382
nuclear@0 383 // Per-thread variable
nuclear@0 384 /*
nuclear@0 385 static __thread Thread* pCurrentThread = 0;
nuclear@0 386
nuclear@0 387 // Static function to return a pointer to the current thread
nuclear@0 388 void Thread::InitCurrentThread(Thread *pthread)
nuclear@0 389 {
nuclear@0 390 pCurrentThread = pthread;
nuclear@0 391 }
nuclear@0 392
nuclear@0 393 // Static function to return a pointer to the current thread
nuclear@0 394 Thread* Thread::GetThread()
nuclear@0 395 {
nuclear@0 396 return pCurrentThread;
nuclear@0 397 }
nuclear@0 398 */
nuclear@0 399
nuclear@0 400
nuclear@0 401 // *** Thread constructors.
nuclear@0 402
nuclear@0 403 Thread::Thread(UPInt stackSize, int processor)
nuclear@0 404 {
nuclear@0 405 // NOTE: RefCount mode already thread-safe for all Waitable objects.
nuclear@0 406 CreateParams params;
nuclear@0 407 params.stackSize = stackSize;
nuclear@0 408 params.processor = processor;
nuclear@0 409 Init(params);
nuclear@0 410 }
nuclear@0 411
nuclear@0 412 Thread::Thread(Thread::ThreadFn threadFunction, void* userHandle, UPInt stackSize,
nuclear@0 413 int processor, Thread::ThreadState initialState)
nuclear@0 414 {
nuclear@0 415 CreateParams params(threadFunction, userHandle, stackSize, processor, initialState);
nuclear@0 416 Init(params);
nuclear@0 417 }
nuclear@0 418
nuclear@0 419 Thread::Thread(const CreateParams& params)
nuclear@0 420 {
nuclear@0 421 Init(params);
nuclear@0 422 }
nuclear@0 423
nuclear@0 424 void Thread::Init(const CreateParams& params)
nuclear@0 425 {
nuclear@0 426 // Clear the variables
nuclear@0 427 ThreadFlags = 0;
nuclear@0 428 ThreadHandle = 0;
nuclear@0 429 ExitCode = 0;
nuclear@0 430 SuspendCount = 0;
nuclear@0 431 StackSize = params.stackSize;
nuclear@0 432 Processor = params.processor;
nuclear@0 433 Priority = params.priority;
nuclear@0 434
nuclear@0 435 // Clear Function pointers
nuclear@0 436 ThreadFunction = params.threadFunction;
nuclear@0 437 UserHandle = params.userHandle;
nuclear@0 438 if (params.initialState != NotRunning)
nuclear@0 439 Start(params.initialState);
nuclear@0 440 }
nuclear@0 441
nuclear@0 442 Thread::~Thread()
nuclear@0 443 {
nuclear@0 444 // Thread should not running while object is being destroyed,
nuclear@0 445 // this would indicate ref-counting issue.
nuclear@0 446 //OVR_ASSERT(IsRunning() == 0);
nuclear@0 447
nuclear@0 448 // Clean up thread.
nuclear@0 449 ThreadHandle = 0;
nuclear@0 450 }
nuclear@0 451
nuclear@0 452
nuclear@0 453
nuclear@0 454 // *** Overridable User functions.
nuclear@0 455
nuclear@0 456 // Default Run implementation
nuclear@0 457 int Thread::Run()
nuclear@0 458 {
nuclear@0 459 // Call pointer to function, if available.
nuclear@0 460 return (ThreadFunction) ? ThreadFunction(this, UserHandle) : 0;
nuclear@0 461 }
nuclear@0 462 void Thread::OnExit()
nuclear@0 463 {
nuclear@0 464 }
nuclear@0 465
nuclear@0 466
nuclear@0 467 // Finishes the thread and releases internal reference to it.
nuclear@0 468 void Thread::FinishAndRelease()
nuclear@0 469 {
nuclear@0 470 // Note: thread must be US.
nuclear@0 471 ThreadFlags &= (UInt32)~(OVR_THREAD_STARTED);
nuclear@0 472 ThreadFlags |= OVR_THREAD_FINISHED;
nuclear@0 473
nuclear@0 474 // Release our reference; this is equivalent to 'delete this'
nuclear@0 475 // from the point of view of our thread.
nuclear@0 476 Release();
nuclear@0 477 }
nuclear@0 478
nuclear@0 479
nuclear@0 480
nuclear@0 481 // *** ThreadList - used to track all created threads
nuclear@0 482
nuclear@0 483 class ThreadList : public NewOverrideBase
nuclear@0 484 {
nuclear@0 485 //------------------------------------------------------------------------
nuclear@0 486 struct ThreadHashOp
nuclear@0 487 {
nuclear@0 488 size_t operator()(const Thread* ptr)
nuclear@0 489 {
nuclear@0 490 return (((size_t)ptr) >> 6) ^ (size_t)ptr;
nuclear@0 491 }
nuclear@0 492 };
nuclear@0 493
nuclear@0 494 HashSet<Thread*, ThreadHashOp> ThreadSet;
nuclear@0 495 Mutex ThreadMutex;
nuclear@0 496 WaitCondition ThreadsEmpty;
nuclear@0 497 // Track the root thread that created us.
nuclear@0 498 pthread_t RootThreadId;
nuclear@0 499
nuclear@0 500 static ThreadList* volatile pRunningThreads;
nuclear@0 501
nuclear@0 502 void addThread(Thread *pthread)
nuclear@0 503 {
nuclear@0 504 Mutex::Locker lock(&ThreadMutex);
nuclear@0 505 ThreadSet.Add(pthread);
nuclear@0 506 }
nuclear@0 507
nuclear@0 508 void removeThread(Thread *pthread)
nuclear@0 509 {
nuclear@0 510 Mutex::Locker lock(&ThreadMutex);
nuclear@0 511 ThreadSet.Remove(pthread);
nuclear@0 512 if (ThreadSet.GetSize() == 0)
nuclear@0 513 ThreadsEmpty.Notify();
nuclear@0 514 }
nuclear@0 515
nuclear@0 516 void finishAllThreads()
nuclear@0 517 {
nuclear@0 518 // Only original root thread can call this.
nuclear@0 519 OVR_ASSERT(pthread_self() == RootThreadId);
nuclear@0 520
nuclear@0 521 Mutex::Locker lock(&ThreadMutex);
nuclear@0 522 while (ThreadSet.GetSize() != 0)
nuclear@0 523 ThreadsEmpty.Wait(&ThreadMutex);
nuclear@0 524 }
nuclear@0 525
nuclear@0 526 public:
nuclear@0 527
nuclear@0 528 ThreadList()
nuclear@0 529 {
nuclear@0 530 RootThreadId = pthread_self();
nuclear@0 531 }
nuclear@0 532 ~ThreadList() { }
nuclear@0 533
nuclear@0 534
nuclear@0 535 static void AddRunningThread(Thread *pthread)
nuclear@0 536 {
nuclear@0 537 // Non-atomic creation ok since only the root thread
nuclear@0 538 if (!pRunningThreads)
nuclear@0 539 {
nuclear@0 540 pRunningThreads = new ThreadList;
nuclear@0 541 OVR_ASSERT(pRunningThreads);
nuclear@0 542 }
nuclear@0 543 pRunningThreads->addThread(pthread);
nuclear@0 544 }
nuclear@0 545
nuclear@0 546 // NOTE: 'pthread' might be a dead pointer when this is
nuclear@0 547 // called so it should not be accessed; it is only used
nuclear@0 548 // for removal.
nuclear@0 549 static void RemoveRunningThread(Thread *pthread)
nuclear@0 550 {
nuclear@0 551 OVR_ASSERT(pRunningThreads);
nuclear@0 552 pRunningThreads->removeThread(pthread);
nuclear@0 553 }
nuclear@0 554
nuclear@0 555 static void FinishAllThreads()
nuclear@0 556 {
nuclear@0 557 // This is ok because only root thread can wait for other thread finish.
nuclear@0 558 if (pRunningThreads)
nuclear@0 559 {
nuclear@0 560 pRunningThreads->finishAllThreads();
nuclear@0 561 delete pRunningThreads;
nuclear@0 562 pRunningThreads = 0;
nuclear@0 563 }
nuclear@0 564 }
nuclear@0 565 };
nuclear@0 566
nuclear@0 567 // By default, we have no thread list.
nuclear@0 568 ThreadList* volatile ThreadList::pRunningThreads = 0;
nuclear@0 569
nuclear@0 570
nuclear@0 571 // FinishAllThreads - exposed publicly in Thread.
nuclear@0 572 void Thread::FinishAllThreads()
nuclear@0 573 {
nuclear@0 574 ThreadList::FinishAllThreads();
nuclear@0 575 }
nuclear@0 576
nuclear@0 577 // *** Run override
nuclear@0 578
nuclear@0 579 int Thread::PRun()
nuclear@0 580 {
nuclear@0 581 // Suspend us on start, if requested
nuclear@0 582 if (ThreadFlags & OVR_THREAD_START_SUSPENDED)
nuclear@0 583 {
nuclear@0 584 Suspend();
nuclear@0 585 ThreadFlags &= (UInt32)~OVR_THREAD_START_SUSPENDED;
nuclear@0 586 }
nuclear@0 587
nuclear@0 588 // Call the virtual run function
nuclear@0 589 ExitCode = Run();
nuclear@0 590 return ExitCode;
nuclear@0 591 }
nuclear@0 592
nuclear@0 593
nuclear@0 594
nuclear@0 595
nuclear@0 596 // *** User overridables
nuclear@0 597
nuclear@0 598 bool Thread::GetExitFlag() const
nuclear@0 599 {
nuclear@0 600 return (ThreadFlags & OVR_THREAD_EXIT) != 0;
nuclear@0 601 }
nuclear@0 602
nuclear@0 603 void Thread::SetExitFlag(bool exitFlag)
nuclear@0 604 {
nuclear@0 605 // The below is atomic since ThreadFlags is AtomicInt.
nuclear@0 606 if (exitFlag)
nuclear@0 607 ThreadFlags |= OVR_THREAD_EXIT;
nuclear@0 608 else
nuclear@0 609 ThreadFlags &= (UInt32) ~OVR_THREAD_EXIT;
nuclear@0 610 }
nuclear@0 611
nuclear@0 612
nuclear@0 613 // Determines whether the thread was running and is now finished
nuclear@0 614 bool Thread::IsFinished() const
nuclear@0 615 {
nuclear@0 616 return (ThreadFlags & OVR_THREAD_FINISHED) != 0;
nuclear@0 617 }
nuclear@0 618 // Determines whether the thread is suspended
nuclear@0 619 bool Thread::IsSuspended() const
nuclear@0 620 {
nuclear@0 621 return SuspendCount > 0;
nuclear@0 622 }
nuclear@0 623 // Returns current thread state
nuclear@0 624 Thread::ThreadState Thread::GetThreadState() const
nuclear@0 625 {
nuclear@0 626 if (IsSuspended())
nuclear@0 627 return Suspended;
nuclear@0 628 if (ThreadFlags & OVR_THREAD_STARTED)
nuclear@0 629 return Running;
nuclear@0 630 return NotRunning;
nuclear@0 631 }
nuclear@0 632
nuclear@0 633 // Join thread
nuclear@0 634 bool Thread::Join(int maxWaitMs) const
nuclear@0 635 {
nuclear@0 636 // If polling,
nuclear@0 637 if (maxWaitMs == 0)
nuclear@0 638 {
nuclear@0 639 // Just return if finished
nuclear@0 640 return IsFinished();
nuclear@0 641 }
nuclear@0 642 // If waiting forever,
nuclear@0 643 else if (maxWaitMs > 0)
nuclear@0 644 {
nuclear@0 645 UInt32 t0 = Timer::GetTicksMs();
nuclear@0 646
nuclear@0 647 while (!IsFinished())
nuclear@0 648 {
nuclear@0 649 UInt32 t1 = Timer::GetTicksMs();
nuclear@0 650
nuclear@0 651 // If the wait has expired,
nuclear@0 652 int delta = (int)(t1 - t0);
nuclear@0 653 if (delta >= maxWaitMs)
nuclear@0 654 {
nuclear@0 655 return false;
nuclear@0 656 }
nuclear@0 657
nuclear@0 658 Thread::MSleep(10);
nuclear@0 659 }
nuclear@0 660
nuclear@0 661 return true;
nuclear@0 662 }
nuclear@0 663 else
nuclear@0 664 {
nuclear@0 665 while (!IsFinished())
nuclear@0 666 {
nuclear@0 667 pthread_join(ThreadHandle, NULL);
nuclear@0 668 }
nuclear@0 669 }
nuclear@0 670
nuclear@0 671 return true;
nuclear@0 672 }
nuclear@0 673
nuclear@0 674 /*
nuclear@0 675 static const char* mapsched_policy(int policy)
nuclear@0 676 {
nuclear@0 677 switch(policy)
nuclear@0 678 {
nuclear@0 679 case SCHED_OTHER:
nuclear@0 680 return "SCHED_OTHER";
nuclear@0 681 case SCHED_RR:
nuclear@0 682 return "SCHED_RR";
nuclear@0 683 case SCHED_FIFO:
nuclear@0 684 return "SCHED_FIFO";
nuclear@0 685
nuclear@0 686 }
nuclear@0 687 return "UNKNOWN";
nuclear@0 688 }
nuclear@0 689 int policy;
nuclear@0 690 sched_param sparam;
nuclear@0 691 pthread_getschedparam(pthread_self(), &policy, &sparam);
nuclear@0 692 int max_prior = sched_get_priority_max(policy);
nuclear@0 693 int min_prior = sched_get_priority_min(policy);
nuclear@0 694 printf(" !!!! policy: %s, priority: %d, max priority: %d, min priority: %d\n", mapsched_policy(policy), sparam.sched_priority, max_prior, min_prior);
nuclear@0 695 #include <stdio.h>
nuclear@0 696 */
nuclear@0 697 // ***** Thread management
nuclear@0 698
nuclear@0 699 // The actual first function called on thread start
nuclear@0 700 void* Thread_PthreadStartFn(void* phandle)
nuclear@0 701 {
nuclear@0 702 Thread* pthread = (Thread*)phandle;
nuclear@0 703 int result = pthread->PRun();
nuclear@0 704 // Signal the thread as done and release it atomically.
nuclear@0 705 pthread->FinishAndRelease();
nuclear@0 706 // At this point Thread object might be dead; however we can still pass
nuclear@0 707 // it to RemoveRunningThread since it is only used as a key there.
nuclear@0 708 ThreadList::RemoveRunningThread(pthread);
nuclear@0 709 return reinterpret_cast<void*>(result);
nuclear@0 710 }
nuclear@0 711
nuclear@0 712 int Thread::InitAttr = 0;
nuclear@0 713 pthread_attr_t Thread::Attr;
nuclear@0 714
nuclear@0 715 /* static */
nuclear@0 716 int Thread::GetOSPriority(ThreadPriority p)
nuclear@0 717 {
nuclear@0 718 OVR_UNUSED(p);
nuclear@0 719 return -1;
nuclear@0 720 }
nuclear@0 721
nuclear@0 722 /* static */
nuclear@0 723 Thread::ThreadPriority Thread::GetOVRPriority(int osPriority)
nuclear@0 724 {
nuclear@0 725 #if defined(OVR_OS_LINUX)
nuclear@0 726 return (ThreadPriority)(Thread::NormalPriority - osPriority); // This works for both SCHED_OTHER, SCHED_RR, and SCHED_FIFO.
nuclear@0 727 #else
nuclear@0 728 // Apple priorities are such that the min is a value less than the max.
nuclear@0 729 static int minPriority = sched_get_priority_min(SCHED_FIFO); // We don't have a means to pass a policy type to this function.
nuclear@0 730 static int maxPriority = sched_get_priority_max(SCHED_FIFO);
nuclear@0 731
nuclear@0 732 return (ThreadPriority)(Thread::NormalPriority - (osPriority - ((minPriority + maxPriority) / 2)));
nuclear@0 733 #endif
nuclear@0 734 }
nuclear@0 735
nuclear@0 736
nuclear@0 737 Thread::ThreadPriority Thread::GetPriority()
nuclear@0 738 {
nuclear@0 739 int policy;
nuclear@0 740 sched_param param;
nuclear@0 741
nuclear@0 742 int result = pthread_getschedparam(ThreadHandle, &policy, &param);
nuclear@0 743
nuclear@0 744 if(result == 0)
nuclear@0 745 {
nuclear@0 746 #if !defined(OVR_OS_LINUX)
nuclear@0 747 if(policy == SCHED_OTHER)
nuclear@0 748 {
nuclear@0 749 return Thread::NormalPriority; //SCHED_OTHER allows only normal priority on BSD-style Unix and Mac OS X.
nuclear@0 750 }
nuclear@0 751 #endif
nuclear@0 752
nuclear@0 753 return GetOVRPriority(param.sched_priority);
nuclear@0 754 }
nuclear@0 755
nuclear@0 756 return Thread::NormalPriority;
nuclear@0 757 }
nuclear@0 758
nuclear@0 759 /* static */
nuclear@0 760 Thread::ThreadPriority Thread::GetCurrentPriority()
nuclear@0 761 {
nuclear@0 762 int policy;
nuclear@0 763 sched_param param;
nuclear@0 764 pthread_t currentThreadId = pthread_self();
nuclear@0 765
nuclear@0 766 int result = pthread_getschedparam(currentThreadId, &policy, &param);
nuclear@0 767
nuclear@0 768 if(result == 0)
nuclear@0 769 {
nuclear@0 770 #if !defined(OVR_OS_LINUX)
nuclear@0 771 if(policy == SCHED_OTHER)
nuclear@0 772 {
nuclear@0 773 return Thread::NormalPriority; //SCHED_OTHER allows only normal priority on BSD-style Unix and Mac OS X.
nuclear@0 774 }
nuclear@0 775 #endif
nuclear@0 776
nuclear@0 777 return GetOVRPriority(param.sched_priority);
nuclear@0 778 }
nuclear@0 779
nuclear@0 780 return Thread::NormalPriority;
nuclear@0 781 }
nuclear@0 782
nuclear@0 783
nuclear@0 784 bool Thread::SetPriority(ThreadPriority)
nuclear@0 785 {
nuclear@0 786 // We currently fail. To do: add code to support this via pthread_getschedparam/pthread_attr_setschedparam
nuclear@0 787 // This won't work unless using SCHED_FIFO or SCHED_RR anyway, which require root privileges.
nuclear@0 788 return false;
nuclear@0 789 }
nuclear@0 790
nuclear@0 791 /* static */
nuclear@0 792 bool Thread::SetCurrentPriority(ThreadPriority)
nuclear@0 793 {
nuclear@0 794 // We currently fail. To do: add code to support this via pthread_getschedparam/pthread_attr_setschedparam
nuclear@0 795 // This won't work unless using SCHED_FIFO or SCHED_RR anyway, which require root privileges.
nuclear@0 796 return false;
nuclear@0 797 }
nuclear@0 798
nuclear@0 799 bool Thread::Start(ThreadState initialState)
nuclear@0 800 {
nuclear@0 801 if (initialState == NotRunning)
nuclear@0 802 return 0;
nuclear@0 803 if (GetThreadState() != NotRunning)
nuclear@0 804 {
nuclear@0 805 OVR_DEBUG_LOG(("Thread::Start failed - thread %p already running", this));
nuclear@0 806 return 0;
nuclear@0 807 }
nuclear@0 808
nuclear@0 809 if (!InitAttr)
nuclear@0 810 {
nuclear@0 811 pthread_attr_init(&Attr);
nuclear@0 812 pthread_attr_setdetachstate(&Attr, PTHREAD_CREATE_DETACHED);
nuclear@0 813 pthread_attr_setstacksize(&Attr, 128 * 1024);
nuclear@0 814 sched_param sparam;
nuclear@0 815 sparam.sched_priority = Thread::GetOSPriority(NormalPriority);
nuclear@0 816 pthread_attr_setschedparam(&Attr, &sparam);
nuclear@0 817 InitAttr = 1;
nuclear@0 818 }
nuclear@0 819
nuclear@0 820 ExitCode = 0;
nuclear@0 821 SuspendCount = 0;
nuclear@0 822 ThreadFlags = (initialState == Running) ? 0 : OVR_THREAD_START_SUSPENDED;
nuclear@0 823
nuclear@0 824 // AddRef to us until the thread is finished
nuclear@0 825 AddRef();
nuclear@0 826 ThreadList::AddRunningThread(this);
nuclear@0 827
nuclear@0 828 int result;
nuclear@0 829 if (StackSize != 128 * 1024 || Priority != NormalPriority)
nuclear@0 830 {
nuclear@0 831 pthread_attr_t attr;
nuclear@0 832
nuclear@0 833 pthread_attr_init(&attr);
nuclear@0 834 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
nuclear@0 835 pthread_attr_setstacksize(&attr, StackSize);
nuclear@0 836 sched_param sparam;
nuclear@0 837 sparam.sched_priority = Thread::GetOSPriority(Priority);
nuclear@0 838 pthread_attr_setschedparam(&attr, &sparam);
nuclear@0 839 result = pthread_create(&ThreadHandle, &attr, Thread_PthreadStartFn, this);
nuclear@0 840 pthread_attr_destroy(&attr);
nuclear@0 841 }
nuclear@0 842 else
nuclear@0 843 result = pthread_create(&ThreadHandle, &Attr, Thread_PthreadStartFn, this);
nuclear@0 844
nuclear@0 845 if (result)
nuclear@0 846 {
nuclear@0 847 ThreadFlags = 0;
nuclear@0 848 Release();
nuclear@0 849 ThreadList::RemoveRunningThread(this);
nuclear@0 850 return 0;
nuclear@0 851 }
nuclear@0 852 return 1;
nuclear@0 853 }
nuclear@0 854
nuclear@0 855
nuclear@0 856 // Suspend the thread until resumed
nuclear@0 857 bool Thread::Suspend()
nuclear@0 858 {
nuclear@0 859 OVR_DEBUG_LOG(("Thread::Suspend - cannot suspend threads on this system"));
nuclear@0 860 return 0;
nuclear@0 861 }
nuclear@0 862
nuclear@0 863 // Resumes currently suspended thread
nuclear@0 864 bool Thread::Resume()
nuclear@0 865 {
nuclear@0 866 return 0;
nuclear@0 867 }
nuclear@0 868
nuclear@0 869
nuclear@0 870 // Quits with an exit code
nuclear@0 871 void Thread::Exit(int exitCode)
nuclear@0 872 {
nuclear@0 873 // Can only exist the current thread
nuclear@0 874 // if (GetThread() != this)
nuclear@0 875 // return;
nuclear@0 876
nuclear@0 877 // Call the virtual OnExit function
nuclear@0 878 OnExit();
nuclear@0 879
nuclear@0 880 // Signal this thread object as done and release it's references.
nuclear@0 881 FinishAndRelease();
nuclear@0 882 ThreadList::RemoveRunningThread(this);
nuclear@0 883
nuclear@0 884 pthread_exit(reinterpret_cast<void*>(exitCode));
nuclear@0 885 }
nuclear@0 886
nuclear@0 887 ThreadId GetCurrentThreadId()
nuclear@0 888 {
nuclear@0 889 return (void*)pthread_self();
nuclear@0 890 }
nuclear@0 891
nuclear@0 892 // *** Sleep functions
nuclear@0 893
nuclear@0 894 /* static */
nuclear@0 895 bool Thread::Sleep(unsigned secs)
nuclear@0 896 {
nuclear@0 897 sleep(secs);
nuclear@0 898 return 1;
nuclear@0 899 }
nuclear@0 900 /* static */
nuclear@0 901 bool Thread::MSleep(unsigned msecs)
nuclear@0 902 {
nuclear@0 903 usleep(msecs*1000);
nuclear@0 904 return 1;
nuclear@0 905 }
nuclear@0 906
nuclear@0 907 /* static */
nuclear@0 908 int Thread::GetCPUCount()
nuclear@0 909 {
nuclear@0 910 #if defined(OVR_OS_MAC) || defined(OVR_OS_BSD)
nuclear@0 911 // http://developer.apple.com/mac/library/documentation/Darwin/Reference/ManPages/man3/sysctlbyname.3.html
nuclear@0 912 int cpuCount = 0;
nuclear@0 913 size_t len = sizeof(cpuCount);
nuclear@0 914
nuclear@0 915 if(sysctlbyname("hw.logicalcpu", &cpuCount, &len, NULL, 0) != 0)
nuclear@0 916 cpuCount = 1;
nuclear@0 917
nuclear@0 918 return cpuCount;
nuclear@0 919
nuclear@0 920 #else // Linux, Android
nuclear@0 921
nuclear@0 922 // Alternative: read /proc/cpuinfo
nuclear@0 923 #ifdef _SC_NPROCESSORS_ONLN
nuclear@0 924 return (int)sysconf(_SC_NPROCESSORS_ONLN);
nuclear@0 925 #else
nuclear@0 926 return 1;
nuclear@0 927 #endif
nuclear@0 928 #endif
nuclear@0 929 }
nuclear@0 930
nuclear@0 931
nuclear@0 932 void Thread::SetThreadName( const char* name )
nuclear@0 933 {
nuclear@0 934 #if defined (OVR_OS_APPLE)
nuclear@0 935 if(ThreadHandle == pthread_self())
nuclear@0 936 pthread_setname_np(name);
nuclear@0 937 // Else there's nothing we can do.
nuclear@0 938 #else
nuclear@0 939 if(ThreadHandle != 0)
nuclear@0 940 pthread_setname_np(ThreadHandle, name);
nuclear@0 941 // Else we can possibly save this name and set it later when the thread starts.
nuclear@0 942 #endif
nuclear@0 943 }
nuclear@0 944
nuclear@0 945
nuclear@0 946 void Thread::SetThreadName(const char* name, ThreadId threadId)
nuclear@0 947 {
nuclear@0 948 #if defined (OVR_OS_APPLE)
nuclear@0 949 if(pthread_equal((pthread_t)threadId, pthread_self()))
nuclear@0 950 pthread_setname_np(name);
nuclear@0 951 // Else there's no way to set the name of another thread.
nuclear@0 952 #else
nuclear@0 953 pthread_setname_np((pthread_t)threadId, name);
nuclear@0 954 #endif
nuclear@0 955 }
nuclear@0 956
nuclear@0 957
nuclear@0 958 void Thread::SetCurrentThreadName(const char* name)
nuclear@0 959 {
nuclear@0 960 #if defined (OVR_OS_APPLE)
nuclear@0 961 pthread_setname_np(name);
nuclear@0 962 #else
nuclear@0 963 pthread_setname_np(pthread_self(), name);
nuclear@0 964 #endif
nuclear@0 965 }
nuclear@0 966
nuclear@0 967
nuclear@0 968 void Thread::GetThreadName(char* name, size_t nameCapacity, ThreadId threadId)
nuclear@0 969 {
nuclear@0 970 name[0] = 0;
nuclear@0 971 pthread_getname_np((pthread_t)threadId, name, nameCapacity);
nuclear@0 972 }
nuclear@0 973
nuclear@0 974
nuclear@0 975 void Thread::GetCurrentThreadName(char* name, size_t nameCapacity)
nuclear@0 976 {
nuclear@0 977 name[0] = 0;
nuclear@0 978 pthread_getname_np(pthread_self(), name, nameCapacity);
nuclear@0 979 }
nuclear@0 980
nuclear@0 981
nuclear@0 982 } // namespace OVR
nuclear@0 983
nuclear@0 984 #endif // OVR_ENABLE_THREADS