ovr_sdk
diff LibOVR/Src/Kernel/OVR_ThreadCommandQueue.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 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/LibOVR/Src/Kernel/OVR_ThreadCommandQueue.h Wed Jan 14 06:51:16 2015 +0200 1.3 @@ -0,0 +1,318 @@ 1.4 +/************************************************************************************ 1.5 + 1.6 +PublicHeader: None 1.7 +Filename : OVR_ThreadCommandQueue.h 1.8 +Content : Command queue for operations executed on a thread 1.9 +Created : October 29, 2012 1.10 +Author : Michael Antonov 1.11 + 1.12 +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. 1.13 + 1.14 +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); 1.15 +you may not use the Oculus VR Rift SDK except in compliance with the License, 1.16 +which is provided at the time of installation or download, or which 1.17 +otherwise accompanies this software in either electronic or hard copy form. 1.18 + 1.19 +You may obtain a copy of the License at 1.20 + 1.21 +http://www.oculusvr.com/licenses/LICENSE-3.2 1.22 + 1.23 +Unless required by applicable law or agreed to in writing, the Oculus VR SDK 1.24 +distributed under the License is distributed on an "AS IS" BASIS, 1.25 +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1.26 +See the License for the specific language governing permissions and 1.27 +limitations under the License. 1.28 + 1.29 +************************************************************************************/ 1.30 + 1.31 +#ifndef OVR_ThreadCommandQueue_h 1.32 +#define OVR_ThreadCommandQueue_h 1.33 + 1.34 +#include "../Kernel/OVR_Types.h" 1.35 +#include "../Kernel/OVR_List.h" 1.36 +#include "../Kernel/OVR_Atomic.h" 1.37 +#include "../Kernel/OVR_Threads.h" 1.38 + 1.39 +namespace OVR { 1.40 + 1.41 +class ThreadCommand; 1.42 +class ThreadCommandQueue; 1.43 + 1.44 + 1.45 +//------------------------------------------------------------------------------------- 1.46 +// ***** ThreadCommand 1.47 + 1.48 +// ThreadCommand is a base class implementation for commands stored in ThreadCommandQueue. 1.49 +class ThreadCommand 1.50 +{ 1.51 +public: 1.52 + // NotifyEvent is used by ThreadCommandQueue::PushCallAndWait to notify the 1.53 + // calling (producer) thread when command is completed or queue slot is available. 1.54 + class NotifyEvent : public ListNode<NotifyEvent>, public NewOverrideBase 1.55 + { 1.56 + Event E; 1.57 + public: 1.58 + NotifyEvent() { } 1.59 + 1.60 + void Wait() { E.Wait(); } 1.61 + void PulseEvent() { E.PulseEvent(); } 1.62 + }; 1.63 + 1.64 + // ThreadCommand::PopBuffer is temporary storage for a command popped off 1.65 + // by ThreadCommandQueue::PopCommand. 1.66 + class PopBuffer 1.67 + { 1.68 + enum { MaxSize = 256 }; 1.69 + 1.70 + size_t Size; 1.71 + union { 1.72 + uint8_t Buffer[MaxSize]; 1.73 + size_t Align; 1.74 + }; 1.75 + 1.76 + ThreadCommand* toCommand() const { return (ThreadCommand*)Buffer; } 1.77 + 1.78 + public: 1.79 + PopBuffer() : Size(0) { } 1.80 + ~PopBuffer(); 1.81 + 1.82 + void InitFromBuffer(void* data); 1.83 + 1.84 + bool HasCommand() const { return Size != 0; } 1.85 + size_t GetSize() const { return Size; } 1.86 + bool NeedsWait() const { return toCommand()->NeedsWait(); } 1.87 + NotifyEvent* GetEvent() const { return toCommand()->pEvent; } 1.88 + 1.89 + // Execute the command and also notifies caller to finish waiting, 1.90 + // if necessary. 1.91 + void Execute(); 1.92 + }; 1.93 + 1.94 + uint16_t Size; 1.95 + bool WaitFlag; 1.96 + bool ExitFlag; // Marks the last exit command. 1.97 + NotifyEvent* pEvent; 1.98 + 1.99 + ThreadCommand(size_t size, bool waitFlag, bool exitFlag = false) 1.100 + : Size((uint16_t)size), WaitFlag(waitFlag), ExitFlag(exitFlag), pEvent(0) { } 1.101 + virtual ~ThreadCommand() { } 1.102 + 1.103 + bool NeedsWait() const { return WaitFlag; } 1.104 + size_t GetSize() const { return Size; } 1.105 + 1.106 + virtual void Execute() const = 0; 1.107 + // Copy constructor used for serializing this to memory buffer. 1.108 + virtual ThreadCommand* CopyConstruct(void* p) const = 0; 1.109 +}; 1.110 + 1.111 + 1.112 +//------------------------------------------------------------------------------------- 1.113 + 1.114 +// CleanType is a template that strips 'const' and '&' modifiers from the argument type; 1.115 +// for example, typename CleanType<A&>::Type is equivalent to A. 1.116 +template<class T> struct CleanType { typedef T Type; }; 1.117 +template<class T> struct CleanType<T&> { typedef T Type; }; 1.118 +template<class T> struct CleanType<const T> { typedef T Type; }; 1.119 +template<class T> struct CleanType<const T&> { typedef T Type; }; 1.120 + 1.121 +// SelfType is a template that yields the argument type. This helps avoid conflicts with 1.122 +// automatic template argument deduction for function calls when identical argument 1.123 +// is already defined. 1.124 +template<class T> struct SelfType { typedef T Type; }; 1.125 + 1.126 + 1.127 + 1.128 +//------------------------------------------------------------------------------------- 1.129 +// ThreadCommand specializations for member functions with different number of 1.130 +// arguments and argument types. 1.131 + 1.132 +// Used to return nothing from a ThreadCommand, to avoid problems with 'void'. 1.133 +struct Void 1.134 +{ 1.135 + Void() {} 1.136 + Void(int) {} 1.137 +}; 1.138 + 1.139 +// ThreadCommand for member function with 0 arguments. 1.140 +template<class C, class R> 1.141 +class ThreadCommandMF0 : public ThreadCommand 1.142 +{ 1.143 + typedef R (C::*FnPtr)(); 1.144 + C* pClass; 1.145 + FnPtr pFn; 1.146 + R* pRet; 1.147 + 1.148 + void executeImpl() const 1.149 + { 1.150 + pRet ? (void)(*pRet = (pClass->*pFn)()) : 1.151 + (void)(pClass->*pFn)(); 1.152 + } 1.153 + 1.154 +public: 1.155 + ThreadCommandMF0(C* pclass, FnPtr fn, R* ret, bool needsWait) 1.156 + : ThreadCommand(sizeof(ThreadCommandMF0), needsWait), 1.157 + pClass(pclass), pFn(fn), pRet(ret) { } 1.158 + 1.159 + virtual void Execute() const { executeImpl(); } 1.160 + virtual ThreadCommand* CopyConstruct(void* p) const 1.161 + { return Construct<ThreadCommandMF0>(p, *this); } 1.162 +}; 1.163 + 1.164 + 1.165 +// ThreadCommand for member function with 1 argument. 1.166 +template<class C, class R, class A0> 1.167 +class ThreadCommandMF1 : public ThreadCommand 1.168 +{ 1.169 + typedef R (C::*FnPtr)(A0); 1.170 + C* pClass; 1.171 + FnPtr pFn; 1.172 + R* pRet; 1.173 + typename CleanType<A0>::Type AVal0; 1.174 + 1.175 + void executeImpl() const 1.176 + { 1.177 + pRet ? (void)(*pRet = (pClass->*pFn)(AVal0)) : 1.178 + (void)(pClass->*pFn)(AVal0); 1.179 + } 1.180 + 1.181 +public: 1.182 + ThreadCommandMF1(C* pclass, FnPtr fn, R* ret, A0 a0, bool needsWait) 1.183 + : ThreadCommand(sizeof(ThreadCommandMF1), needsWait), 1.184 + pClass(pclass), pFn(fn), pRet(ret), AVal0(a0) { } 1.185 + 1.186 + virtual void Execute() const { executeImpl(); } 1.187 + virtual ThreadCommand* CopyConstruct(void* p) const 1.188 + { return Construct<ThreadCommandMF1>(p, *this); } 1.189 +}; 1.190 + 1.191 +// ThreadCommand for member function with 2 arguments. 1.192 +template<class C, class R, class A0, class A1> 1.193 +class ThreadCommandMF2 : public ThreadCommand 1.194 +{ 1.195 + typedef R (C::*FnPtr)(A0, A1); 1.196 + C* pClass; 1.197 + FnPtr pFn; 1.198 + R* pRet; 1.199 + typename CleanType<A0>::Type AVal0; 1.200 + typename CleanType<A1>::Type AVal1; 1.201 + 1.202 + void executeImpl() const 1.203 + { 1.204 + pRet ? (void)(*pRet = (pClass->*pFn)(AVal0, AVal1)) : 1.205 + (void)(pClass->*pFn)(AVal0, AVal1); 1.206 + } 1.207 + 1.208 +public: 1.209 + ThreadCommandMF2(C* pclass, FnPtr fn, R* ret, A0 a0, A1 a1, bool needsWait) 1.210 + : ThreadCommand(sizeof(ThreadCommandMF2), needsWait), 1.211 + pClass(pclass), pFn(fn), pRet(ret), AVal0(a0), AVal1(a1) { } 1.212 + 1.213 + virtual void Execute() const { executeImpl(); } 1.214 + virtual ThreadCommand* CopyConstruct(void* p) const 1.215 + { return Construct<ThreadCommandMF2>(p, *this); } 1.216 +}; 1.217 + 1.218 + 1.219 +//------------------------------------------------------------------------------------- 1.220 +// ***** ThreadCommandQueue 1.221 + 1.222 +// ThreadCommandQueue is a queue of executable function-call commands intended to be 1.223 +// serviced by a single consumer thread. Commands are added to the queue with PushCall 1.224 +// and removed with PopCall; they are processed in FIFO order. Multiple producer threads 1.225 +// are supported and will be blocked if internal data buffer is full. 1.226 + 1.227 +class ThreadCommandQueue 1.228 +{ 1.229 +public: 1.230 + 1.231 + ThreadCommandQueue(); 1.232 + virtual ~ThreadCommandQueue(); 1.233 + 1.234 + 1.235 + // Pops the next command from the thread queue, if any is available. 1.236 + // The command should be executed by calling popBuffer->Execute(). 1.237 + // Returns 'false' if no command is available at the time of the call. 1.238 + bool PopCommand(ThreadCommand::PopBuffer* popBuffer); 1.239 + 1.240 + // Generic implementaion of PushCommand; enqueues a command for execution. 1.241 + // Returns 'false' if push failed, usually indicating thread shutdown. 1.242 + bool PushCommand(const ThreadCommand& command); 1.243 + 1.244 + // 1.245 + void PushExitCommand(bool wait); 1.246 + 1.247 + // Returns 'true' once ExitCommand has been processed, so the thread can shut down. 1.248 + bool IsExiting() const; 1.249 + 1.250 + 1.251 + // These two virtual functions serve as notifications for derived 1.252 + // thread waiting. 1.253 + virtual void OnPushNonEmpty_Locked() { } 1.254 + virtual void OnPopEmpty_Locked() { } 1.255 + 1.256 + 1.257 + // *** PushCall with no result 1.258 + 1.259 + // Enqueue a member function of 'this' class to be called on consumer thread. 1.260 + // By default the function returns immediately; set 'wait' argument to 'true' to 1.261 + // wait for completion. 1.262 + template<class C, class R> 1.263 + bool PushCall(R (C::*fn)(), bool wait = false) 1.264 + { return PushCommand(ThreadCommandMF0<C,R>(static_cast<C*>(this), fn, 0, wait)); } 1.265 + template<class C, class R, class A0> 1.266 + bool PushCall(R (C::*fn)(A0), typename SelfType<A0>::Type a0, bool wait = false) 1.267 + { return PushCommand(ThreadCommandMF1<C,R,A0>(static_cast<C*>(this), fn, 0, a0, wait)); } 1.268 + template<class C, class R, class A0, class A1> 1.269 + bool PushCall(R (C::*fn)(A0, A1), 1.270 + typename SelfType<A0>::Type a0, typename SelfType<A1>::Type a1, bool wait = false) 1.271 + { return PushCommand(ThreadCommandMF2<C,R,A0,A1>(static_cast<C*>(this), fn, 0, a0, a1, wait)); } 1.272 + // Enqueue a specified member function call of class C. 1.273 + // By default the function returns immediately; set 'wait' argument to 'true' to 1.274 + // wait for completion. 1.275 + template<class C, class R> 1.276 + bool PushCall(C* p, R (C::*fn)(), bool wait = false) 1.277 + { return PushCommand(ThreadCommandMF0<C,R>(p, fn, 0, wait)); } 1.278 + template<class C, class R, class A0> 1.279 + bool PushCall(C* p, R (C::*fn)(A0), typename SelfType<A0>::Type a0, bool wait = false) 1.280 + { return PushCommand(ThreadCommandMF1<C,R,A0>(p, fn, 0, a0, wait)); } 1.281 + template<class C, class R, class A0, class A1> 1.282 + bool PushCall(C* p, R (C::*fn)(A0, A1), 1.283 + typename SelfType<A0>::Type a0, typename SelfType<A1>::Type a1, bool wait = false) 1.284 + { return PushCommand(ThreadCommandMF2<C,R,A0,A1>(p, fn, 0, a0, a1, wait)); } 1.285 + 1.286 + 1.287 + // *** PushCall with Result 1.288 + 1.289 + // Enqueue a member function of 'this' class call and wait for call to complete 1.290 + // on consumer thread before returning. 1.291 + template<class C, class R> 1.292 + bool PushCallAndWaitResult(R (C::*fn)(), R* ret) 1.293 + { return PushCommand(ThreadCommandMF0<C,R>(static_cast<C*>(this), fn, ret, true)); } 1.294 + template<class C, class R, class A0> 1.295 + bool PushCallAndWaitResult(R (C::*fn)(A0), R* ret, typename SelfType<A0>::Type a0) 1.296 + { return PushCommand(ThreadCommandMF1<C,R,A0>(static_cast<C*>(this), fn, ret, a0, true)); } 1.297 + template<class C, class R, class A0, class A1> 1.298 + bool PushCallAndWaitResult(R (C::*fn)(A0, A1), R* ret, 1.299 + typename SelfType<A0>::Type a0, typename SelfType<A1>::Type a1) 1.300 + { return PushCommand(ThreadCommandMF2<C,R,A0,A1>(static_cast<C*>(this), fn, ret, a0, a1, true)); } 1.301 + // Enqueue a member function call for class C and wait for the call to complete 1.302 + // on consumer thread before returning. 1.303 + template<class C, class R> 1.304 + bool PushCallAndWaitResult(C* p, R (C::*fn)(), R* ret) 1.305 + { return PushCommand(ThreadCommandMF0<C,R>(p, fn, ret, true)); } 1.306 + template<class C, class R, class A0> 1.307 + bool PushCallAndWaitResult(C* p, R (C::*fn)(A0), R* ret, typename SelfType<A0>::Type a0) 1.308 + { return PushCommand(ThreadCommandMF1<C,R,A0>(p, fn, ret, a0, true)); } 1.309 + template<class C, class R, class A0, class A1> 1.310 + bool PushCallAndWaitResult(C* p, R (C::*fn)(A0, A1), R* ret, 1.311 + typename SelfType<A0>::Type a0, typename SelfType<A1>::Type a1) 1.312 + { return PushCommand(ThreadCommandMF2<C,R,A0,A1>(p, fn, ret, a0, a1, true)); } 1.313 + 1.314 +private: 1.315 + class ThreadCommandQueueImpl* pImpl; 1.316 +}; 1.317 + 1.318 + 1.319 +} // namespace OVR 1.320 + 1.321 +#endif // OVR_ThreadCommandQueue_h