Leaked source code of windows server 2003
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.

478 lines
12 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1997.
  5. //
  6. // File: E V E N T Q . C P P
  7. //
  8. // Contents: Event Queue for managing synchonization of external events.
  9. //
  10. // Notes:
  11. //
  12. // Author: ckotze 29 Nov 2000
  13. //
  14. //----------------------------------------------------------------------------
  15. #include "pch.h"
  16. #pragma hdrstop
  17. #include "cmevent.h"
  18. #include "eventq.h"
  19. #include "ncmisc.h"
  20. #include "conman.h"
  21. #include "nceh.h"
  22. //+---------------------------------------------------------------------------
  23. //
  24. // Function: Constructor for CEventQueue
  25. //
  26. // Purpose: Creates the various synchronization objects required for the
  27. // Queue
  28. // Arguments:
  29. // HANDLE hServiceShutdown [in]
  30. // Event to set when shutting down queue.
  31. //
  32. //
  33. // Returns: nothing.
  34. //
  35. // Author: ckotze 30 Nov 2000
  36. //
  37. // Notes:
  38. //
  39. //
  40. //
  41. CEventQueue::CEventQueue(HANDLE hServiceShutdown) throw(HRESULT) :
  42. m_hServiceShutdown(0), m_pFireEvents(NULL), m_hWait(0), m_fRefreshAllInQueue(FALSE)
  43. {
  44. TraceFileFunc(ttidEvents);
  45. NTSTATUS Status;
  46. try
  47. {
  48. Status = DuplicateHandle(GetCurrentProcess(), hServiceShutdown, GetCurrentProcess(), &m_hServiceShutdown, NULL, FALSE, DUPLICATE_SAME_ACCESS);
  49. if (!Status)
  50. {
  51. TraceTag(ttidEvents, "Couldn't Duplicate handle!");
  52. throw HRESULT_FROM_WIN32(Status);
  53. }
  54. HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  55. m_pFireEvents = new CEvent(hEvent);
  56. if (!m_pFireEvents)
  57. {
  58. throw E_OUTOFMEMORY;
  59. }
  60. Status = RtlRegisterWait(&m_hWait, hEvent, (WAITORTIMERCALLBACKFUNC) DispatchEvents, NULL, INFINITE, WT_EXECUTEDEFAULT);
  61. if (!NT_SUCCESS(Status))
  62. {
  63. throw HRESULT_FROM_WIN32(Status);
  64. }
  65. TraceTag(ttidEvents, "RtlRegisterWait Succeeded");
  66. InitializeCriticalSection(&m_csQueue);
  67. }
  68. catch (HRESULT &hr)
  69. {
  70. TraceError("Out of memory", hr);
  71. if (m_hWait && NT_SUCCESS(Status))
  72. {
  73. RtlDeregisterWaitEx(m_hWait, INVALID_HANDLE_VALUE);
  74. }
  75. // ISSUE: If CreateEvent succeeds and new CEvent fails, we're not freeing the hEvent.
  76. if (m_pFireEvents)
  77. {
  78. delete m_pFireEvents;
  79. }
  80. if (m_hServiceShutdown)
  81. {
  82. CloseHandle(m_hServiceShutdown);
  83. }
  84. throw;
  85. }
  86. catch (SE_Exception &e)
  87. {
  88. TraceError("An exception occurred", HRESULT_FROM_WIN32(e.getSeNumber()) );
  89. if (m_hWait && NT_SUCCESS(Status))
  90. {
  91. RtlDeregisterWaitEx(m_hWait, INVALID_HANDLE_VALUE);
  92. }
  93. // ISSUE: If CreateEvent succeeds and new CEvent fails, we're not freeing the hEvent.
  94. if (m_pFireEvents)
  95. {
  96. delete m_pFireEvents;
  97. }
  98. if (m_hServiceShutdown)
  99. {
  100. CloseHandle(m_hServiceShutdown);
  101. }
  102. throw E_UNEXPECTED;
  103. }
  104. }
  105. //+---------------------------------------------------------------------------
  106. //
  107. // Function: Destructor for CEventQueue
  108. //
  109. // Purpose: Empties the queue and frees all existing items in the queue.
  110. //
  111. // Arguments:
  112. //
  113. //
  114. //
  115. //
  116. // Returns: nothing.
  117. //
  118. // Author: ckotze 30 Nov 2000
  119. //
  120. // Notes:
  121. //
  122. //
  123. //
  124. CEventQueue::~CEventQueue() throw()
  125. {
  126. TraceFileFunc(ttidEvents);
  127. NTSTATUS Status;
  128. // Blocks until all outstanding threads return.
  129. Status = RtlDeregisterWaitEx(m_hWait, INVALID_HANDLE_VALUE);
  130. TraceError("RtlDeregisterWaitEx", HRESULT_FROM_WIN32(Status));
  131. if (TryEnterCriticalSection(&m_csQueue))
  132. {
  133. // This is okay.
  134. LeaveCriticalSection(&m_csQueue);
  135. }
  136. else
  137. {
  138. AssertSz(FALSE, "Another thread is still holding onto this critical section. This is unexpected at this point.");
  139. }
  140. DeleteCriticalSection(&m_csQueue);
  141. while (!m_eqWorkItems.empty())
  142. {
  143. USERWORKITEM UserWorkItem;
  144. UserWorkItem = m_eqWorkItems.front();
  145. m_eqWorkItems.pop_front();
  146. if (UserWorkItem.EventMgr == EVENTMGR_CONMAN)
  147. {
  148. FreeConmanEvent(UserWorkItem.Event);
  149. }
  150. }
  151. delete m_pFireEvents;
  152. CloseHandle(m_hServiceShutdown);
  153. }
  154. //+---------------------------------------------------------------------------
  155. //
  156. // Function: EnqueueEvent
  157. //
  158. // Purpose: Stores the new event in the Event Queue
  159. //
  160. // Arguments:
  161. // Function - The pointer to the function to be called when firing the
  162. // event
  163. // pEvent - The Event information
  164. // EventMgr - Which event manager the event should go to.
  165. //
  166. // Returns: HRESULT
  167. // S_OK - Event has been added and Event code is
  168. // already dispatching events
  169. // S_FALSE - Event has been added to Queue, but a
  170. // thread needs to be scheduled to fire
  171. // the events
  172. // E_OUTOFMEMORY - Unable to add the event to the Queue.
  173. //
  174. // Author: ckotze 30 Nov 2000
  175. //
  176. // Notes: Locks and Unlocks the critical section only while working
  177. // with the queue
  178. //
  179. //
  180. HRESULT CEventQueue::EnqueueEvent(IN PCONMAN_EVENTTHREAD Function,
  181. IN TAKEOWNERSHIP CONMAN_EVENT* pEvent,
  182. IN const EVENT_MANAGER EventMgr)
  183. {
  184. TraceFileFunc(ttidEvents);
  185. CExceptionSafeLock esLock(&m_csQueue);
  186. USERWORKITEM UserWorkItem;
  187. HRESULT hr = S_OK;
  188. if (!Function)
  189. {
  190. return E_POINTER;
  191. }
  192. if (!pEvent)
  193. {
  194. return E_POINTER;
  195. }
  196. UserWorkItem.Function = Function;
  197. UserWorkItem.Event = pEvent;
  198. UserWorkItem.EventMgr = EventMgr;
  199. if (EVENTMGR_CONMAN == EventMgr)
  200. {
  201. if (REFRESH_ALL == pEvent->Type)
  202. {
  203. if (!m_fRefreshAllInQueue)
  204. {
  205. m_fRefreshAllInQueue = TRUE;
  206. }
  207. else
  208. {
  209. FreeConmanEvent(pEvent);
  210. return S_OK;
  211. }
  212. }
  213. }
  214. #ifdef DBG
  215. char pchErrorText[MAX_PATH];
  216. Assert(UserWorkItem.EventMgr);
  217. if (EVENTMGR_CONMAN == UserWorkItem.EventMgr)
  218. {
  219. TraceTag(ttidEvents, "EnqueueEvent received Event: %s (currently %d in queue). Event Manager: CONMAN", DbgEvents(pEvent->Type), m_eqWorkItems.size());
  220. sprintf(pchErrorText, "Invalid Type %d specified in Event structure\r\n", pEvent->Type);
  221. AssertSz(IsValidEventType(UserWorkItem.EventMgr, pEvent->Type), pchErrorText);
  222. }
  223. else
  224. {
  225. sprintf(pchErrorText, "Invalid Event Manager %d specified in Event structure\r\n", EventMgr);
  226. AssertSz(FALSE, pchErrorText);
  227. }
  228. #endif
  229. try
  230. {
  231. m_eqWorkItems.push_back(UserWorkItem);
  232. m_pFireEvents->SetEvent();
  233. }
  234. catch (bad_alloc)
  235. {
  236. hr = E_OUTOFMEMORY;
  237. }
  238. return hr;
  239. }
  240. //+---------------------------------------------------------------------------
  241. //
  242. // Function: DequeueEvent
  243. //
  244. // Purpose: Retrieves the next event in the Event Queue
  245. //
  246. // Arguments:
  247. // Function - The pointer to the function to be called when firing the
  248. // event
  249. // Event - The Event information. Free with delete
  250. // EventMgr - Which event manager the event should go to.
  251. //
  252. // Returns: HRESULT
  253. //
  254. // Author: ckotze 30 Nov 2000
  255. //
  256. // Notes: Locks and Unlocks the critical section only while working
  257. // with the queue
  258. //
  259. //
  260. HRESULT CEventQueue::DequeueEvent(OUT PCONMAN_EVENTTHREAD& Function,
  261. OUT TAKEOWNERSHIP CONMAN_EVENT*& pEvent,
  262. OUT EVENT_MANAGER& EventMgr)
  263. {
  264. TraceFileFunc(ttidEvents);
  265. CExceptionSafeLock esLock(&m_csQueue);
  266. USERWORKITEM UserWorkItem;
  267. DWORD dwSize = m_eqWorkItems.size();
  268. if (!dwSize)
  269. {
  270. AssertSz(FALSE, "Calling DequeueEvent with 0 items in Queue!!!");
  271. return E_UNEXPECTED;
  272. }
  273. UserWorkItem = m_eqWorkItems.front();
  274. m_eqWorkItems.pop_front();
  275. Function = UserWorkItem.Function;
  276. pEvent = UserWorkItem.Event;
  277. EventMgr = UserWorkItem.EventMgr;
  278. if (EVENTMGR_CONMAN == EventMgr)
  279. {
  280. if (REFRESH_ALL == pEvent->Type)
  281. {
  282. m_fRefreshAllInQueue = FALSE;
  283. }
  284. }
  285. #ifdef DBG
  286. char pchErrorText[MAX_PATH];
  287. Assert(EventMgr);
  288. if (EVENTMGR_CONMAN == EventMgr)
  289. {
  290. TraceTag(ttidEvents, "DequeueEvent retrieved Event: %s (%d left in queue). Event Manager: CONMAN", DbgEvents(pEvent->Type), m_eqWorkItems.size());
  291. sprintf(pchErrorText, "Invalid Type %d specified in Event structure\r\nItems in Queue: %d\r\n", pEvent->Type, dwSize);
  292. AssertSz(IsValidEventType(EventMgr, pEvent->Type), pchErrorText);
  293. }
  294. else
  295. {
  296. sprintf(pchErrorText, "Invalid Event Manager %d specified in Event structure\r\n", EventMgr);
  297. AssertSz(FALSE, pchErrorText);
  298. }
  299. #endif
  300. return S_OK;
  301. }
  302. //+---------------------------------------------------------------------------
  303. //
  304. // Function: WaitForExit
  305. //
  306. // Purpose: Waits for the queue to exit.
  307. //
  308. // Arguments:
  309. // (none)
  310. //
  311. // Returns: WAIT_OBJECT_0 or failure code.
  312. //
  313. // Author: ckotze 28 Apr 2001
  314. //
  315. // Notes:
  316. //
  317. //
  318. DWORD CEventQueue::WaitForExit() throw()
  319. {
  320. TraceFileFunc(ttidEvents);
  321. return WaitForSingleObject(m_hServiceShutdown, INFINITE);
  322. }
  323. //+---------------------------------------------------------------------------
  324. //
  325. // Function: size
  326. //
  327. // Purpose: Returns the Number of items in the queue
  328. //
  329. // Arguments:
  330. // (none)
  331. //
  332. // Returns: Number of items in the queue
  333. //
  334. // Author: ckotze 30 Nov 2000
  335. //
  336. // Notes:
  337. //
  338. //
  339. size_t CEventQueue::size() throw()
  340. {
  341. CExceptionSafeLock esLock(&m_csQueue);
  342. TraceFileFunc(ttidEvents);
  343. size_t tempsize;
  344. tempsize = m_eqWorkItems.size();
  345. return tempsize;
  346. }
  347. //+---------------------------------------------------------------------------
  348. //
  349. // Function: AtomCheckSizeAndResetEvent
  350. //
  351. // Purpose: Make sure we know when we're supposed to exit, lock during the
  352. // operation.
  353. // Arguments:
  354. // fDispatchEvents [in] Should be dispatching more events.
  355. //
  356. // Returns: TRUE if should exit thread. FALSE if more events in queue, or
  357. // service is not shutting down.
  358. // Author: ckotze 04 March 2001
  359. //
  360. // Notes:
  361. //
  362. //
  363. BOOL CEventQueue::AtomCheckSizeAndResetEvent(IN const BOOL fDispatchEvents) throw()
  364. {
  365. TraceFileFunc(ttidEvents);
  366. CExceptionSafeLock esLock(&m_csQueue);
  367. BOOL fRet = TRUE;
  368. TraceTag(ttidEvents, "Checking for Exit Conditions, Events in queue: %d, Service Shutting Down: %s", size(), (fDispatchEvents) ? "FALSE" : "TRUE");
  369. if (m_eqWorkItems.empty() || !fDispatchEvents)
  370. {
  371. fRet = FALSE;
  372. if (fDispatchEvents)
  373. {
  374. m_pFireEvents->ResetEvent();
  375. }
  376. else
  377. {
  378. SetEvent(m_hServiceShutdown);
  379. }
  380. }
  381. return fRet;
  382. }
  383. // CEvent is a Hybrid between Automatic and Manual reset events.
  384. // It is automatically reset, but we control when it is set so it
  385. // doesn't spawn threads while set, except for the first one.
  386. CEvent::CEvent(IN HANDLE hEvent) throw()
  387. {
  388. m_hEvent = hEvent;
  389. m_bSignaled = FALSE;
  390. }
  391. CEvent::~CEvent() throw()
  392. {
  393. CloseHandle(m_hEvent);
  394. }
  395. HRESULT CEvent::SetEvent()
  396. {
  397. HRESULT hr = S_OK;
  398. if (!m_bSignaled)
  399. {
  400. if (!::SetEvent(m_hEvent))
  401. {
  402. hr = HrFromLastWin32Error();
  403. }
  404. else
  405. {
  406. m_bSignaled = TRUE;
  407. }
  408. }
  409. return hr;
  410. }
  411. HRESULT CEvent::ResetEvent()
  412. {
  413. HRESULT hr = S_OK;
  414. Assert(m_bSignaled);
  415. m_bSignaled = FALSE;
  416. return hr;
  417. }