oculus1

view libovr/Src/OVR_ThreadCommandQueue.h @ 23:0c76f70fb7e9

merged
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 28 Sep 2013 04:13:33 +0300
parents
children
line source
1 /************************************************************************************
3 PublicHeader: None
4 Filename : OVR_ThreadCommandQueue.h
5 Content : Command queue for operations executed on a thread
6 Created : October 29, 2012
7 Author : Michael Antonov
9 Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved.
11 Use of this software is subject to the terms of the Oculus license
12 agreement provided at the time of installation or download, or which
13 otherwise accompanies this software in either electronic or hard copy form.
15 ************************************************************************************/
17 #ifndef OVR_ThreadCommandQueue_h
18 #define OVR_ThreadCommandQueue_h
20 #include "Kernel/OVR_Types.h"
21 #include "Kernel/OVR_List.h"
22 #include "Kernel/OVR_Atomic.h"
23 #include "Kernel/OVR_Threads.h"
25 namespace OVR {
27 class ThreadCommand;
28 class ThreadCommandQueue;
31 //-------------------------------------------------------------------------------------
32 // ***** ThreadCommand
34 // ThreadCommand is a base class implementation for commands stored in ThreadCommandQueue.
35 class ThreadCommand
36 {
37 public:
39 // NotifyEvent is used by ThreadCommandQueue::PushCallAndWait to notify the
40 // calling (producer) thread when command is completed or queue slot is available.
41 class NotifyEvent : public ListNode<NotifyEvent>, public NewOverrideBase
42 {
43 Event E;
44 public:
45 NotifyEvent() { }
47 void Wait() { E.Wait(); }
48 void PulseEvent() { E.PulseEvent(); }
49 };
51 // ThreadCommand::PopBuffer is temporary storage for a command popped off
52 // by ThreadCommandQueue::PopCommand.
53 class PopBuffer
54 {
55 enum { MaxSize = 256 };
57 UPInt Size;
58 union {
59 UByte Buffer[MaxSize];
60 UPInt Align;
61 };
63 ThreadCommand* toCommand() const { return (ThreadCommand*)Buffer; }
65 public:
66 PopBuffer() : Size(0) { }
67 ~PopBuffer();
69 void InitFromBuffer(void* data);
71 bool HasCommand() const { return Size != 0; }
72 UPInt GetSize() const { return Size; }
73 bool NeedsWait() const { return toCommand()->NeedsWait(); }
74 NotifyEvent* GetEvent() const { return toCommand()->pEvent; }
76 // Execute the command and also notifies caller to finish waiting,
77 // if necessary.
78 void Execute();
79 };
81 UInt16 Size;
82 bool WaitFlag;
83 bool ExitFlag; // Marks the last exit command.
84 NotifyEvent* pEvent;
86 ThreadCommand(UPInt size, bool waitFlag, bool exitFlag = false)
87 : Size((UInt16)size), WaitFlag(waitFlag), ExitFlag(exitFlag), pEvent(0) { }
88 virtual ~ThreadCommand() { }
90 bool NeedsWait() const { return WaitFlag; }
91 UPInt GetSize() const { return Size; }
93 virtual void Execute() const = 0;
94 // Copy constructor used for serializing this to memory buffer.
95 virtual ThreadCommand* CopyConstruct(void* p) const = 0;
96 };
99 //-------------------------------------------------------------------------------------
101 // CleanType is a template that strips 'const' and '&' modifiers from the argument type;
102 // for example, typename CleanType<A&>::Type is equivalent to A.
103 template<class T> struct CleanType { typedef T Type; };
104 template<class T> struct CleanType<T&> { typedef T Type; };
105 template<class T> struct CleanType<const T> { typedef T Type; };
106 template<class T> struct CleanType<const T&> { typedef T Type; };
108 // SelfType is a template that yields the argument type. This helps avoid conflicts with
109 // automatic template argument deduction for function calls when identical argument
110 // is already defined.
111 template<class T> struct SelfType { typedef T Type; };
115 //-------------------------------------------------------------------------------------
116 // ThreadCommand specializations for member functions with different number of
117 // arguments and argument types.
119 // Used to return nothing from a ThreadCommand, to avoid problems with 'void'.
120 struct Void
121 {
122 Void() {}
123 Void(int) {}
124 };
126 // ThreadCommand for member function with 0 arguments.
127 template<class C, class R>
128 class ThreadCommandMF0 : public ThreadCommand
129 {
130 typedef R (C::*FnPtr)();
131 C* pClass;
132 FnPtr pFn;
133 R* pRet;
135 void executeImpl() const
136 {
137 pRet ? (void)(*pRet = (pClass->*pFn)()) :
138 (void)(pClass->*pFn)();
139 }
141 public:
142 ThreadCommandMF0(C* pclass, FnPtr fn, R* ret, bool needsWait)
143 : ThreadCommand(sizeof(ThreadCommandMF0), needsWait),
144 pClass(pclass), pFn(fn), pRet(ret) { }
146 virtual void Execute() const { executeImpl(); }
147 virtual ThreadCommand* CopyConstruct(void* p) const
148 { return Construct<ThreadCommandMF0>(p, *this); }
149 };
152 // ThreadCommand for member function with 1 argument.
153 template<class C, class R, class A0>
154 class ThreadCommandMF1 : public ThreadCommand
155 {
156 typedef R (C::*FnPtr)(A0);
157 C* pClass;
158 FnPtr pFn;
159 R* pRet;
160 typename CleanType<A0>::Type AVal0;
162 void executeImpl() const
163 {
164 pRet ? (void)(*pRet = (pClass->*pFn)(AVal0)) :
165 (void)(pClass->*pFn)(AVal0);
166 }
168 public:
169 ThreadCommandMF1(C* pclass, FnPtr fn, R* ret, A0 a0, bool needsWait)
170 : ThreadCommand(sizeof(ThreadCommandMF1), needsWait),
171 pClass(pclass), pFn(fn), pRet(ret), AVal0(a0) { }
173 virtual void Execute() const { executeImpl(); }
174 virtual ThreadCommand* CopyConstruct(void* p) const
175 { return Construct<ThreadCommandMF1>(p, *this); }
176 };
178 // ThreadCommand for member function with 2 arguments.
179 template<class C, class R, class A0, class A1>
180 class ThreadCommandMF2 : public ThreadCommand
181 {
182 typedef R (C::*FnPtr)(A0, A1);
183 C* pClass;
184 FnPtr pFn;
185 R* pRet;
186 typename CleanType<A0>::Type AVal0;
187 typename CleanType<A1>::Type AVal1;
189 void executeImpl() const
190 {
191 pRet ? (void)(*pRet = (pClass->*pFn)(AVal0, AVal1)) :
192 (void)(pClass->*pFn)(AVal0, AVal1);
193 }
195 public:
196 ThreadCommandMF2(C* pclass, FnPtr fn, R* ret, A0 a0, A1 a1, bool needsWait)
197 : ThreadCommand(sizeof(ThreadCommandMF2), needsWait),
198 pClass(pclass), pFn(fn), pRet(ret), AVal0(a0), AVal1(a1) { }
200 virtual void Execute() const { executeImpl(); }
201 virtual ThreadCommand* CopyConstruct(void* p) const
202 { return Construct<ThreadCommandMF2>(p, *this); }
203 };
206 //-------------------------------------------------------------------------------------
207 // ***** ThreadCommandQueue
209 // ThreadCommandQueue is a queue of executable function-call commands intended to be
210 // serviced by a single consumer thread. Commands are added to the queue with PushCall
211 // and removed with PopCall; they are processed in FIFO order. Multiple producer threads
212 // are supported and will be blocked if internal data buffer is full.
214 class ThreadCommandQueue
215 {
216 public:
218 ThreadCommandQueue();
219 virtual ~ThreadCommandQueue();
222 // Pops the next command from the thread queue, if any is available.
223 // The command should be executed by calling popBuffer->Execute().
224 // Returns 'false' if no command is available at the time of the call.
225 bool PopCommand(ThreadCommand::PopBuffer* popBuffer);
227 // Generic implementaion of PushCommand; enqueues a command for execution.
228 // Returns 'false' if push failed, usually indicating thread shutdown.
229 bool PushCommand(const ThreadCommand& command);
231 //
232 void PushExitCommand(bool wait);
234 // Returns 'true' once ExitCommand has been processed, so the thread can shut down.
235 bool IsExiting() const;
238 // These two virtual functions serve as notifications for derived
239 // thread waiting.
240 virtual void OnPushNonEmpty_Locked() { }
241 virtual void OnPopEmpty_Locked() { }
244 // *** PushCall with no result
246 // Enqueue a member function of 'this' class to be called on consumer thread.
247 // By default the function returns immediately; set 'wait' argument to 'true' to
248 // wait for completion.
249 template<class C, class R>
250 bool PushCall(R (C::*fn)(), bool wait = false)
251 { return PushCommand(ThreadCommandMF0<C,R>(static_cast<C*>(this), fn, 0, wait)); }
252 template<class C, class R, class A0>
253 bool PushCall(R (C::*fn)(A0), typename SelfType<A0>::Type a0, bool wait = false)
254 { return PushCommand(ThreadCommandMF1<C,R,A0>(static_cast<C*>(this), fn, 0, a0, wait)); }
255 template<class C, class R, class A0, class A1>
256 bool PushCall(R (C::*fn)(A0, A1),
257 typename SelfType<A0>::Type a0, typename SelfType<A1>::Type a1, bool wait = false)
258 { return PushCommand(ThreadCommandMF2<C,R,A0,A1>(static_cast<C*>(this), fn, 0, a0, a1, wait)); }
259 // Enqueue a specified member function call of class C.
260 // By default the function returns immediately; set 'wait' argument to 'true' to
261 // wait for completion.
262 template<class C, class R>
263 bool PushCall(C* p, R (C::*fn)(), bool wait = false)
264 { return PushCommand(ThreadCommandMF0<C,R>(p, fn, 0, wait)); }
265 template<class C, class R, class A0>
266 bool PushCall(C* p, R (C::*fn)(A0), typename SelfType<A0>::Type a0, bool wait = false)
267 { return PushCommand(ThreadCommandMF1<C,R,A0>(p, fn, 0, a0, wait)); }
268 template<class C, class R, class A0, class A1>
269 bool PushCall(C* p, R (C::*fn)(A0, A1),
270 typename SelfType<A0>::Type a0, typename SelfType<A1>::Type a1, bool wait = false)
271 { return PushCommand(ThreadCommandMF2<C,R,A0,A1>(p, fn, 0, a0, a1, wait)); }
274 // *** PushCall with Result
276 // Enqueue a member function of 'this' class call and wait for call to complete
277 // on consumer thread before returning.
278 template<class C, class R>
279 bool PushCallAndWaitResult(R (C::*fn)(), R* ret)
280 { return PushCommand(ThreadCommandMF0<C,R>(static_cast<C*>(this), fn, ret, true)); }
281 template<class C, class R, class A0>
282 bool PushCallAndWaitResult(R (C::*fn)(A0), R* ret, typename SelfType<A0>::Type a0)
283 { return PushCommand(ThreadCommandMF1<C,R,A0>(static_cast<C*>(this), fn, ret, a0, true)); }
284 template<class C, class R, class A0, class A1>
285 bool PushCallAndWaitResult(R (C::*fn)(A0, A1), R* ret,
286 typename SelfType<A0>::Type a0, typename SelfType<A1>::Type a1)
287 { return PushCommand(ThreadCommandMF2<C,R,A0,A1>(static_cast<C*>(this), fn, ret, a0, a1, true)); }
288 // Enqueue a member function call for class C and wait for the call to complete
289 // on consumer thread before returning.
290 template<class C, class R>
291 bool PushCallAndWaitResult(C* p, R (C::*fn)(), R* ret)
292 { return PushCommand(ThreadCommandMF0<C,R>(p, fn, ret, true)); }
293 template<class C, class R, class A0>
294 bool PushCallAndWaitResult(C* p, R (C::*fn)(A0), R* ret, typename SelfType<A0>::Type a0)
295 { return PushCommand(ThreadCommandMF1<C,R,A0>(p, fn, ret, a0, true)); }
296 template<class C, class R, class A0, class A1>
297 bool PushCallAndWaitResult(C* p, R (C::*fn)(A0, A1), R* ret,
298 typename SelfType<A0>::Type a0, typename SelfType<A1>::Type a1)
299 { return PushCommand(ThreadCommandMF2<C,R,A0,A1>(p, fn, ret, a0, a1, true)); }
301 private:
302 class ThreadCommandQueueImpl* pImpl;
303 };
306 }
308 #endif // OVR_ThreadCommandQueue_h