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