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