OVR_CallbacksInternal.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. /************************************************************************************
  2. PublicHeader: Kernel
  3. Filename : OVR_CallbacksInternal.h
  4. Content : Callback library
  5. Created : Nov 11, 2014
  6. Author : Chris Taylor
  7. Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved.
  8. Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License");
  9. you may not use the Oculus VR Rift SDK except in compliance with the License,
  10. which is provided at the time of installation or download, or which
  11. otherwise accompanies this software in either electronic or hard copy form.
  12. You may obtain a copy of the License at
  13. http://www.oculusvr.com/licenses/LICENSE-3.2
  14. Unless required by applicable law or agreed to in writing, the Oculus VR SDK
  15. distributed under the License is distributed on an "AS IS" BASIS,
  16. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17. See the License for the specific language governing permissions and
  18. limitations under the License.
  19. ************************************************************************************/
  20. #ifndef OVR_CallbacksInternal_h
  21. #define OVR_CallbacksInternal_h
  22. #include "OVR_Atomic.h"
  23. #include "OVR_RefCount.h"
  24. #include "OVR_Delegates.h"
  25. #include "OVR_Array.h"
  26. #if !defined(OVR_CC_MSVC) || (OVR_CC_VERSION > 1600) // Newer than VS2010
  27. #include <atomic>
  28. #endif
  29. namespace OVR {
  30. template<class DelegateT> class FloatingCallbackEmitter; // Floating emitter object
  31. template<class DelegateT> class CallbackEmitter;
  32. template<class DelegateT> class FloatingCallbackListener; // Floating listener object
  33. template<class DelegateT> class CallbackListener;
  34. //-----------------------------------------------------------------------------
  35. // FloatingCallbackEmitter
  36. //
  37. // The Call() function is not thread-safe.
  38. // TBD: Should we add a thread-safe Call() option to constructor?
  39. class CallbackEmitterBase
  40. {
  41. protected:
  42. static Lock* GetEmitterLock();
  43. };
  44. template<class DelegateT>
  45. class FloatingCallbackEmitter : public CallbackEmitterBase, public RefCountBase< FloatingCallbackEmitter<DelegateT> >
  46. {
  47. friend class CallbackEmitter<DelegateT>;
  48. FloatingCallbackEmitter() :
  49. IsShutdown(false),
  50. #if !defined(OVR_CC_MSVC) || (OVR_CC_VERSION > 1600) // Newer than VS2010
  51. ListenersExist(false),
  52. #endif
  53. DirtyListenersCache(0)
  54. {
  55. }
  56. public:
  57. typedef Array< Ptr< FloatingCallbackListener<DelegateT> > > ListenerPtrArray;
  58. ~FloatingCallbackEmitter()
  59. {
  60. OVR_ASSERT(Listeners.GetSizeI() == 0);
  61. // ListenersCache will be emptied here.
  62. }
  63. bool AddListener(FloatingCallbackListener<DelegateT>* listener);
  64. bool HasListeners() const
  65. {
  66. #if !defined(OVR_CC_MSVC) || (OVR_CC_VERSION > 1600) // Newer than VS2010
  67. return ListenersExist.load(std::memory_order_relaxed);
  68. #else
  69. // This code still has a data race
  70. return (Listeners.GetSizeI() > 0);
  71. #endif
  72. }
  73. void Shutdown();
  74. // Called from the listener object as it is transitioning to canceled state.
  75. // The listener's mutex is not held during this call.
  76. void OnListenerCancel(FloatingCallbackListener<DelegateT>* listener);
  77. public:
  78. void Call();
  79. template<class Param1>
  80. void Call(Param1* p1);
  81. template<class Param1>
  82. void Call(Param1& p1);
  83. template<class Param1, class Param2>
  84. void Call(Param1* p1, Param2* p2);
  85. template<class Param1, class Param2>
  86. void Call(Param1& p1, Param2& p2);
  87. template<class Param1, class Param2, class Param3>
  88. void Call(Param1* p1, Param2* p2, Param3* p3);
  89. template<class Param1, class Param2, class Param3>
  90. void Call(Param1& p1, Param2& p2, Param3& p3);
  91. protected:
  92. // Is the emitter shut down? This prevents more listeners from being added during shutdown.
  93. bool IsShutdown;
  94. // Array of added listeners.
  95. ListenerPtrArray Listeners;
  96. #if !defined(OVR_CC_MSVC) || (OVR_CC_VERSION > 1600) // Newer than VS2010
  97. std::atomic<bool> ListenersExist;
  98. #endif
  99. // Is the cache dirty? This avoids locking and memory allocation in steady state.
  100. AtomicInt<uint32_t> DirtyListenersCache;
  101. // Cache of listeners used by the Call() function.
  102. ListenerPtrArray ListenersCacheForCalls;
  103. // Update the ListenersCache array in response to an insertion or removal.
  104. // This is how AddListener() insertions get rolled into the listeners array.
  105. // This is how RemoveListener() removals get purged from the cache.
  106. void updateListenersCache()
  107. {
  108. if (DirtyListenersCache != 0)
  109. {
  110. Lock::Locker locker(GetEmitterLock());
  111. // TBD: Should memory allocation be further reduced here?
  112. ListenersCacheForCalls = Listeners;
  113. DirtyListenersCache = 0;
  114. }
  115. }
  116. // Without holding a lock, find and remove the given listener from the array of listeners.
  117. void noLockFindAndRemoveListener(FloatingCallbackListener<DelegateT>* listener)
  118. {
  119. const int count = Listeners.GetSizeI();
  120. for (int i = 0; i < count; ++i)
  121. {
  122. if (Listeners[i] == listener)
  123. {
  124. Listeners.RemoveAt(i);
  125. // After removing it from the array, set the dirty flag.
  126. // Note: Because the flag is atomic, a portable memory fence is implied.
  127. DirtyListenersCache = 1;
  128. break;
  129. }
  130. }
  131. #if !defined(OVR_CC_MSVC) || (OVR_CC_VERSION > 1600) // Newer than VS2010
  132. if (Listeners.GetSizeI() < 1)
  133. {
  134. ListenersExist.store(false, std::memory_order_relaxed);
  135. }
  136. #endif
  137. }
  138. };
  139. //-----------------------------------------------------------------------------
  140. // FloatingCallbackListener
  141. //
  142. // Internal implementation class for the CallbackListener.
  143. // This can only be associated with one CallbackListener object for its lifetime.
  144. template<class DelegateT>
  145. class FloatingCallbackListener : public RefCountBase< FloatingCallbackListener<DelegateT> >
  146. {
  147. public:
  148. FloatingCallbackListener(DelegateT handler);
  149. ~FloatingCallbackListener();
  150. void EnterCancelState();
  151. bool IsValid() const
  152. {
  153. return Handler.IsValid();
  154. }
  155. // TBD: Should these be binned to reduce the lock count?
  156. // Boost does not do that. And I am worried about deadlocks when misused.
  157. mutable Lock ListenerLock;
  158. // Handler function
  159. DelegateT Handler;
  160. };
  161. //-----------------------------------------------------------------------------
  162. // Template Implementation: FloatingCallbackEmitter
  163. template<class DelegateT>
  164. bool FloatingCallbackEmitter<DelegateT>::AddListener(FloatingCallbackListener<DelegateT>* listener)
  165. {
  166. Lock::Locker locker(GetEmitterLock());
  167. if (IsShutdown)
  168. {
  169. return false;
  170. }
  171. // Add the listener to our list
  172. Listeners.PushBack(listener);
  173. // After adding it to the array, set the dirty flag.
  174. // Note: Because the flag is atomic, a portable memory fence is implied.
  175. DirtyListenersCache = 1;
  176. #if !defined(OVR_CC_MSVC) || (OVR_CC_VERSION > 1600) // Newer than VS2010
  177. ListenersExist.store(true, std::memory_order_relaxed);
  178. #endif
  179. return true;
  180. }
  181. // Called from the listener object as it is transitioning to canceled state.
  182. // The listener's mutex is not held during this call.
  183. template<class DelegateT>
  184. void FloatingCallbackEmitter<DelegateT>::OnListenerCancel(FloatingCallbackListener<DelegateT>* listener)
  185. {
  186. Lock::Locker locker(GetEmitterLock());
  187. // If not shut down,
  188. // Note that if it is shut down then there will be no listeners in the array.
  189. if (!IsShutdown)
  190. {
  191. // Remove it.
  192. noLockFindAndRemoveListener(listener);
  193. }
  194. }
  195. template<class DelegateT>
  196. void FloatingCallbackEmitter<DelegateT>::Shutdown()
  197. {
  198. Lock::Locker locker(GetEmitterLock());
  199. IsShutdown = true;
  200. Listeners.ClearAndRelease();
  201. // Note: Because the flag is atomic, a portable memory fence is implied.
  202. DirtyListenersCache = 1;
  203. #if !defined(OVR_CC_MSVC) || (OVR_CC_VERSION > 1600) // Newer than VS2010
  204. ListenersExist.store(false, std::memory_order_relaxed);
  205. #endif
  206. }
  207. //-----------------------------------------------------------------------------
  208. // Call function
  209. //
  210. // (1) Update the cache of listener references, if it has changed.
  211. // (2) For each listener,
  212. // (a) Hold ListenerLock.
  213. // (b) If listener handler is valid, call the handler.
  214. #define OVR_EMITTER_CALL_BODY(params) \
  215. updateListenersCache(); \
  216. if (IsShutdown) return; /* Pure optimization. It is fine if this races. */ \
  217. const int count = ListenersCacheForCalls.GetSizeI(); \
  218. for (int i = 0; i < count; ++i) \
  219. { \
  220. Lock::Locker locker(&ListenersCacheForCalls[i]->ListenerLock); \
  221. if (ListenersCacheForCalls[i]->Handler.IsValid()) \
  222. { \
  223. ListenersCacheForCalls[i]->Handler params; /* Using a macro for this line. */ \
  224. } \
  225. }
  226. template<class DelegateT>
  227. void FloatingCallbackEmitter<DelegateT>::Call()
  228. {
  229. OVR_EMITTER_CALL_BODY(())
  230. }
  231. template<class DelegateT>
  232. template<class Param1>
  233. void FloatingCallbackEmitter<DelegateT>::Call(Param1* p1)
  234. {
  235. OVR_EMITTER_CALL_BODY((p1))
  236. }
  237. template<class DelegateT>
  238. template<class Param1>
  239. void FloatingCallbackEmitter<DelegateT>::Call(Param1& p1)
  240. {
  241. OVR_EMITTER_CALL_BODY((p1))
  242. }
  243. template<class DelegateT>
  244. template<class Param1, class Param2>
  245. void FloatingCallbackEmitter<DelegateT>::Call(Param1* p1, Param2* p2)
  246. {
  247. OVR_EMITTER_CALL_BODY((p1, p2))
  248. }
  249. template<class DelegateT>
  250. template<class Param1, class Param2>
  251. void FloatingCallbackEmitter<DelegateT>::Call(Param1& p1, Param2& p2)
  252. {
  253. OVR_EMITTER_CALL_BODY((p1, p2))
  254. }
  255. template<class DelegateT>
  256. template<class Param1, class Param2, class Param3>
  257. void FloatingCallbackEmitter<DelegateT>::Call(Param1* p1, Param2* p2, Param3* p3)
  258. {
  259. OVR_EMITTER_CALL_BODY((p1, p2, p3))
  260. }
  261. template<class DelegateT>
  262. template<class Param1, class Param2, class Param3>
  263. void FloatingCallbackEmitter<DelegateT>::Call(Param1& p1, Param2& p2, Param3& p3)
  264. {
  265. OVR_EMITTER_CALL_BODY((p1, p2, p3))
  266. }
  267. #undef OVR_EMITTER_CALL_BODY
  268. //-----------------------------------------------------------------------------
  269. // Template Implementation: FloatingCallbackListener
  270. template<class DelegateT>
  271. FloatingCallbackListener<DelegateT>::FloatingCallbackListener(DelegateT handler) :
  272. Handler(handler)
  273. {
  274. OVR_ASSERT(Handler.IsValid());
  275. }
  276. template<class DelegateT>
  277. FloatingCallbackListener<DelegateT>::~FloatingCallbackListener()
  278. {
  279. OVR_ASSERT(!Handler.IsValid());
  280. }
  281. template<class DelegateT>
  282. void FloatingCallbackListener<DelegateT>::EnterCancelState()
  283. {
  284. ListenerLock.DoLock();
  285. Handler.Invalidate();
  286. ListenerLock.Unlock();
  287. }
  288. } // namespace OVR
  289. #endif // OVR_CallbacksInternal_h