| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318 |
- /************************************************************************************
- PublicHeader: None
- Filename : OVR_ThreadCommandQueue.h
- Content : Command queue for operations executed on a thread
- Created : October 29, 2012
- Author : Michael Antonov
- Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved.
- Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License");
- you may not use the Oculus VR Rift SDK except in compliance with the License,
- which is provided at the time of installation or download, or which
- otherwise accompanies this software in either electronic or hard copy form.
- You may obtain a copy of the License at
- http://www.oculusvr.com/licenses/LICENSE-3.2
- Unless required by applicable law or agreed to in writing, the Oculus VR SDK
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- ************************************************************************************/
- #ifndef OVR_ThreadCommandQueue_h
- #define OVR_ThreadCommandQueue_h
- #include "OVR_Types.h"
- #include "OVR_List.h"
- #include "OVR_Atomic.h"
- #include "OVR_Threads.h"
- namespace OVR {
- class ThreadCommand;
- class ThreadCommandQueue;
- //-------------------------------------------------------------------------------------
- // ***** ThreadCommand
- // ThreadCommand is a base class implementation for commands stored in ThreadCommandQueue.
- class ThreadCommand
- {
- public:
- // NotifyEvent is used by ThreadCommandQueue::PushCallAndWait to notify the
- // calling (producer) thread when command is completed or queue slot is available.
- class NotifyEvent : public ListNode<NotifyEvent>, public NewOverrideBase
- {
- Event E;
- public:
- NotifyEvent() { }
- void Wait() { E.Wait(); }
- void PulseEvent() { E.PulseEvent(); }
- };
- // ThreadCommand::PopBuffer is temporary storage for a command popped off
- // by ThreadCommandQueue::PopCommand.
- class PopBuffer
- {
- enum { MaxSize = 256 };
- size_t Size;
- union {
- uint8_t Buffer[MaxSize];
- size_t Align;
- };
- ThreadCommand* toCommand() const { return (ThreadCommand*)Buffer; }
- public:
- PopBuffer() : Size(0) { }
- ~PopBuffer();
- void InitFromBuffer(void* data);
- bool HasCommand() const { return Size != 0; }
- size_t GetSize() const { return Size; }
- bool NeedsWait() const { return toCommand()->NeedsWait(); }
- NotifyEvent* GetEvent() const { return toCommand()->pEvent; }
- // Execute the command and also notifies caller to finish waiting,
- // if necessary.
- void Execute();
- };
-
- uint16_t Size;
- bool WaitFlag;
- bool ExitFlag; // Marks the last exit command.
- NotifyEvent* pEvent;
- ThreadCommand(size_t size, bool waitFlag, bool exitFlag = false)
- : Size((uint16_t)size), WaitFlag(waitFlag), ExitFlag(exitFlag), pEvent(0) { }
- virtual ~ThreadCommand() { }
- bool NeedsWait() const { return WaitFlag; }
- size_t GetSize() const { return Size; }
- virtual void Execute() const = 0;
- // Copy constructor used for serializing this to memory buffer.
- virtual ThreadCommand* CopyConstruct(void* p) const = 0;
- };
- //-------------------------------------------------------------------------------------
- // CleanType is a template that strips 'const' and '&' modifiers from the argument type;
- // for example, typename CleanType<A&>::Type is equivalent to A.
- template<class T> struct CleanType { typedef T Type; };
- template<class T> struct CleanType<T&> { typedef T Type; };
- template<class T> struct CleanType<const T> { typedef T Type; };
- template<class T> struct CleanType<const T&> { typedef T Type; };
- // SelfType is a template that yields the argument type. This helps avoid conflicts with
- // automatic template argument deduction for function calls when identical argument
- // is already defined.
- template<class T> struct SelfType { typedef T Type; };
- //-------------------------------------------------------------------------------------
- // ThreadCommand specializations for member functions with different number of
- // arguments and argument types.
- // Used to return nothing from a ThreadCommand, to avoid problems with 'void'.
- struct Void
- {
- Void() {}
- Void(int) {}
- };
- // ThreadCommand for member function with 0 arguments.
- template<class C, class R>
- class ThreadCommandMF0 : public ThreadCommand
- {
- typedef R (C::*FnPtr)();
- C* pClass;
- FnPtr pFn;
- R* pRet;
- void executeImpl() const
- {
- pRet ? (void)(*pRet = (pClass->*pFn)()) :
- (void)(pClass->*pFn)();
- }
- public:
- ThreadCommandMF0(C* pclass, FnPtr fn, R* ret, bool needsWait)
- : ThreadCommand(sizeof(ThreadCommandMF0), needsWait),
- pClass(pclass), pFn(fn), pRet(ret) { }
- virtual void Execute() const { executeImpl(); }
- virtual ThreadCommand* CopyConstruct(void* p) const
- { return Construct<ThreadCommandMF0>(p, *this); }
- };
- // ThreadCommand for member function with 1 argument.
- template<class C, class R, class A0>
- class ThreadCommandMF1 : public ThreadCommand
- {
- typedef R (C::*FnPtr)(A0);
- C* pClass;
- FnPtr pFn;
- R* pRet;
- typename CleanType<A0>::Type AVal0;
- void executeImpl() const
- {
- pRet ? (void)(*pRet = (pClass->*pFn)(AVal0)) :
- (void)(pClass->*pFn)(AVal0);
- }
- public:
- ThreadCommandMF1(C* pclass, FnPtr fn, R* ret, A0 a0, bool needsWait)
- : ThreadCommand(sizeof(ThreadCommandMF1), needsWait),
- pClass(pclass), pFn(fn), pRet(ret), AVal0(a0) { }
- virtual void Execute() const { executeImpl(); }
- virtual ThreadCommand* CopyConstruct(void* p) const
- { return Construct<ThreadCommandMF1>(p, *this); }
- };
- // ThreadCommand for member function with 2 arguments.
- template<class C, class R, class A0, class A1>
- class ThreadCommandMF2 : public ThreadCommand
- {
- typedef R (C::*FnPtr)(A0, A1);
- C* pClass;
- FnPtr pFn;
- R* pRet;
- typename CleanType<A0>::Type AVal0;
- typename CleanType<A1>::Type AVal1;
- void executeImpl() const
- {
- pRet ? (void)(*pRet = (pClass->*pFn)(AVal0, AVal1)) :
- (void)(pClass->*pFn)(AVal0, AVal1);
- }
- public:
- ThreadCommandMF2(C* pclass, FnPtr fn, R* ret, A0 a0, A1 a1, bool needsWait)
- : ThreadCommand(sizeof(ThreadCommandMF2), needsWait),
- pClass(pclass), pFn(fn), pRet(ret), AVal0(a0), AVal1(a1) { }
-
- virtual void Execute() const { executeImpl(); }
- virtual ThreadCommand* CopyConstruct(void* p) const
- { return Construct<ThreadCommandMF2>(p, *this); }
- };
- //-------------------------------------------------------------------------------------
- // ***** ThreadCommandQueue
- // ThreadCommandQueue is a queue of executable function-call commands intended to be
- // serviced by a single consumer thread. Commands are added to the queue with PushCall
- // and removed with PopCall; they are processed in FIFO order. Multiple producer threads
- // are supported and will be blocked if internal data buffer is full.
- class ThreadCommandQueue
- {
- public:
- ThreadCommandQueue();
- virtual ~ThreadCommandQueue();
- // Pops the next command from the thread queue, if any is available.
- // The command should be executed by calling popBuffer->Execute().
- // Returns 'false' if no command is available at the time of the call.
- bool PopCommand(ThreadCommand::PopBuffer* popBuffer);
- // Generic implementaion of PushCommand; enqueues a command for execution.
- // Returns 'false' if push failed, usually indicating thread shutdown.
- bool PushCommand(const ThreadCommand& command);
- //
- void PushExitCommand(bool wait);
- // Returns 'true' once ExitCommand has been processed, so the thread can shut down.
- bool IsExiting() const;
- // These two virtual functions serve as notifications for derived
- // thread waiting.
- virtual void OnPushNonEmpty_Locked() { }
- virtual void OnPopEmpty_Locked() { }
- // *** PushCall with no result
-
- // Enqueue a member function of 'this' class to be called on consumer thread.
- // By default the function returns immediately; set 'wait' argument to 'true' to
- // wait for completion.
- template<class C, class R>
- bool PushCall(R (C::*fn)(), bool wait = false)
- { return PushCommand(ThreadCommandMF0<C,R>(static_cast<C*>(this), fn, 0, wait)); }
- template<class C, class R, class A0>
- bool PushCall(R (C::*fn)(A0), typename SelfType<A0>::Type a0, bool wait = false)
- { return PushCommand(ThreadCommandMF1<C,R,A0>(static_cast<C*>(this), fn, 0, a0, wait)); }
- template<class C, class R, class A0, class A1>
- bool PushCall(R (C::*fn)(A0, A1),
- typename SelfType<A0>::Type a0, typename SelfType<A1>::Type a1, bool wait = false)
- { return PushCommand(ThreadCommandMF2<C,R,A0,A1>(static_cast<C*>(this), fn, 0, a0, a1, wait)); }
- // Enqueue a specified member function call of class C.
- // By default the function returns immediately; set 'wait' argument to 'true' to
- // wait for completion.
- template<class C, class R>
- bool PushCall(C* p, R (C::*fn)(), bool wait = false)
- { return PushCommand(ThreadCommandMF0<C,R>(p, fn, 0, wait)); }
- template<class C, class R, class A0>
- bool PushCall(C* p, R (C::*fn)(A0), typename SelfType<A0>::Type a0, bool wait = false)
- { return PushCommand(ThreadCommandMF1<C,R,A0>(p, fn, 0, a0, wait)); }
- template<class C, class R, class A0, class A1>
- bool PushCall(C* p, R (C::*fn)(A0, A1),
- typename SelfType<A0>::Type a0, typename SelfType<A1>::Type a1, bool wait = false)
- { return PushCommand(ThreadCommandMF2<C,R,A0,A1>(p, fn, 0, a0, a1, wait)); }
-
-
- // *** PushCall with Result
- // Enqueue a member function of 'this' class call and wait for call to complete
- // on consumer thread before returning.
- template<class C, class R>
- bool PushCallAndWaitResult(R (C::*fn)(), R* ret)
- { return PushCommand(ThreadCommandMF0<C,R>(static_cast<C*>(this), fn, ret, true)); }
- template<class C, class R, class A0>
- bool PushCallAndWaitResult(R (C::*fn)(A0), R* ret, typename SelfType<A0>::Type a0)
- { return PushCommand(ThreadCommandMF1<C,R,A0>(static_cast<C*>(this), fn, ret, a0, true)); }
- template<class C, class R, class A0, class A1>
- bool PushCallAndWaitResult(R (C::*fn)(A0, A1), R* ret,
- typename SelfType<A0>::Type a0, typename SelfType<A1>::Type a1)
- { return PushCommand(ThreadCommandMF2<C,R,A0,A1>(static_cast<C*>(this), fn, ret, a0, a1, true)); }
- // Enqueue a member function call for class C and wait for the call to complete
- // on consumer thread before returning.
- template<class C, class R>
- bool PushCallAndWaitResult(C* p, R (C::*fn)(), R* ret)
- { return PushCommand(ThreadCommandMF0<C,R>(p, fn, ret, true)); }
- template<class C, class R, class A0>
- bool PushCallAndWaitResult(C* p, R (C::*fn)(A0), R* ret, typename SelfType<A0>::Type a0)
- { return PushCommand(ThreadCommandMF1<C,R,A0>(p, fn, ret, a0, true)); }
- template<class C, class R, class A0, class A1>
- bool PushCallAndWaitResult(C* p, R (C::*fn)(A0, A1), R* ret,
- typename SelfType<A0>::Type a0, typename SelfType<A1>::Type a1)
- { return PushCommand(ThreadCommandMF2<C,R,A0,A1>(p, fn, ret, a0, a1, true)); }
- private:
- class ThreadCommandQueueImpl* pImpl;
- };
- } // namespace OVR
- #endif // OVR_ThreadCommandQueue_h
|