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.

506 lines
11 KiB

  1. /*++
  2. Copyright (c) 1998-1999 Microsoft Corporation
  3. Module Name:
  4. DTEvntSk.cpp
  5. Abstract:
  6. This module contains implementation of CPTEventSink.
  7. Author:
  8. vlade Nov 1999
  9. --*/
  10. #include "precomp.h"
  11. #pragma hdrstop
  12. CPTEventSink::CPTEventSink() :
  13. m_pMSPStream(NULL)
  14. {
  15. LOG((MSP_TRACE, "CPTEventSink::CPTEventSink enter"));
  16. LOG((MSP_TRACE, "CPTEventSink::CPTEventSink exit"));
  17. }
  18. CPTEventSink::~CPTEventSink()
  19. {
  20. LOG((MSP_TRACE, "CPTEventSink::~CPTEventSink enter"));
  21. LOG((MSP_TRACE, "CPTEventSink::~CPTEventSink exit"));
  22. };
  23. // --- ITPluggableTerminalEventSnk ---
  24. /*++
  25. FireEvent
  26. Parameters:
  27. IN MSPEVENTITEM * pEventItem pointer to the structure that describes the
  28. event. all the pointers contained in the structure must be addreffed by
  29. the caller, and then released by the caller if FireEvent fails
  30. FireEvent makes a (shallow) copy of the structure, so the caller can
  31. delete the structure when the function returns
  32. Returns:
  33. S_OK - every thing was OK
  34. E_FAIL & other - something was wrong
  35. Description:
  36. This method is called by the dynamic terminals to
  37. signal a new event
  38. --*/
  39. STDMETHODIMP CPTEventSink::FireEvent(
  40. IN const MSP_EVENT_INFO * pEventInfo
  41. )
  42. {
  43. LOG((MSP_TRACE, "CPTEventSink::FireEvent enter"));
  44. //
  45. // make sure we got a good mspeventitem structure
  46. //
  47. if( MSPB_IsBadWritePtr( (void*)pEventInfo, sizeof( MSP_EVENT_INFO )))
  48. {
  49. LOG((MSP_ERROR, "CPTEventSink::FireEvent -"
  50. "pEventItem is bad, returns E_POINTER"));
  51. return E_POINTER;
  52. }
  53. //
  54. // Create an MSPEVENTITEM
  55. //
  56. MSPEVENTITEM *pEventItem = AllocateEventItem();
  57. if (NULL == pEventItem)
  58. {
  59. LOG((MSP_ERROR, "CPTEventSink::FireEvent -"
  60. "failed to create MSPEVENTITEM. returning E_OUTOFMEMORY "));
  61. return E_OUTOFMEMORY;
  62. }
  63. //
  64. // make a shallow copy of the structure
  65. //
  66. pEventItem->MSPEventInfo = *pEventInfo;
  67. Lock();
  68. HRESULT hr = E_FAIL;
  69. if (NULL != m_pMSPStream)
  70. {
  71. //
  72. // nicely ask stream to process our event
  73. //
  74. LOG((MSP_TRACE, "CPTEventSink::FireEvent - passing event [%p] to the stream", pEventItem));
  75. AsyncEventStruct *pAsyncEvent = new AsyncEventStruct;
  76. if (NULL == pAsyncEvent)
  77. {
  78. LOG((MSP_ERROR,
  79. "CPTEventSink::FireEvent - failed to allocate memory for AsyncEventStruct"));
  80. hr = E_OUTOFMEMORY;
  81. }
  82. else
  83. {
  84. //
  85. // stuff the structure with the addref'fed stream on which the
  86. // event will be fired and the actual event to fire
  87. //
  88. ULONG ulRC = m_pMSPStream->AddRef();
  89. if (1 == ulRC)
  90. {
  91. //
  92. // this is a workaround for a timing window: the stream could
  93. // be in its desctructor while we are doing the addref. this
  94. // condition is very-vary rare, as the timing window is very
  95. // narrow.
  96. //
  97. // the good thing is that stream destructor will not finish
  98. // while we are here, because it will try to get event sink's
  99. // critical section in its call to SetSinkStream() to set our
  100. // stream pointer to NULL.
  101. //
  102. // so if we detect that the refcount after our addref is 1,
  103. // that would mean that the stream is in (or is about to start
  104. // executing its desctructor). in which case we should do
  105. // nothing.
  106. //
  107. // cleanup and return a failure.
  108. //
  109. Unlock();
  110. LOG((MSP_ERROR,
  111. "CPTEventSink::FireEvent - stream is going away"));
  112. delete pAsyncEvent;
  113. pAsyncEvent = NULL;
  114. FreeEventItem(pEventItem);
  115. pEventItem = NULL;
  116. return TAPI_E_INVALIDSTREAM;
  117. }
  118. pAsyncEvent->pMSPStream = m_pMSPStream;
  119. pAsyncEvent->pEventItem = pEventItem;
  120. //
  121. // now use thread pool api to schedule the event for future async
  122. // processing
  123. //
  124. BOOL bQueueSuccess = QueueUserWorkItem(
  125. CPTEventSink::FireEventCallBack,
  126. (void *)pAsyncEvent,
  127. WT_EXECUTEDEFAULT);
  128. if (!bQueueSuccess)
  129. {
  130. DWORD dwLastError = GetLastError();
  131. LOG((MSP_ERROR,
  132. "CPTEventSink::FireEvent - QueueUserWorkItem failed. LastError = %ld", dwLastError));
  133. //
  134. // undo the addref we did on the stream object. the event will
  135. // be freed later
  136. //
  137. m_pMSPStream->Release();
  138. //
  139. // the event was not enqueued. delete now.
  140. //
  141. delete pAsyncEvent;
  142. pAsyncEvent = NULL;
  143. //
  144. // map the code and bail out
  145. //
  146. hr = HRESULT_FROM_WIN32(dwLastError);
  147. }
  148. else
  149. {
  150. //
  151. // log the event we have submitted, so we can match submission
  152. // with processing from the log
  153. //
  154. LOG((MSP_TRACE,
  155. "CPTEventSink::FireEvent - submitted event [%p]", pAsyncEvent));
  156. hr = S_OK;
  157. } // async event structure submitted
  158. } // async event structure allocated
  159. } // msp stream exists
  160. else
  161. {
  162. hr = TAPI_E_INVALIDSTREAM;
  163. LOG((MSP_ERROR,
  164. "CPTEventSink::FireEvent - stream pointer is NULL"));
  165. }
  166. Unlock();
  167. //
  168. // if we don't have a stream, or if the stream refused to process the
  169. // event, cleanup and return an error
  170. //
  171. if (FAILED(hr))
  172. {
  173. LOG((MSP_ERROR, "CPTEventSink::FireEvent - call to HandleStreamEvent failed. hr = 0x%08x", hr));
  174. FreeEventItem(pEventItem);
  175. return hr;
  176. }
  177. LOG((MSP_TRACE, "CPTEventSink::FireEvent - exit"));
  178. return S_OK;
  179. }
  180. /////////////////////////////////////////////////////////////////////////////
  181. //
  182. // CPTEventSink::FireEventCallBack
  183. //
  184. // the callback function that is called by thread pool api to asyncronously to
  185. // process events fired by the terminals.
  186. //
  187. // the argument should point to the structure that contains the pointer to the
  188. // stream on which to fire the event and the pointer to the event to fire.
  189. //
  190. // the dll is guaranteed to not go away, since the structure passed in holds a
  191. // reference to the stream object on which to process the event
  192. //
  193. // static
  194. DWORD WINAPI CPTEventSink::FireEventCallBack(LPVOID lpParameter)
  195. {
  196. LOG((MSP_TRACE, "CPTEventSink::FireEventCallBack - enter. Argument [%p]",
  197. lpParameter));
  198. AsyncEventStruct *pEventStruct = (AsyncEventStruct *)lpParameter;
  199. //
  200. // make sure the structure is valid
  201. //
  202. if (IsBadReadPtr(pEventStruct, sizeof(AsyncEventStruct)))
  203. {
  204. //
  205. // complain and exit. should not happen, unless there is a problem in
  206. // thread pool api or memory corruption
  207. //
  208. LOG((MSP_ERROR,
  209. "CPTEventSink::FireEventCallBack - Argument does not point to a valid AsyncEventStruct"));
  210. return FALSE;
  211. }
  212. BOOL bBadDataPassedIn = FALSE;
  213. //
  214. // the structure contains an addref'fed stream pointer. extract it and
  215. // make sure it is still valid
  216. //
  217. CMSPStream *pMSPStream = pEventStruct->pMSPStream;
  218. if (IsBadReadPtr(pMSPStream, sizeof(CMSPStream)))
  219. {
  220. //
  221. // should not happen, unless there is a problem in thread pool api or
  222. // memory corruption, or someone is over-releasing the stream object
  223. //
  224. LOG((MSP_ERROR,
  225. "CPTEventSink::FireEventCallBack - stream pointer is bad"));
  226. pMSPStream = NULL;
  227. bBadDataPassedIn = TRUE;
  228. }
  229. //
  230. // the structure contains the event that we are tryint to fire.
  231. // make sure the event we are about to fire is good.
  232. //
  233. MSPEVENTITEM *pEventItem = pEventStruct->pEventItem;
  234. if (IsBadReadPtr(pEventItem, sizeof(MSPEVENTITEM)))
  235. {
  236. //
  237. // should not happen, unless there is a problem in thread pool api or
  238. // memory corruption, or we didn't check success of allocation when we
  239. // created the event (which we did!)
  240. //
  241. LOG((MSP_ERROR,
  242. "CPTEventSink::FireEventCallBack - event is bad"));
  243. pEventItem = NULL;
  244. bBadDataPassedIn = TRUE;
  245. }
  246. //
  247. // bad stream or event structure?
  248. //
  249. if (bBadDataPassedIn)
  250. {
  251. //
  252. // release the event if it was good.
  253. //
  254. if ( NULL != pEventItem)
  255. {
  256. FreeEventItem(pEventItem);
  257. pEventItem = NULL;
  258. }
  259. //
  260. // release the stream if it was good.
  261. //
  262. if (NULL != pMSPStream)
  263. {
  264. pMSPStream->Release();
  265. pMSPStream = NULL;
  266. }
  267. //
  268. // no need to keep the event structure itself, delete it
  269. //
  270. delete pEventStruct;
  271. pEventStruct = NULL;
  272. return FALSE;
  273. }
  274. //
  275. // we have both the stream and the event, fire the event on the stream
  276. //
  277. HRESULT hr = pMSPStream->HandleSinkEvent(pEventItem);
  278. //
  279. // if HandleSinkEvent succeeded, pEventItem will be released by whoever
  280. // will handle the event, otherwise we need to release eventitem here
  281. //
  282. if (FAILED(hr))
  283. {
  284. LOG((MSP_ERROR,
  285. "CPTEventSink::FireEventCallBack - HandleSinkEvent not called or failed. hr = %lx",
  286. hr));
  287. FreeEventItem(pEventItem);
  288. pEventItem = NULL;
  289. }
  290. //
  291. // release the stream pointer that is a part of the structure --
  292. // we don't want any reference leaks.
  293. //
  294. //
  295. // note that the dll may go away at this point (if we are holding the last
  296. // reference to the last object from the dll)
  297. //
  298. pMSPStream->Release();
  299. pMSPStream = NULL;
  300. //
  301. // at this point we release the stream pointer and either submitted the
  302. // event or freed it. we no longer need the event structure.
  303. //
  304. delete pEventStruct;
  305. pEventStruct = NULL;
  306. LOG((MSP_(hr), "CPTEventSink::FireEventCallBack - exit. hr = %lx", hr));
  307. return SUCCEEDED(hr);
  308. }
  309. /*++
  310. SetSinkStream
  311. Parameters:
  312. CMSPStream *pStream
  313. the stream that will be processing our events, or NULL when no stream is
  314. available to process our events
  315. Returns:
  316. S_OK -
  317. Description:
  318. this method is called by the stream that is going to process our events
  319. when the stream is going away and is no longer available to process our
  320. messages, it will call SetSinkStream with NULL.
  321. --*/
  322. HRESULT CPTEventSink::SetSinkStream( CMSPStream *pStream )
  323. {
  324. LOG((MSP_TRACE, "CPTEventSink::SetSinkStream - enter"));
  325. Lock();
  326. LOG((MSP_TRACE,
  327. "CPTEventSink::SetSinkStream - replacing sink stream [%p] with [%p]",
  328. m_pMSPStream, pStream));
  329. //
  330. // we don't keep a reference to the stream -- the stream keeps a reference
  331. // to us. when the stream goes away, it will let us know.
  332. //
  333. m_pMSPStream = pStream;
  334. Unlock();
  335. LOG((MSP_TRACE, "CPTEventSink::SetSinkStream - exit"));
  336. return S_OK;
  337. }