ovr_sdk

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