OVR_ThreadCommandQueue.h
Go to the documentation of this file.
00001 /************************************************************************************
00002 
00003 PublicHeader:   None
00004 Filename    :   OVR_ThreadCommandQueue.h
00005 Content     :   Command queue for operations executed on a thread
00006 Created     :   October 29, 2012
00007 Author      :   Michael Antonov
00008 
00009 Copyright   :   Copyright 2012 Oculus VR, Inc. All Rights reserved.
00010 
00011 Use of this software is subject to the terms of the Oculus license
00012 agreement provided at the time of installation or download, or which
00013 otherwise accompanies this software in either electronic or hard copy form.
00014 
00015 ************************************************************************************/
00016 
00017 #ifndef OVR_ThreadCommandQueue_h
00018 #define OVR_ThreadCommandQueue_h
00019 
00020 #include "Kernel/OVR_Types.h"
00021 #include "Kernel/OVR_List.h"
00022 #include "Kernel/OVR_Atomic.h"
00023 #include "Kernel/OVR_Threads.h"
00024 
00025 namespace OVR {
00026 
00027 class ThreadCommand;
00028 class ThreadCommandQueue;
00029 
00030 
00031 //-------------------------------------------------------------------------------------
00032 // ***** ThreadCommand
00033 
00034 // ThreadCommand is a base class implementation for commands stored in ThreadCommandQueue.
00035 class ThreadCommand
00036 {
00037 public:    
00038 
00039     // NotifyEvent is used by ThreadCommandQueue::PushCallAndWait to notify the
00040     // calling (producer)  thread when command is completed or queue slot is available.
00041     class NotifyEvent : public ListNode<NotifyEvent>, public NewOverrideBase
00042     {
00043         Event E;
00044     public:   
00045         NotifyEvent() { }
00046 
00047         void Wait()        { E.Wait(); }
00048         void PulseEvent()  { E.PulseEvent(); }
00049     };
00050 
00051     // ThreadCommand::PopBuffer is temporary storage for a command popped off
00052     // by ThreadCommandQueue::PopCommand. 
00053     class PopBuffer
00054     {
00055         enum { MaxSize = 256 };
00056 
00057         UPInt Size;
00058         union {            
00059             UByte Buffer[MaxSize];
00060             UPInt Align;
00061         };
00062 
00063         ThreadCommand* toCommand() const { return (ThreadCommand*)Buffer; }
00064 
00065     public:
00066         PopBuffer() : Size(0) { }
00067         ~PopBuffer();
00068 
00069         void        InitFromBuffer(void* data);
00070 
00071         bool        HasCommand() const  { return Size != 0; }
00072         UPInt       GetSize() const     { return Size; }
00073         bool        NeedsWait() const   { return toCommand()->NeedsWait(); }
00074         NotifyEvent* GetEvent() const   { return toCommand()->pEvent; }
00075 
00076         // Execute the command and also notifies caller to finish waiting,
00077         // if necessary.
00078         void        Execute();
00079     };
00080     
00081     UInt16       Size;
00082     bool         WaitFlag; 
00083     bool         ExitFlag; // Marks the last exit command. 
00084     NotifyEvent* pEvent;
00085 
00086     ThreadCommand(UPInt size, bool waitFlag, bool exitFlag = false)
00087         : Size((UInt16)size), WaitFlag(waitFlag), ExitFlag(exitFlag), pEvent(0) { }
00088     virtual ~ThreadCommand() { }
00089 
00090     bool          NeedsWait() const { return WaitFlag; }
00091     UPInt         GetSize() const   { return Size; }
00092 
00093     virtual void            Execute() const = 0;
00094     // Copy constructor used for serializing this to memory buffer.
00095     virtual ThreadCommand*  CopyConstruct(void* p) const = 0;
00096 };
00097 
00098 
00099 //-------------------------------------------------------------------------------------
00100 
00101 // CleanType is a template that strips 'const' and '&' modifiers from the argument type;
00102 // for example, typename CleanType<A&>::Type is equivalent to A.
00103 template<class T> struct CleanType           { typedef T Type; };
00104 template<class T> struct CleanType<T&>       { typedef T Type; };
00105 template<class T> struct CleanType<const T>  { typedef T Type; };
00106 template<class T> struct CleanType<const T&> { typedef T Type; };
00107 
00108 // SelfType is a template that yields the argument type. This helps avoid conflicts with
00109 // automatic template argument deduction for function calls when identical argument
00110 // is already defined.
00111 template<class T> struct SelfType { typedef T Type; };
00112 
00113 
00114 
00115 //-------------------------------------------------------------------------------------
00116 // ThreadCommand specializations for member functions with different number of
00117 // arguments and argument types.
00118 
00119 // Used to return nothing from a ThreadCommand, to avoid problems with 'void'.
00120 struct Void
00121 {
00122     Void() {}
00123     Void(int) {}
00124 };
00125 
00126 // ThreadCommand for member function with 0 arguments.
00127 template<class C, class R>
00128 class ThreadCommandMF0 : public ThreadCommand
00129 {   
00130     typedef R (C::*FnPtr)();
00131     C*      pClass;
00132     FnPtr   pFn;
00133     R*      pRet;
00134 
00135     void executeImpl() const
00136     {
00137         pRet ? (void)(*pRet = (pClass->*pFn)()) :
00138                    (void)(pClass->*pFn)();
00139     }
00140 
00141 public:    
00142     ThreadCommandMF0(C* pclass, FnPtr fn, R* ret, bool needsWait)
00143         : ThreadCommand(sizeof(ThreadCommandMF0), needsWait),
00144           pClass(pclass), pFn(fn), pRet(ret) { }
00145 
00146     virtual void           Execute() const { executeImpl(); }
00147     virtual ThreadCommand* CopyConstruct(void* p) const
00148     { return Construct<ThreadCommandMF0>(p, *this); }
00149 };
00150 
00151 
00152 // ThreadCommand for member function with 1 argument.
00153 template<class C, class R, class A0>
00154 class ThreadCommandMF1 : public ThreadCommand
00155 {   
00156     typedef R (C::*FnPtr)(A0);
00157     C*                           pClass;
00158     FnPtr                        pFn;
00159     R*                           pRet;
00160     typename CleanType<A0>::Type AVal0;
00161 
00162     void executeImpl() const
00163     {
00164       pRet ? (void)(*pRet = (pClass->*pFn)(AVal0)) :
00165                  (void)(pClass->*pFn)(AVal0);
00166     }
00167 
00168 public:    
00169     ThreadCommandMF1(C* pclass, FnPtr fn, R* ret, A0 a0, bool needsWait)
00170         : ThreadCommand(sizeof(ThreadCommandMF1), needsWait),
00171           pClass(pclass), pFn(fn), pRet(ret), AVal0(a0) { }
00172 
00173     virtual void           Execute() const { executeImpl(); }
00174     virtual ThreadCommand* CopyConstruct(void* p) const
00175     { return Construct<ThreadCommandMF1>(p, *this); }
00176 };
00177 
00178 // ThreadCommand for member function with 2 arguments.
00179 template<class C, class R, class A0, class A1>
00180 class ThreadCommandMF2 : public ThreadCommand
00181 {   
00182     typedef R (C::*FnPtr)(A0, A1);
00183     C*                            pClass;
00184     FnPtr                         pFn;
00185     R*                            pRet;
00186     typename CleanType<A0>::Type  AVal0;
00187     typename CleanType<A1>::Type  AVal1;
00188 
00189     void executeImpl() const
00190     {
00191         pRet ? (void)(*pRet = (pClass->*pFn)(AVal0, AVal1)) :
00192                    (void)(pClass->*pFn)(AVal0, AVal1);
00193     }
00194 
00195 public:    
00196     ThreadCommandMF2(C* pclass, FnPtr fn, R* ret, A0 a0, A1 a1, bool needsWait)
00197         : ThreadCommand(sizeof(ThreadCommandMF2), needsWait),
00198           pClass(pclass), pFn(fn), pRet(ret), AVal0(a0), AVal1(a1) { }
00199     
00200     virtual void           Execute() const { executeImpl(); }
00201     virtual ThreadCommand* CopyConstruct(void* p) const 
00202     { return Construct<ThreadCommandMF2>(p, *this); }
00203 };
00204 
00205 
00206 //-------------------------------------------------------------------------------------
00207 // ***** ThreadCommandQueue
00208 
00209 // ThreadCommandQueue is a queue of executable function-call commands intended to be
00210 // serviced by a single consumer thread. Commands are added to the queue with PushCall
00211 // and removed with PopCall; they are processed in FIFO order. Multiple producer threads
00212 // are supported and will be blocked if internal data buffer is full.
00213 
00214 class ThreadCommandQueue
00215 {
00216 public:
00217 
00218     ThreadCommandQueue();
00219     virtual ~ThreadCommandQueue();
00220 
00221 
00222     // Pops the next command from the thread queue, if any is available.
00223     // The command should be executed by calling popBuffer->Execute().
00224     // Returns 'false' if no command is available at the time of the call.
00225     bool PopCommand(ThreadCommand::PopBuffer* popBuffer);
00226 
00227     // Generic implementaion of PushCommand; enqueues a command for execution.
00228     // Returns 'false' if push failed, usually indicating thread shutdown.
00229     bool PushCommand(const ThreadCommand& command);
00230 
00231     // 
00232     void PushExitCommand(bool wait);
00233 
00234     // Returns 'true' once ExitCommand has been processed, so the thread can shut down.
00235     bool IsExiting() const;
00236 
00237 
00238     // These two virtual functions serve as notifications for derived
00239     // thread waiting.    
00240     virtual void OnPushNonEmpty_Locked() { }
00241     virtual void OnPopEmpty_Locked()     { }
00242 
00243 
00244     // *** PushCall with no result
00245     
00246     // Enqueue a member function of 'this' class to be called on consumer thread.
00247     // By default the function returns immediately; set 'wait' argument to 'true' to
00248     // wait for completion.
00249     template<class C, class R>
00250     bool PushCall(R (C::*fn)(), bool wait = false)
00251     { return PushCommand(ThreadCommandMF0<C,R>(static_cast<C*>(this), fn, 0, wait)); }       
00252     template<class C, class R, class A0>
00253     bool PushCall(R (C::*fn)(A0), typename SelfType<A0>::Type a0, bool wait = false)
00254     { return PushCommand(ThreadCommandMF1<C,R,A0>(static_cast<C*>(this), fn, 0, a0, wait)); }
00255     template<class C, class R, class A0, class A1>
00256     bool PushCall(R (C::*fn)(A0, A1),
00257                   typename SelfType<A0>::Type a0, typename SelfType<A1>::Type a1, bool wait = false)
00258     { return PushCommand(ThreadCommandMF2<C,R,A0,A1>(static_cast<C*>(this), fn, 0, a0, a1, wait)); }
00259     // Enqueue a specified member function call of class C.
00260     // By default the function returns immediately; set 'wait' argument to 'true' to
00261     // wait for completion.
00262     template<class C, class R>
00263     bool PushCall(C* p, R (C::*fn)(), bool wait = false)
00264     { return PushCommand(ThreadCommandMF0<C,R>(p, fn, 0, wait)); }
00265     template<class C, class R, class A0>
00266     bool PushCall(C* p, R (C::*fn)(A0), typename SelfType<A0>::Type a0, bool wait = false)
00267     { return PushCommand(ThreadCommandMF1<C,R,A0>(p, fn, 0, a0, wait)); }
00268     template<class C, class R, class A0, class A1>
00269     bool PushCall(C* p, R (C::*fn)(A0, A1),
00270                   typename SelfType<A0>::Type a0, typename SelfType<A1>::Type a1, bool wait = false)
00271     { return PushCommand(ThreadCommandMF2<C,R,A0,A1>(p, fn, 0, a0, a1, wait)); }
00272     
00273     
00274     // *** PushCall with Result
00275 
00276     // Enqueue a member function of 'this' class call and wait for call to complete
00277     // on consumer thread before returning.
00278     template<class C, class R>
00279     bool PushCallAndWaitResult(R (C::*fn)(), R* ret)
00280     { return PushCommand(ThreadCommandMF0<C,R>(static_cast<C*>(this), fn, ret, true)); }       
00281     template<class C, class R, class A0>
00282     bool PushCallAndWaitResult(R (C::*fn)(A0), R* ret, typename SelfType<A0>::Type a0)
00283     { return PushCommand(ThreadCommandMF1<C,R,A0>(static_cast<C*>(this), fn, ret, a0, true)); }
00284     template<class C, class R, class A0, class A1>
00285     bool PushCallAndWaitResult(R (C::*fn)(A0, A1), R* ret,
00286                                typename SelfType<A0>::Type a0, typename SelfType<A1>::Type a1)
00287     { return PushCommand(ThreadCommandMF2<C,R,A0,A1>(static_cast<C*>(this), fn, ret, a0, a1, true)); }
00288     // Enqueue a member function call for class C and wait for the call to complete
00289     // on consumer thread before returning.
00290     template<class C, class R>
00291     bool PushCallAndWaitResult(C* p, R (C::*fn)(), R* ret)
00292     { return PushCommand(ThreadCommandMF0<C,R>(p, fn, ret, true)); }
00293     template<class C, class R, class A0>
00294     bool PushCallAndWaitResult(C* p, R (C::*fn)(A0), R* ret, typename SelfType<A0>::Type a0)
00295     { return PushCommand(ThreadCommandMF1<C,R,A0>(p, fn, ret, a0, true)); }
00296     template<class C, class R, class A0, class A1>
00297     bool PushCallAndWaitResult(C* p, R (C::*fn)(A0, A1), R* ret,
00298                                typename SelfType<A0>::Type a0, typename SelfType<A1>::Type a1)
00299     { return PushCommand(ThreadCommandMF2<C,R,A0,A1>(p, fn, ret, a0, a1, true)); }
00300 
00301 private:
00302     class ThreadCommandQueueImpl* pImpl;
00303 };
00304 
00305 
00306 }
00307 
00308 #endif // OVR_ThreadCommandQueue_h


oculus_sdk
Author(s): Tully Foote
autogenerated on Thu Jun 6 2019 20:13:48