oculus1

annotate libovr/Src/Kernel/OVR_Threads.h @ 29:9a973ef0e2a3

fixed the performance issue under MacOSX by replacing glutSolidTeapot (which uses glEvalMesh) with my own teapot generator.
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 27 Oct 2013 06:31:18 +0200
parents e2f9e4603129
children
rev   line source
nuclear@3 1 /************************************************************************************
nuclear@3 2
nuclear@3 3 PublicHeader: None
nuclear@3 4 Filename : OVR_Threads.h
nuclear@3 5 Content : Contains thread-related (safe) functionality
nuclear@3 6 Created : September 19, 2012
nuclear@3 7 Notes :
nuclear@3 8
nuclear@3 9 Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
nuclear@3 10
nuclear@3 11 Use of this software is subject to the terms of the Oculus license
nuclear@3 12 agreement provided at the time of installation or download, or which
nuclear@3 13 otherwise accompanies this software in either electronic or hard copy form.
nuclear@3 14
nuclear@3 15 ************************************************************************************/
nuclear@3 16 #ifndef OVR_Threads_h
nuclear@3 17 #define OVR_Threads_h
nuclear@3 18
nuclear@3 19 #include "OVR_Types.h"
nuclear@3 20 #include "OVR_Atomic.h"
nuclear@3 21 #include "OVR_RefCount.h"
nuclear@3 22 #include "OVR_Array.h"
nuclear@3 23
nuclear@3 24 // Defines the infinite wait delay timeout
nuclear@3 25 #define OVR_WAIT_INFINITE 0xFFFFFFFF
nuclear@3 26
nuclear@3 27 // To be defined in the project configuration options
nuclear@3 28 #ifdef OVR_ENABLE_THREADS
nuclear@3 29
nuclear@3 30
nuclear@3 31 namespace OVR {
nuclear@3 32
nuclear@3 33 //-----------------------------------------------------------------------------------
nuclear@3 34 // ****** Declared classes
nuclear@3 35
nuclear@3 36 // Declared with thread support only
nuclear@3 37 class Mutex;
nuclear@3 38 class WaitCondition;
nuclear@3 39 class Event;
nuclear@3 40 // Implementation forward declarations
nuclear@3 41 class MutexImpl;
nuclear@3 42 class WaitConditionImpl;
nuclear@3 43
nuclear@3 44
nuclear@3 45
nuclear@3 46 //-----------------------------------------------------------------------------------
nuclear@3 47 // ***** Mutex
nuclear@3 48
nuclear@3 49 // Mutex class represents a system Mutex synchronization object that provides access
nuclear@3 50 // serialization between different threads, allowing one thread mutually exclusive access
nuclear@3 51 // to a resource. Mutex is more heavy-weight then Lock, but supports WaitCondition.
nuclear@3 52
nuclear@3 53 class Mutex
nuclear@3 54 {
nuclear@3 55 friend class WaitConditionImpl;
nuclear@3 56 friend class MutexImpl;
nuclear@3 57
nuclear@3 58 MutexImpl *pImpl;
nuclear@3 59
nuclear@3 60 public:
nuclear@3 61 // Constructor/destructor
nuclear@3 62 Mutex(bool recursive = 1);
nuclear@3 63 ~Mutex();
nuclear@3 64
nuclear@3 65 // Locking functions
nuclear@3 66 void DoLock();
nuclear@3 67 bool TryLock();
nuclear@3 68 void Unlock();
nuclear@3 69
nuclear@3 70 // Returns 1 if the mutes is currently locked by another thread
nuclear@3 71 // Returns 0 if the mutex is not locked by another thread, and can therefore be acquired.
nuclear@3 72 bool IsLockedByAnotherThread();
nuclear@3 73
nuclear@3 74 // Locker class; Used for automatic locking of a mutex withing scope
nuclear@3 75 class Locker
nuclear@3 76 {
nuclear@3 77 public:
nuclear@3 78 Mutex *pMutex;
nuclear@3 79 Locker(Mutex *pmutex)
nuclear@3 80 { pMutex = pmutex; pMutex->DoLock(); }
nuclear@3 81 ~Locker()
nuclear@3 82 { pMutex->Unlock(); }
nuclear@3 83 };
nuclear@3 84 };
nuclear@3 85
nuclear@3 86
nuclear@3 87 //-----------------------------------------------------------------------------------
nuclear@3 88 // ***** WaitCondition
nuclear@3 89
nuclear@3 90 /*
nuclear@3 91 WaitCondition is a synchronization primitive that can be used to implement what is known as a monitor.
nuclear@3 92 Dependent threads wait on a wait condition by calling Wait(), and get woken up by other threads that
nuclear@3 93 call Notify() or NotifyAll().
nuclear@3 94
nuclear@3 95 The unique feature of this class is that it provides an atomic way of first releasing a Mutex, and then
nuclear@3 96 starting a wait on a wait condition. If both the mutex and the wait condition are associated with the same
nuclear@3 97 resource, this ensures that any condition checked for while the mutex was locked does not change before
nuclear@3 98 the wait on the condition is actually initiated.
nuclear@3 99 */
nuclear@3 100
nuclear@3 101 class WaitCondition
nuclear@3 102 {
nuclear@3 103 friend class WaitConditionImpl;
nuclear@3 104 // Internal implementation structure
nuclear@3 105 WaitConditionImpl *pImpl;
nuclear@3 106
nuclear@3 107 public:
nuclear@3 108 // Constructor/destructor
nuclear@3 109 WaitCondition();
nuclear@3 110 ~WaitCondition();
nuclear@3 111
nuclear@3 112 // Release mutex and wait for condition. The mutex is re-aquired after the wait.
nuclear@3 113 // Delay is specified in milliseconds (1/1000 of a second).
nuclear@3 114 bool Wait(Mutex *pmutex, unsigned delay = OVR_WAIT_INFINITE);
nuclear@3 115
nuclear@3 116 // Notify a condition, releasing at one object waiting
nuclear@3 117 void Notify();
nuclear@3 118 // Notify a condition, releasing all objects waiting
nuclear@3 119 void NotifyAll();
nuclear@3 120 };
nuclear@3 121
nuclear@3 122
nuclear@3 123 //-----------------------------------------------------------------------------------
nuclear@3 124 // ***** Event
nuclear@3 125
nuclear@3 126 // Event is a wait-able synchronization object similar to Windows event.
nuclear@3 127 // Event can be waited on until it's signaled by another thread calling
nuclear@3 128 // either SetEvent or PulseEvent.
nuclear@3 129
nuclear@3 130 class Event
nuclear@3 131 {
nuclear@3 132 // Event state, its mutex and the wait condition
nuclear@3 133 volatile bool State;
nuclear@3 134 volatile bool Temporary;
nuclear@3 135 mutable Mutex StateMutex;
nuclear@3 136 WaitCondition StateWaitCondition;
nuclear@3 137
nuclear@3 138 void updateState(bool newState, bool newTemp, bool mustNotify);
nuclear@3 139
nuclear@3 140 public:
nuclear@3 141 Event(bool setInitially = 0) : State(setInitially), Temporary(false) { }
nuclear@3 142 ~Event() { }
nuclear@3 143
nuclear@3 144 // Wait on an event condition until it is set
nuclear@3 145 // Delay is specified in milliseconds (1/1000 of a second).
nuclear@3 146 bool Wait(unsigned delay = OVR_WAIT_INFINITE);
nuclear@3 147
nuclear@3 148 // Set an event, releasing objects waiting on it
nuclear@3 149 void SetEvent()
nuclear@3 150 { updateState(true, false, true); }
nuclear@3 151
nuclear@3 152 // Reset an event, un-signaling it
nuclear@3 153 void ResetEvent()
nuclear@3 154 { updateState(false, false, false); }
nuclear@3 155
nuclear@3 156 // Set and then reset an event once a waiter is released.
nuclear@3 157 // If threads are already waiting, they will be notified and released
nuclear@3 158 // If threads are not waiting, the event is set until the first thread comes in
nuclear@3 159 void PulseEvent()
nuclear@3 160 { updateState(true, true, true); }
nuclear@3 161 };
nuclear@3 162
nuclear@3 163
nuclear@3 164 //-----------------------------------------------------------------------------------
nuclear@3 165 // ***** Thread class
nuclear@3 166
nuclear@3 167 // ThreadId uniquely identifies a thread; returned by GetCurrentThreadId() and
nuclear@3 168 // Thread::GetThreadId.
nuclear@3 169 typedef void* ThreadId;
nuclear@3 170
nuclear@3 171
nuclear@3 172 // *** Thread flags
nuclear@3 173
nuclear@3 174 // Indicates that the thread is has been started, i.e. Start method has been called, and threads
nuclear@3 175 // OnExit() method has not yet been called/returned.
nuclear@3 176 #define OVR_THREAD_STARTED 0x01
nuclear@3 177 // This flag is set once the thread has ran, and finished.
nuclear@3 178 #define OVR_THREAD_FINISHED 0x02
nuclear@3 179 // This flag is set temporarily if this thread was started suspended. It is used internally.
nuclear@3 180 #define OVR_THREAD_START_SUSPENDED 0x08
nuclear@3 181 // This flag is used to ask a thread to exit. Message driven threads will usually check this flag
nuclear@3 182 // and finish once it is set.
nuclear@3 183 #define OVR_THREAD_EXIT 0x10
nuclear@3 184
nuclear@3 185
nuclear@3 186 class Thread : public RefCountBase<Thread>
nuclear@3 187 { // NOTE: Waitable must be the first base since it implements RefCountImpl.
nuclear@3 188
nuclear@3 189 public:
nuclear@3 190
nuclear@3 191 // *** Callback functions, can be used instead of overriding Run
nuclear@3 192
nuclear@3 193 // Run function prototypes.
nuclear@3 194 // Thread function and user handle passed to it, executed by the default
nuclear@3 195 // Thread::Run implementation if not null.
nuclear@3 196 typedef int (*ThreadFn)(Thread *pthread, void* h);
nuclear@3 197
nuclear@3 198 // Thread ThreadFunction1 is executed if not 0, otherwise ThreadFunction2 is tried
nuclear@3 199 ThreadFn ThreadFunction;
nuclear@3 200 // User handle passes to a thread
nuclear@3 201 void* UserHandle;
nuclear@3 202
nuclear@3 203 // Thread state to start a thread with
nuclear@3 204 enum ThreadState
nuclear@3 205 {
nuclear@3 206 NotRunning = 0,
nuclear@3 207 Running = 1,
nuclear@3 208 Suspended = 2
nuclear@3 209 };
nuclear@3 210
nuclear@3 211 // Thread priority
nuclear@3 212 enum ThreadPriority
nuclear@3 213 {
nuclear@3 214 CriticalPriority,
nuclear@3 215 HighestPriority,
nuclear@3 216 AboveNormalPriority,
nuclear@3 217 NormalPriority,
nuclear@3 218 BelowNormalPriority,
nuclear@3 219 LowestPriority,
nuclear@3 220 IdlePriority,
nuclear@3 221 };
nuclear@3 222
nuclear@3 223 // Thread constructor parameters
nuclear@3 224 struct CreateParams
nuclear@3 225 {
nuclear@3 226 CreateParams(ThreadFn func = 0, void* hand = 0, UPInt ssize = 128 * 1024,
nuclear@3 227 int proc = -1, ThreadState state = NotRunning, ThreadPriority prior = NormalPriority)
nuclear@3 228 : threadFunction(func), userHandle(hand), stackSize(ssize),
nuclear@3 229 processor(proc), initialState(state), priority(prior) {}
nuclear@3 230 ThreadFn threadFunction; // Thread function
nuclear@3 231 void* userHandle; // User handle passes to a thread
nuclear@3 232 UPInt stackSize; // Thread stack size
nuclear@3 233 int processor; // Thread hardware processor
nuclear@3 234 ThreadState initialState; //
nuclear@3 235 ThreadPriority priority; // Thread priority
nuclear@3 236 };
nuclear@3 237
nuclear@3 238 // *** Constructors
nuclear@3 239
nuclear@3 240 // A default constructor always creates a thread in NotRunning state, because
nuclear@3 241 // the derived class has not yet been initialized. The derived class can call Start explicitly.
nuclear@3 242 // "processor" parameter specifies which hardware processor this thread will be run on.
nuclear@3 243 // -1 means OS decides this. Implemented only on Win32
nuclear@3 244 Thread(UPInt stackSize = 128 * 1024, int processor = -1);
nuclear@3 245 // Constructors that initialize the thread with a pointer to function.
nuclear@3 246 // An option to start a thread is available, but it should not be used if classes are derived from Thread.
nuclear@3 247 // "processor" parameter specifies which hardware processor this thread will be run on.
nuclear@3 248 // -1 means OS decides this. Implemented only on Win32
nuclear@3 249 Thread(ThreadFn threadFunction, void* userHandle = 0, UPInt stackSize = 128 * 1024,
nuclear@3 250 int processor = -1, ThreadState initialState = NotRunning);
nuclear@3 251 // Constructors that initialize the thread with a create parameters structure.
nuclear@3 252 explicit Thread(const CreateParams& params);
nuclear@3 253
nuclear@3 254 // Destructor.
nuclear@3 255 virtual ~Thread();
nuclear@3 256
nuclear@3 257 // Waits for all Threads to finish; should be called only from the root
nuclear@3 258 // application thread. Once this function returns, we know that all other
nuclear@3 259 // thread's references to Thread object have been released.
nuclear@3 260 static void OVR_CDECL FinishAllThreads();
nuclear@3 261
nuclear@3 262
nuclear@3 263 // *** Overridable Run function for thread processing
nuclear@3 264
nuclear@3 265 // - returning from this method will end the execution of the thread
nuclear@3 266 // - return value is usually 0 for success
nuclear@3 267 virtual int Run();
nuclear@3 268 // Called after return/exit function
nuclear@3 269 virtual void OnExit();
nuclear@3 270
nuclear@3 271
nuclear@3 272 // *** Thread management
nuclear@3 273
nuclear@3 274 // Starts the thread if its not already running
nuclear@3 275 // - internally sets up the threading and calls Run()
nuclear@3 276 // - initial state can either be Running or Suspended, NotRunning will just fail and do nothing
nuclear@3 277 // - returns the exit code
nuclear@3 278 virtual bool Start(ThreadState initialState = Running);
nuclear@3 279
nuclear@3 280 // Quits with an exit code
nuclear@3 281 virtual void Exit(int exitCode=0);
nuclear@3 282
nuclear@3 283 // Suspend the thread until resumed
nuclear@3 284 // Returns 1 for success, 0 for failure.
nuclear@3 285 bool Suspend();
nuclear@3 286 // Resumes currently suspended thread
nuclear@3 287 // Returns 1 for success, 0 for failure.
nuclear@3 288 bool Resume();
nuclear@3 289
nuclear@3 290 // Static function to return a pointer to the current thread
nuclear@3 291 //static Thread* GetThread();
nuclear@3 292
nuclear@3 293
nuclear@3 294 // *** Thread status query functions
nuclear@3 295
nuclear@3 296 bool GetExitFlag() const;
nuclear@3 297 void SetExitFlag(bool exitFlag);
nuclear@3 298
nuclear@3 299 // Determines whether the thread was running and is now finished
nuclear@3 300 bool IsFinished() const;
nuclear@3 301 // Determines if the thread is currently suspended
nuclear@3 302 bool IsSuspended() const;
nuclear@3 303 // Returns current thread state
nuclear@3 304 ThreadState GetThreadState() const;
nuclear@3 305
nuclear@3 306 // Returns the number of available CPUs on the system
nuclear@3 307 static int GetCPUCount();
nuclear@3 308
nuclear@3 309 // Returns the thread exit code. Exit code is initialized to 0,
nuclear@3 310 // and set to the return value if Run function after the thread is finished.
nuclear@3 311 inline int GetExitCode() const { return ExitCode; }
nuclear@3 312 // Returns an OS handle
nuclear@3 313 #if defined(OVR_OS_WIN32)
nuclear@3 314 void* GetOSHandle() const { return ThreadHandle; }
nuclear@3 315 #else
nuclear@3 316 pthread_t GetOSHandle() const { return ThreadHandle; }
nuclear@3 317 #endif
nuclear@3 318
nuclear@3 319 #if defined(OVR_OS_WIN32)
nuclear@3 320 ThreadId GetThreadId() const { return IdValue; }
nuclear@3 321 #else
nuclear@3 322 ThreadId GetThreadId() const { return (ThreadId)GetOSHandle(); }
nuclear@3 323 #endif
nuclear@3 324
nuclear@3 325 static int GetOSPriority(ThreadPriority);
nuclear@3 326 // *** Sleep
nuclear@3 327
nuclear@3 328 // Sleep secs seconds
nuclear@3 329 static bool Sleep(unsigned secs);
nuclear@3 330 // Sleep msecs milliseconds
nuclear@3 331 static bool MSleep(unsigned msecs);
nuclear@3 332
nuclear@3 333
nuclear@3 334 // *** Debugging functionality
nuclear@3 335 #if defined(OVR_OS_WIN32)
nuclear@3 336 virtual void SetThreadName( const char* name );
nuclear@3 337 #else
nuclear@3 338 virtual void SetThreadName( const char* name ) { OVR_UNUSED(name); }
nuclear@3 339 #endif
nuclear@3 340
nuclear@3 341 private:
nuclear@3 342 #if defined(OVR_OS_WIN32)
nuclear@3 343 friend unsigned WINAPI Thread_Win32StartFn(void *pthread);
nuclear@3 344
nuclear@3 345 #else
nuclear@3 346 friend void *Thread_PthreadStartFn(void * phandle);
nuclear@3 347
nuclear@3 348 static int InitAttr;
nuclear@3 349 static pthread_attr_t Attr;
nuclear@3 350 #endif
nuclear@3 351
nuclear@3 352 protected:
nuclear@3 353 // Thread state flags
nuclear@3 354 AtomicInt<UInt32> ThreadFlags;
nuclear@3 355 AtomicInt<SInt32> SuspendCount;
nuclear@3 356 UPInt StackSize;
nuclear@3 357
nuclear@3 358 // Hardware processor which this thread is running on.
nuclear@3 359 int Processor;
nuclear@3 360 ThreadPriority Priority;
nuclear@3 361
nuclear@3 362 #if defined(OVR_OS_WIN32)
nuclear@3 363 void* ThreadHandle;
nuclear@3 364 volatile ThreadId IdValue;
nuclear@3 365
nuclear@3 366 // System-specific cleanup function called from destructor
nuclear@3 367 void CleanupSystemThread();
nuclear@3 368
nuclear@3 369 #else
nuclear@3 370 pthread_t ThreadHandle;
nuclear@3 371 #endif
nuclear@3 372
nuclear@3 373 // Exit code of the thread, as returned by Run.
nuclear@3 374 int ExitCode;
nuclear@3 375
nuclear@3 376 // Internal run function.
nuclear@3 377 int PRun();
nuclear@3 378 // Finishes the thread and releases internal reference to it.
nuclear@3 379 void FinishAndRelease();
nuclear@3 380
nuclear@3 381 void Init(const CreateParams& params);
nuclear@3 382
nuclear@3 383 // Protected copy constructor
nuclear@3 384 Thread(const Thread &source) { OVR_UNUSED(source); }
nuclear@3 385
nuclear@3 386 };
nuclear@3 387
nuclear@3 388 // Returns the unique Id of a thread it is called on, intended for
nuclear@3 389 // comparison purposes.
nuclear@3 390 ThreadId GetCurrentThreadId();
nuclear@3 391
nuclear@3 392
nuclear@3 393 } // OVR
nuclear@3 394
nuclear@3 395 #endif // OVR_ENABLE_THREADS
nuclear@3 396 #endif // OVR_Threads_h