Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

244 lines
6.8 KiB

  1. //========== Copyright � 2006, Valve Corporation, All rights reserved. ========
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #ifndef CALLQUEUE_H
  7. #define CALLQUEUE_H
  8. #include "tier0/tslist.h"
  9. #include "functors.h"
  10. #include "vstdlib/jobthread.h"
  11. #if defined( _WIN32 )
  12. #pragma once
  13. #endif
  14. //-----------------------------------------------------
  15. // Avert thy eyes! Imagine rather:
  16. //
  17. // void QueueCall( <function>, [args1, [arg2,]...]
  18. // void QueueCall( <object>, <function>, [args1, [arg2,]...]
  19. // void QueueRefCall( <object>, <<function>, [args1, [arg2,]...]
  20. //-----------------------------------------------------
  21. #define DEFINE_CALLQUEUE_NONMEMBER_QUEUE_CALL(N) \
  22. template <typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
  23. void QueueCall(FUNCTION_RETTYPE (*pfnProxied)( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \
  24. { \
  25. QueueFunctorInternal( CreateFunctor( pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ) ); \
  26. }
  27. //-------------------------------------
  28. #define DEFINE_CALLQUEUE_MEMBER_QUEUE_CALL(N) \
  29. template <typename OBJECT_TYPE_PTR, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
  30. void QueueCall(OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \
  31. { \
  32. QueueFunctorInternal( CreateFunctor( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ) ); \
  33. }
  34. //-------------------------------------
  35. #define DEFINE_CALLQUEUE_CONST_MEMBER_QUEUE_CALL(N) \
  36. template <typename OBJECT_TYPE_PTR, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
  37. void QueueCall(OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) const FUNC_ARG_FORMAL_PARAMS_##N ) \
  38. { \
  39. QueueFunctorInternal( CreateFunctor( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ) ); \
  40. }
  41. //-------------------------------------
  42. #define DEFINE_CALLQUEUE_REF_COUNTING_MEMBER_QUEUE_CALL(N) \
  43. template <typename OBJECT_TYPE_PTR, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
  44. void QueueRefCall(OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) FUNC_ARG_FORMAL_PARAMS_##N ) \
  45. { \
  46. QueueFunctorInternal( CreateRefCountingFunctor( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ) ); \
  47. }
  48. //-------------------------------------
  49. #define DEFINE_CALLQUEUE_REF_COUNTING_CONST_MEMBER_QUEUE_CALL(N) \
  50. template <typename OBJECT_TYPE_PTR, typename FUNCTION_CLASS, typename FUNCTION_RETTYPE FUNC_TEMPLATE_FUNC_PARAMS_##N FUNC_TEMPLATE_ARG_PARAMS_##N> \
  51. void QueueRefCall(OBJECT_TYPE_PTR pObject, FUNCTION_RETTYPE ( FUNCTION_CLASS::*pfnProxied )( FUNC_BASE_TEMPLATE_FUNC_PARAMS_##N ) const FUNC_ARG_FORMAL_PARAMS_##N ) \
  52. { \
  53. QueueFunctorInternal( CreateRefCountingFunctor( pObject, pfnProxied FUNC_FUNCTOR_CALL_ARGS_##N ) ); \
  54. \
  55. }
  56. #define FUNC_GENERATE_QUEUE_METHODS() \
  57. FUNC_GENERATE_ALL( DEFINE_CALLQUEUE_NONMEMBER_QUEUE_CALL ); \
  58. FUNC_GENERATE_ALL( DEFINE_CALLQUEUE_MEMBER_QUEUE_CALL ); \
  59. FUNC_GENERATE_ALL( DEFINE_CALLQUEUE_CONST_MEMBER_QUEUE_CALL );\
  60. FUNC_GENERATE_ALL( DEFINE_CALLQUEUE_REF_COUNTING_MEMBER_QUEUE_CALL ); \
  61. FUNC_GENERATE_ALL( DEFINE_CALLQUEUE_REF_COUNTING_CONST_MEMBER_QUEUE_CALL )
  62. //-----------------------------------------------------
  63. template <typename QUEUE_TYPE = CTSQueue<CFunctor *> >
  64. class CCallQueueT
  65. {
  66. public:
  67. CCallQueueT()
  68. : m_bNoQueue( false )
  69. {
  70. #ifdef _DEBUG
  71. m_nCurSerialNumber = 0;
  72. m_nBreakSerialNumber = (unsigned)-1;
  73. #endif
  74. }
  75. void DisableQueue( bool bDisable )
  76. {
  77. if ( m_bNoQueue == bDisable )
  78. {
  79. return;
  80. }
  81. if ( !m_bNoQueue )
  82. CallQueued();
  83. m_bNoQueue = bDisable;
  84. }
  85. bool IsDisabled() const
  86. {
  87. return m_bNoQueue;
  88. }
  89. int Count()
  90. {
  91. return m_queue.Count();
  92. }
  93. void CallQueued()
  94. {
  95. if ( !m_queue.Count() )
  96. {
  97. return;
  98. }
  99. m_queue.PushItem( NULL );
  100. CFunctor *pFunctor = NULL;
  101. while ( m_queue.PopItem( &pFunctor ) && pFunctor != NULL )
  102. {
  103. #ifdef _DEBUG
  104. if ( pFunctor->m_nUserID == m_nBreakSerialNumber)
  105. {
  106. m_nBreakSerialNumber = (unsigned)-1;
  107. }
  108. #endif
  109. (*pFunctor)();
  110. pFunctor->Release();
  111. }
  112. }
  113. void ParallelCallQueued( IThreadPool *pPool = NULL )
  114. {
  115. if ( ! pPool )
  116. {
  117. pPool = g_pThreadPool;
  118. }
  119. int nNumThreads = 1;
  120. if ( pPool )
  121. {
  122. nNumThreads = MIN( pPool->NumThreads(), MAX( 1, Count() ) );
  123. }
  124. if ( nNumThreads < 2 )
  125. {
  126. CallQueued();
  127. }
  128. else
  129. {
  130. int *pDummy = NULL;
  131. ParallelProcess( pPool, pDummy, nNumThreads, this, &CCallQueueT<>::ExecuteWrapper );
  132. }
  133. }
  134. void QueueFunctor( CFunctor *pFunctor )
  135. {
  136. Assert( pFunctor );
  137. QueueFunctorInternal( RetAddRef( pFunctor ) );
  138. }
  139. void Flush()
  140. {
  141. m_queue.PushItem( NULL );
  142. CFunctor *pFunctor;
  143. while ( m_queue.PopItem( &pFunctor ) && pFunctor != NULL )
  144. {
  145. pFunctor->Release();
  146. }
  147. }
  148. FUNC_GENERATE_QUEUE_METHODS();
  149. private:
  150. void ExecuteWrapper( int &nDummy ) // to match paralell process function template
  151. {
  152. CallQueued();
  153. }
  154. void QueueFunctorInternal( CFunctor *pFunctor )
  155. {
  156. if ( !m_bNoQueue )
  157. {
  158. #ifdef _DEBUG
  159. pFunctor->m_nUserID = m_nCurSerialNumber++;
  160. #endif
  161. m_queue.PushItem( pFunctor );
  162. }
  163. else
  164. {
  165. (*pFunctor)();
  166. pFunctor->Release();
  167. }
  168. }
  169. QUEUE_TYPE m_queue;
  170. bool m_bNoQueue;
  171. unsigned m_nCurSerialNumber;
  172. unsigned m_nBreakSerialNumber;
  173. };
  174. class CCallQueue : public CCallQueueT<>
  175. {
  176. };
  177. //-----------------------------------------------------
  178. // Optional interface that can be bound to concrete CCallQueue
  179. //-----------------------------------------------------
  180. class ICallQueue
  181. {
  182. public:
  183. void QueueFunctor( CFunctor *pFunctor )
  184. {
  185. // [mhansen] If we grab an extra reference here then this functor never gets released.
  186. // That usually isn't too bad because the memory the functor is allocated in is cleared and
  187. // reused every frame. But, if the functor contains a CUtlDataEnvelope with more than
  188. // 4 bytes of data it allocates its own memory and, in that case, we need the destructor to
  189. // be called to free it. So, we don't want to grab the "extra" reference here.
  190. // The net result should be that after this call the pFunctor has a ref count of 1 (which
  191. // is held by the functor it gets nested in, which is stuck in the call queue) and after it
  192. // is executed the owning functor is destructed which causes it to release the reference
  193. // and this functor is then freed. This happens in imatersysteminternal.h:112 where the
  194. // destructor is called explictly for the owning functor: pFunctor->~CFunctor();
  195. //QueueFunctorInternal( RetAddRef( pFunctor ) );
  196. QueueFunctorInternal( pFunctor );
  197. }
  198. FUNC_GENERATE_QUEUE_METHODS();
  199. private:
  200. virtual void QueueFunctorInternal( CFunctor *pFunctor ) = 0;
  201. };
  202. #endif // CALLQUEUE_H