summaryrefslogtreecommitdiffhomepage
path: root/ovr_sdk_win_23.0.0/LibOVRKernel/Src/Kernel/OVR_CallbacksInternal.h
diff options
context:
space:
mode:
Diffstat (limited to 'ovr_sdk_win_23.0.0/LibOVRKernel/Src/Kernel/OVR_CallbacksInternal.h')
-rw-r--r--ovr_sdk_win_23.0.0/LibOVRKernel/Src/Kernel/OVR_CallbacksInternal.h338
1 files changed, 338 insertions, 0 deletions
diff --git a/ovr_sdk_win_23.0.0/LibOVRKernel/Src/Kernel/OVR_CallbacksInternal.h b/ovr_sdk_win_23.0.0/LibOVRKernel/Src/Kernel/OVR_CallbacksInternal.h
new file mode 100644
index 0000000..bb45f55
--- /dev/null
+++ b/ovr_sdk_win_23.0.0/LibOVRKernel/Src/Kernel/OVR_CallbacksInternal.h
@@ -0,0 +1,338 @@
+/************************************************************************************
+
+PublicHeader: Kernel
+Filename : OVR_CallbacksInternal.h
+Content : Callback library
+Created : Nov 11, 2014
+Author : Chris Taylor
+
+Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved.
+
+Licensed under the Oculus Master SDK License Version 1.0 (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
+
+https://developer.oculus.com/licenses/oculusmastersdk-1.0
+
+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_CallbacksInternal_h
+#define OVR_CallbacksInternal_h
+
+#include "OVR_Array.h"
+#include "OVR_Atomic.h"
+#include "OVR_Delegates.h"
+#include "OVR_RefCount.h"
+
+#if !defined(OVR_CC_MSVC) || (OVR_CC_VERSION > 1600) // Newer than VS2010
+#include <atomic>
+#endif
+
+namespace OVR {
+
+template <class DelegateT>
+class FloatingCallbackEmitter; // Floating emitter object
+template <class DelegateT>
+class CallbackEmitter;
+template <class DelegateT>
+class FloatingCallbackListener; // Floating listener object
+template <class DelegateT>
+class CallbackListener;
+
+//-----------------------------------------------------------------------------
+// FloatingCallbackEmitter
+//
+// The Call() function is not thread-safe.
+// TBD: Should we add a thread-safe Call() option to constructor?
+
+class CallbackEmitterBase {
+ protected:
+ static Lock* GetEmitterLock();
+};
+
+template <class DelegateT>
+class FloatingCallbackEmitter : public CallbackEmitterBase,
+ public RefCountBase<FloatingCallbackEmitter<DelegateT>> {
+ friend class CallbackEmitter<DelegateT>;
+
+ FloatingCallbackEmitter()
+ : IsShutdown(false),
+#if !defined(OVR_CC_MSVC) || (OVR_CC_VERSION > 1600) // Newer than VS2010
+ ListenersExist(false),
+#endif
+ DirtyListenersCache(0) {
+ }
+
+ public:
+ typedef Array<Ptr<FloatingCallbackListener<DelegateT>>> ListenerPtrArray;
+
+ ~FloatingCallbackEmitter() {
+ OVR_ASSERT(Listeners.GetSizeI() == 0);
+ // ListenersCache will be emptied here.
+ }
+
+ bool AddListener(FloatingCallbackListener<DelegateT>* listener);
+ bool HasListeners() const {
+#if !defined(OVR_CC_MSVC) || (OVR_CC_VERSION > 1600) // Newer than VS2010
+ return ListenersExist.load(std::memory_order_relaxed);
+#else
+ // This code still has a data race
+ return (Listeners.GetSizeI() > 0);
+#endif
+ }
+ void Shutdown();
+
+ // Called from the listener object as it is transitioning to canceled state.
+ // The listener's mutex is not held during this call.
+ void OnListenerCancel(FloatingCallbackListener<DelegateT>* listener);
+
+ public:
+ void Call();
+
+ template <class Param1>
+ void Call(Param1* p1);
+
+ template <class Param1>
+ void Call(Param1& p1);
+
+ template <class Param1, class Param2>
+ void Call(Param1* p1, Param2* p2);
+
+ template <class Param1, class Param2>
+ void Call(Param1& p1, Param2& p2);
+
+ template <class Param1, class Param2, class Param3>
+ void Call(Param1* p1, Param2* p2, Param3* p3);
+
+ template <class Param1, class Param2, class Param3>
+ void Call(Param1& p1, Param2& p2, Param3& p3);
+
+ protected:
+ // Is the emitter shut down? This prevents more listeners from being added during shutdown.
+ bool IsShutdown;
+
+ // Array of added listeners.
+ ListenerPtrArray Listeners;
+
+#if !defined(OVR_CC_MSVC) || (OVR_CC_VERSION > 1600) // Newer than VS2010
+ std::atomic<bool> ListenersExist;
+#endif
+
+ // Is the cache dirty? This avoids locking and memory allocation in steady state.
+ std::atomic<uint32_t> DirtyListenersCache = {0};
+
+ // Cache of listeners used by the Call() function.
+ ListenerPtrArray ListenersCacheForCalls;
+
+ // Update the ListenersCache array in response to an insertion or removal.
+ // This is how AddListener() insertions get rolled into the listeners array.
+ // This is how RemoveListener() removals get purged from the cache.
+ void updateListenersCache() {
+ if (DirtyListenersCache != 0) {
+ Lock::Locker locker(GetEmitterLock());
+
+ // TBD: Should memory allocation be further reduced here?
+ ListenersCacheForCalls = Listeners;
+ DirtyListenersCache = 0;
+ }
+ }
+
+ // Without holding a lock, find and remove the given listener from the array of listeners.
+ void noLockFindAndRemoveListener(FloatingCallbackListener<DelegateT>* listener) {
+ const int count = Listeners.GetSizeI();
+ for (int i = 0; i < count; ++i) {
+ if (Listeners[i] == listener) {
+ Listeners.RemoveAt(i);
+
+ // After removing it from the array, set the dirty flag.
+ // Note: Because the flag is atomic, a portable memory fence is implied.
+ DirtyListenersCache = 1;
+
+ break;
+ }
+ }
+#if !defined(OVR_CC_MSVC) || (OVR_CC_VERSION > 1600) // Newer than VS2010
+ if (Listeners.GetSizeI() < 1) {
+ ListenersExist.store(false, std::memory_order_relaxed);
+ }
+#endif
+ }
+};
+
+//-----------------------------------------------------------------------------
+// FloatingCallbackListener
+//
+// Internal implementation class for the CallbackListener.
+// This can only be associated with one CallbackListener object for its lifetime.
+template <class DelegateT>
+class FloatingCallbackListener : public RefCountBase<FloatingCallbackListener<DelegateT>> {
+ public:
+ FloatingCallbackListener(DelegateT handler);
+ ~FloatingCallbackListener();
+
+ void EnterCancelState();
+
+ bool IsValid() const {
+ return Handler.IsValid();
+ }
+
+ // TBD: Should these be binned to reduce the lock count?
+ // Boost does not do that. And I am worried about deadlocks when misused.
+ mutable Lock ListenerLock;
+
+ // Handler function
+ DelegateT Handler;
+};
+
+//-----------------------------------------------------------------------------
+// Template Implementation: FloatingCallbackEmitter
+
+template <class DelegateT>
+bool FloatingCallbackEmitter<DelegateT>::AddListener(
+ FloatingCallbackListener<DelegateT>* listener) {
+ Lock::Locker locker(GetEmitterLock());
+
+ if (IsShutdown) {
+ return false;
+ }
+
+ // Add the listener to our list
+ Listeners.PushBack(listener);
+
+ // After adding it to the array, set the dirty flag.
+ // Note: Because the flag is atomic, a portable memory fence is implied.
+ DirtyListenersCache = 1;
+
+#if !defined(OVR_CC_MSVC) || (OVR_CC_VERSION > 1600) // Newer than VS2010
+ ListenersExist.store(true, std::memory_order_relaxed);
+#endif
+
+ return true;
+}
+
+// Called from the listener object as it is transitioning to canceled state.
+// The listener's mutex is not held during this call.
+template <class DelegateT>
+void FloatingCallbackEmitter<DelegateT>::OnListenerCancel(
+ FloatingCallbackListener<DelegateT>* listener) {
+ Lock::Locker locker(GetEmitterLock());
+
+ // If not shut down,
+ // Note that if it is shut down then there will be no listeners in the array.
+ if (!IsShutdown) {
+ // Remove it.
+ noLockFindAndRemoveListener(listener);
+ }
+}
+
+template <class DelegateT>
+void FloatingCallbackEmitter<DelegateT>::Shutdown() {
+ Lock::Locker locker(GetEmitterLock());
+
+ IsShutdown = true;
+
+ Listeners.ClearAndRelease();
+
+ // Note: Because the flag is atomic, a portable memory fence is implied.
+ DirtyListenersCache = 1;
+
+#if !defined(OVR_CC_MSVC) || (OVR_CC_VERSION > 1600) // Newer than VS2010
+ ListenersExist.store(false, std::memory_order_relaxed);
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Call function
+//
+// (1) Update the cache of listener references, if it has changed.
+// (2) For each listener,
+// (a) Hold ListenerLock.
+// (b) If listener handler is valid, call the handler.
+#define OVR_EMITTER_CALL_BODY(params) \
+ updateListenersCache(); \
+ if (IsShutdown) \
+ return; /* Pure optimization. It is fine if this races. */ \
+ const int count = ListenersCacheForCalls.GetSizeI(); \
+ for (int i = 0; i < count; ++i) { \
+ Lock::Locker locker(&ListenersCacheForCalls[i]->ListenerLock); \
+ if (ListenersCacheForCalls[i]->Handler.IsValid()) { \
+ ListenersCacheForCalls[i]->Handler params; /* Using a macro for this line. */ \
+ } \
+ }
+
+template <class DelegateT>
+void FloatingCallbackEmitter<DelegateT>::Call() {
+ OVR_EMITTER_CALL_BODY(())
+}
+
+template <class DelegateT>
+template <class Param1>
+void FloatingCallbackEmitter<DelegateT>::Call(Param1* p1) {
+ OVR_EMITTER_CALL_BODY((p1))
+}
+
+template <class DelegateT>
+template <class Param1>
+void FloatingCallbackEmitter<DelegateT>::Call(Param1& p1) {
+ OVR_EMITTER_CALL_BODY((p1))
+}
+
+template <class DelegateT>
+template <class Param1, class Param2>
+void FloatingCallbackEmitter<DelegateT>::Call(Param1* p1, Param2* p2) {
+ OVR_EMITTER_CALL_BODY((p1, p2))
+}
+
+template <class DelegateT>
+template <class Param1, class Param2>
+void FloatingCallbackEmitter<DelegateT>::Call(Param1& p1, Param2& p2) {
+ OVR_EMITTER_CALL_BODY((p1, p2))
+}
+
+template <class DelegateT>
+template <class Param1, class Param2, class Param3>
+void FloatingCallbackEmitter<DelegateT>::Call(Param1* p1, Param2* p2, Param3* p3) {
+ OVR_EMITTER_CALL_BODY((p1, p2, p3))
+}
+
+template <class DelegateT>
+template <class Param1, class Param2, class Param3>
+void FloatingCallbackEmitter<DelegateT>::Call(Param1& p1, Param2& p2, Param3& p3) {
+ OVR_EMITTER_CALL_BODY((p1, p2, p3))
+}
+
+#undef OVR_EMITTER_CALL_BODY
+
+//-----------------------------------------------------------------------------
+// Template Implementation: FloatingCallbackListener
+
+template <class DelegateT>
+FloatingCallbackListener<DelegateT>::FloatingCallbackListener(DelegateT handler)
+ : Handler(handler) {
+ OVR_ASSERT(Handler.IsValid());
+}
+
+template <class DelegateT>
+FloatingCallbackListener<DelegateT>::~FloatingCallbackListener() {
+ OVR_ASSERT(!Handler.IsValid());
+}
+
+template <class DelegateT>
+void FloatingCallbackListener<DelegateT>::EnterCancelState() {
+ ListenerLock.DoLock();
+ Handler.Invalidate();
+ ListenerLock.Unlock();
+}
+
+} // namespace OVR
+
+#endif // OVR_CallbacksInternal_h