Source code of Windows XP (NT5)
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.

410 lines
8.3 KiB

  1. /*
  2. Copyright (c) 1998-1999 Microsoft Corporation
  3. */
  4. #ifndef __MEDIA_STREAM_PUMP__
  5. #define __MEDIA_STREAM_PUMP__
  6. // atl fns
  7. #include <atlcom.h>
  8. // CTimerQueue
  9. #include "timerq.h"
  10. // we can wait for at most this many filters (per thread -- see CMediaPumpPool)
  11. // this limitation is imposed by WaitForMultipleObjects
  12. const DWORD MAX_FILTERS = MAXIMUM_WAIT_OBJECTS;
  13. // expandable array of scalar/pointer values
  14. template <class T>
  15. class CMyArray
  16. {
  17. public:
  18. CMyArray(
  19. IN DWORD BlockSize = 4
  20. )
  21. : m_pData(NULL),
  22. m_AllocElements(0),
  23. m_NumElements(0),
  24. m_BlockSize(BlockSize)
  25. {}
  26. virtual ~CMyArray()
  27. {
  28. if (NULL != m_pData) delete m_pData;
  29. }
  30. inline T *GetData()
  31. {
  32. return m_pData;
  33. }
  34. inline DWORD GetSize()
  35. {
  36. return m_NumElements;
  37. }
  38. HRESULT Add(
  39. IN T NewVal
  40. );
  41. inline T Get(
  42. IN DWORD Index
  43. );
  44. inline HRESULT Set(
  45. IN DWORD Index,
  46. IN T Val
  47. );
  48. inline BOOL Find(
  49. IN T Val,
  50. OUT DWORD &Index
  51. );
  52. HRESULT Remove(
  53. IN DWORD Index
  54. );
  55. inline HRESULT Remove(
  56. IN T Val
  57. );
  58. protected:
  59. T *m_pData;
  60. DWORD m_NumElements;
  61. DWORD m_AllocElements;
  62. DWORD m_BlockSize;
  63. };
  64. template <class T>
  65. HRESULT
  66. CMyArray<T>::Add(
  67. IN T NewVal
  68. )
  69. {
  70. // check if new memory needs to be allocated
  71. if ( m_AllocElements <= m_NumElements )
  72. {
  73. T *pData = new T[(m_NumElements+1) + m_BlockSize];
  74. BAIL_IF_NULL(pData, E_OUTOFMEMORY);
  75. if (NULL != m_pData)
  76. {
  77. CopyMemory(pData, m_pData, m_NumElements * sizeof(T));
  78. delete [] m_pData;
  79. }
  80. m_pData = pData;
  81. m_AllocElements = (m_NumElements+1) + m_BlockSize;
  82. }
  83. m_pData[m_NumElements] = NewVal;
  84. m_NumElements++;
  85. return S_OK;
  86. }
  87. template <class T>
  88. T
  89. CMyArray<T>::Get(
  90. IN DWORD Index
  91. )
  92. {
  93. TM_ASSERT(Index < m_NumElements);
  94. if (Index >= m_NumElements) return NULL;
  95. return m_pData[Index];
  96. }
  97. template <class T>
  98. HRESULT
  99. CMyArray<T>::Set(
  100. IN DWORD Index,
  101. IN T Val
  102. )
  103. {
  104. TM_ASSERT(Index < m_NumElements);
  105. if (Index >= m_NumElements) return E_INVALIDARG;
  106. m_pData[Index] = Val;
  107. return S_OK;
  108. }
  109. template <class T>
  110. HRESULT
  111. CMyArray<T>::Remove(
  112. IN DWORD Index
  113. )
  114. {
  115. TM_ASSERT(Index < m_NumElements);
  116. if (Index >= m_NumElements) return E_INVALIDARG;
  117. // copy all elements to the right of Index leftwards
  118. for(DWORD i=Index; i < (m_NumElements-1); i++)
  119. {
  120. m_pData[i] = m_pData[i+1];
  121. }
  122. // decrement the number of elements
  123. m_NumElements--;
  124. return S_OK;
  125. }
  126. template <class T>
  127. inline BOOL
  128. CMyArray<T>::Find(
  129. IN T Val,
  130. OUT DWORD &Index
  131. )
  132. {
  133. for(Index = 0; Index < m_NumElements; Index++)
  134. {
  135. if (Val == m_pData[Index]) return TRUE;
  136. }
  137. return FALSE;
  138. }
  139. template <class T>
  140. inline HRESULT
  141. CMyArray<T>::Remove(
  142. IN T Val
  143. )
  144. {
  145. DWORD Index;
  146. if ( Find(Val, Index) ) return Remove(Index);
  147. return E_FAIL;
  148. }
  149. class RELEASE_SEMAPHORE_ON_DEST
  150. {
  151. public:
  152. inline RELEASE_SEMAPHORE_ON_DEST(
  153. IN HANDLE hEvent
  154. )
  155. : m_hEvent(hEvent)
  156. {
  157. TM_ASSERT(NULL != m_hEvent);
  158. LOG((MSP_TRACE,
  159. "RELEASE_SEMAPHORE_ON_DEST::RELEASE_SEMAPHORE_ON_DEST[%p] - event[%p]", this, hEvent));
  160. }
  161. inline ~RELEASE_SEMAPHORE_ON_DEST()
  162. {
  163. if (NULL != m_hEvent)
  164. {
  165. LONG lDebug;
  166. ReleaseSemaphore(m_hEvent, 1, &lDebug);
  167. LOG((MSP_TRACE,
  168. "RELEASE_SEMAPHORE_ON_DEST::~RELEASE_SEMAPHORE_ON_DEST[%p] - released end semaphore[%p] -- old count was %ld",
  169. this, m_hEvent, lDebug));
  170. }
  171. }
  172. protected:
  173. HANDLE m_hEvent;
  174. };
  175. class CMediaTerminalFilter;
  176. class CFilterInfo;
  177. // implements single thread pump for the write media streaming terminal
  178. // filters. it creates a thread if necessary when a write terminal registers
  179. // itself (in commit). the filter signals its wait handle in decommit,
  180. // causing the thread to wake up and remove the filter from its data
  181. // structures. the thread returns when there are no more filters to service
  182. class CMediaPump
  183. {
  184. public:
  185. CMediaPump();
  186. virtual ~CMediaPump();
  187. // adds this filter to its wait array
  188. HRESULT Register(
  189. IN CMediaTerminalFilter *pFilter,
  190. IN HANDLE hWaitEvent
  191. );
  192. //
  193. // removes this filter from its wait array and timerq, and restarts sleep
  194. // with recalculated time
  195. //
  196. HRESULT UnRegister(
  197. IN HANDLE hWaitEvent // filter's event, used as filter id
  198. );
  199. // waits for filter events to be activated. also waits
  200. // for registration calls and timer events
  201. virtual HRESULT PumpMainLoop();
  202. int CountFilters();
  203. protected:
  204. typedef LOCAL_CRIT_LOCK<CComAutoCriticalSection> PUMP_LOCK;
  205. // thread pump - this is closed by the thread pump itself,
  206. // when the
  207. HANDLE m_hThread;
  208. // this event is used to signal the thread pump to exit the
  209. // critical section
  210. // all calls to Register first signal this event before trying
  211. // to acquire the critical section
  212. HANDLE m_hRegisterBeginSemaphore;
  213. // when a register call is in progress (m_hRegisterEvent was signaled)
  214. // the thread pump exits the critical section and blocks on this semaphore
  215. // the registering thread must release this semaphore if it signaled
  216. // m_hRegisterBeginSemaphore
  217. HANDLE m_hRegisterEndSemaphore;
  218. // regulates access to the member variables
  219. // the pump holds this during its wait and service actions
  220. // but releases it at the bottom of the loop
  221. CComAutoCriticalSection m_CritSec;
  222. // wait related members
  223. CMyArray<HANDLE> m_EventArray;
  224. CMyArray<CFilterInfo *> m_FilterInfoArray;
  225. CTimerQueue m_TimerQueue;
  226. HRESULT CreateThreadPump();
  227. void RemoveFilter(
  228. IN DWORD Index
  229. );
  230. void RemoveFilter(
  231. IN CFilterInfo *pFilterInfo
  232. );
  233. void ServiceFilter(
  234. IN CFilterInfo *pFilterInfo
  235. );
  236. void DestroyFilterInfoArray();
  237. };
  238. //////////////////////////////////////////////////////////////////////////////
  239. //
  240. // ZoltanS: non-optimal, but relatively painless way to get around scalability
  241. // limitation of 63 filters per pump thread. This class presents the same
  242. // external interface as the single thread pump, but creates as many pump
  243. // threads as are needed to serve the filters that are in use.
  244. //
  245. class CMediaPumpPool
  246. {
  247. public:
  248. CMediaPumpPool();
  249. ~CMediaPumpPool();
  250. HRESULT Register(
  251. IN CMediaTerminalFilter *pFilter,
  252. IN HANDLE hWaitEvent
  253. );
  254. HRESULT UnRegister(
  255. IN HANDLE hWaitEvent // filter's event, used as filter id
  256. );
  257. private:
  258. //
  259. // read optional user configuration from registry (only on the first call,
  260. // subsequent calls do nothing)
  261. //
  262. HRESULT ReadRegistryValuesIfNeeded();
  263. //
  264. // create new pumps, nPumpsToCreate is the number of new pumps to create
  265. //
  266. HRESULT CreatePumps(int nPumpsToCreate);
  267. //
  268. // calculate the optimal number of pumps needed to service the number of
  269. // filters that we have
  270. //
  271. HRESULT GetOptimalNumberOfPumps(OUT int *pNumberOfPumps);
  272. //
  273. // this method returns the pump to be used to service the new filter
  274. //
  275. HRESULT PickThePumpToUse(int *pnPumpToUse);
  276. //
  277. // utility function that calculates the number of filters per pump
  278. //
  279. inline DWORD GetMaxNumberOfFiltersPerPump()
  280. {
  281. //
  282. // check if the value is configured in the registry
  283. //
  284. ReadRegistryValuesIfNeeded();
  285. //
  286. // return the value -- it was either read from the registry on the
  287. // first call to GetMaxNumberOfFiltersPerPump, or using default
  288. //
  289. return m_dwMaxNumberOfFilterPerPump;
  290. }
  291. private:
  292. CMSPArray<CMediaPump *> m_aPumps;
  293. CMSPCritSection m_CritSection;
  294. //
  295. // the value that specifies the max number of filters to be serviced by one
  296. // pump
  297. //
  298. DWORD m_dwMaxNumberOfFilterPerPump;
  299. };
  300. #endif // __MEDIA_STREAM_PUMP__