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.

441 lines
13 KiB

  1. //-----------------------------------------------------------------------------
  2. //
  3. //
  4. // File: asncwrkq.cpp
  5. //
  6. // Description: Implementation of CAsyncWorkQueue.
  7. //
  8. // Author: Mike Swafford (MikeSwa)
  9. //
  10. // History:
  11. // 3/8/99 - MikeSwa Created
  12. //
  13. // Copyright (C) 1999 Microsoft Corporation
  14. //
  15. //-----------------------------------------------------------------------------
  16. #include "aqprecmp.h"
  17. #include "asncwrkq.h"
  18. #include "asyncq.inl"
  19. CPool CAsyncWorkQueueItem::s_CAsyncWorkQueueItemPool;
  20. DWORD CAsyncWorkQueueItem::s_cCurrentHeapAllocations = 0;
  21. DWORD CAsyncWorkQueueItem::s_cTotalHeapAllocations = 0;
  22. //---[ CAsyncWorkQueueItem::new ]----------------------------------------------
  23. //
  24. //
  25. // Description:
  26. // Wrapper for new that will use CPool or Exchmem to allocate...
  27. // whichever is appropriate.
  28. // Parameters:
  29. // size size of item to allocate (should always be
  30. // sizeof (CAsyncWorkQueueItem)
  31. // Returns:
  32. // Pointer to newly allocated CAsyncWorkQueueItem
  33. // History:
  34. // 7/8/99 - MikeSwa Created
  35. //
  36. //-----------------------------------------------------------------------------
  37. void * CAsyncWorkQueueItem::operator new(size_t size)
  38. {
  39. CAsyncWorkQueueItemAllocatorBlock *pcpaqwi = NULL;
  40. _ASSERT(sizeof(CAsyncWorkQueueItem) == size);
  41. pcpaqwi = (CAsyncWorkQueueItemAllocatorBlock *) s_CAsyncWorkQueueItemPool.Alloc();
  42. if (pcpaqwi)
  43. {
  44. pcpaqwi->m_dwSignature = ASYNC_WORK_QUEUE_ENTRY_ALLOC_CPOOL_SIG;
  45. }
  46. else
  47. {
  48. //Fallback on Exchmem
  49. pcpaqwi = (CAsyncWorkQueueItemAllocatorBlock *)
  50. pvMalloc(sizeof(CAsyncWorkQueueItemAllocatorBlock));
  51. if (pcpaqwi)
  52. {
  53. pcpaqwi->m_dwSignature = ASYNC_WORK_QUEUE_ENTRY_ALLOC_HEAP_SIG;
  54. DEBUG_DO_IT(InterlockedIncrement((PLONG) &s_cCurrentHeapAllocations));
  55. DEBUG_DO_IT(InterlockedIncrement((PLONG) &s_cTotalHeapAllocations));
  56. }
  57. }
  58. if (pcpaqwi)
  59. return ((void *) &(pcpaqwi->m_pawqi));
  60. else
  61. return NULL;
  62. }
  63. //---[ CAsyncWorkQueueItem::delete ]-------------------------------------------
  64. //
  65. //
  66. // Description:
  67. // Delete operator that will handle deleting via CPool or exchmem
  68. // Parameters:
  69. // pv Object to delete
  70. // size Size of object
  71. // Returns:
  72. // -
  73. // History:
  74. // 7/8/99 - MikeSwa Created
  75. //
  76. //-----------------------------------------------------------------------------
  77. void CAsyncWorkQueueItem::operator delete(void *pv, size_t size)
  78. {
  79. _ASSERT(sizeof(CAsyncWorkQueueItem) == size);
  80. _ASSERT(pv);
  81. CAsyncWorkQueueItemAllocatorBlock *pcpaqwi = CONTAINING_RECORD(pv,
  82. CAsyncWorkQueueItemAllocatorBlock, m_pawqi);
  83. DWORD dwOldSignature = pcpaqwi->m_dwSignature;
  84. _ASSERT(ASYNC_WORK_QUEUE_ENTRY_ALLOC_INVALID_SIG != dwOldSignature);
  85. //Reset signature before we free it, in case memory allocators
  86. //do not overwrite it (we want our asserts to fire at the time
  87. //of the double-free).
  88. pcpaqwi->m_dwSignature = ASYNC_WORK_QUEUE_ENTRY_ALLOC_INVALID_SIG;
  89. switch(dwOldSignature)
  90. {
  91. case ASYNC_WORK_QUEUE_ENTRY_ALLOC_CPOOL_SIG:
  92. s_CAsyncWorkQueueItemPool.Free(pcpaqwi);
  93. break;
  94. case ASYNC_WORK_QUEUE_ENTRY_ALLOC_HEAP_SIG:
  95. DEBUG_DO_IT(InterlockedDecrement((PLONG) &s_cCurrentHeapAllocations));
  96. FreePv(pcpaqwi);
  97. break;
  98. default:
  99. _ASSERT(0 && "Invalid signature when freeing CAsyncWorkQueueItem");
  100. }
  101. }
  102. //---[ CAsyncWorkQueueItem::CAsyncWorkQueueItem ]------------------------------
  103. //
  104. //
  105. // Description:
  106. // Default constructor for CAsyncWorkQueueItem
  107. // Parameters:
  108. // pvData Data to pass to completion function
  109. // pfnCompletion Completion function
  110. // Returns:
  111. // -
  112. // History:
  113. // 3/8/99 - MikeSwa Created
  114. //
  115. //-----------------------------------------------------------------------------
  116. CAsyncWorkQueueItem::CAsyncWorkQueueItem(PVOID pvData,
  117. PASYNC_WORK_QUEUE_FN pfnCompletion)
  118. {
  119. _ASSERT(pfnCompletion);
  120. m_dwSignature = ASYNC_WORK_QUEUE_ENTRY;
  121. m_pvData = pvData;
  122. m_pfnCompletion = pfnCompletion;
  123. }
  124. //---[ CAsyncWorkQueueItem::~CAsyncWorkQueueItem ]-----------------------------
  125. //
  126. //
  127. // Description:
  128. // Default destructor for CAsyncWorkQueueItem
  129. // Parameters:
  130. // -
  131. // Returns:
  132. // -
  133. // History:
  134. // 3/8/99 - MikeSwa Created
  135. //
  136. //-----------------------------------------------------------------------------
  137. CAsyncWorkQueueItem::~CAsyncWorkQueueItem()
  138. {
  139. m_dwSignature = ASYNC_WORK_QUEUE_ENTRY_FREE;
  140. }
  141. //---[ CAsyncWorkQueue::CAsyncWorkQueue ]--------------------------------------
  142. //
  143. //
  144. // Description:
  145. // Default constructor for CAsyncWorkQueue
  146. // Parameters:
  147. // -
  148. // Returns:
  149. // -
  150. // History:
  151. // 3/8/99 - MikeSwa Created
  152. //
  153. //-----------------------------------------------------------------------------
  154. CAsyncWorkQueue::CAsyncWorkQueue()
  155. {
  156. m_dwSignature = ASYNC_WORK_QUEUE_SIG;
  157. m_cWorkQueueItems = 0;
  158. m_dwStateFlags = ASYNC_WORK_QUEUE_NORMAL;
  159. }
  160. //---[ CAsyncWorkQueue::~CAsyncWorkQueue ]-------------------------------------
  161. //
  162. //
  163. // Description:
  164. // Destructor for CAsyncWorkQueue
  165. // Parameters:
  166. // -
  167. // Returns:
  168. // -
  169. // History:
  170. // 3/8/99 - MikeSwa Created
  171. //
  172. //-----------------------------------------------------------------------------
  173. CAsyncWorkQueue::~CAsyncWorkQueue()
  174. {
  175. m_dwSignature = ASYNC_WORK_QUEUE_SIG_FREE;
  176. }
  177. //---[ CAsyncWorkQueue::HrInitialize ]-----------------------------------------
  178. //
  179. //
  180. // Description:
  181. // Initialization routing for CAsyncWorkQueue base. Initializes the
  182. // CAsyncQueue
  183. // Parameters:
  184. // cItemsPerThread The number of items to process per async thread
  185. // Returns:
  186. // S_OK on success
  187. // Failure code from CAsyncQueue::HrInitialize()
  188. // History:
  189. // 3/8/99 - MikeSwa Created
  190. //
  191. //-----------------------------------------------------------------------------
  192. HRESULT CAsyncWorkQueue::HrInitialize(DWORD cItemsPerThread)
  193. {
  194. HRESULT hr = S_OK;
  195. hr = m_asyncq.HrInitialize(0, //there can be *no* sync threads
  196. cItemsPerThread,
  197. 1,//init requires this value to be at least 1
  198. this,
  199. CAsyncWorkQueue::fQueueCompletion,
  200. CAsyncWorkQueue::fQueueFailure,
  201. NULL);
  202. return hr;
  203. }
  204. //---[ CAsyncWorkQueue::HrDeinitialize ]---------------------------------------
  205. //
  206. //
  207. // Description:
  208. // Signals shutdown for queue code
  209. // Parameters:
  210. // paqinst Pointer to AQ server instance object
  211. // Returns:
  212. // S_OK on success
  213. // History:
  214. // 3/8/99 - MikeSwa Created
  215. // 7/7/99 - MikeSwa Allow async threads to help process shutdown
  216. //
  217. //-----------------------------------------------------------------------------
  218. HRESULT CAsyncWorkQueue::HrDeinitialize(CAQSvrInst *paqinst)
  219. {
  220. const DWORD MAX_ITERATIONS_NO_PROGRESS = 1000; //iterations before assert
  221. HRESULT hr = S_OK;
  222. DWORD cLastCount = cGetWorkQueueItems();
  223. DWORD cIterationsNoProgress = 0;
  224. _ASSERT(paqinst);
  225. //Start processing all items in "shutdown" mode
  226. m_dwStateFlags = ASYNC_WORK_QUEUE_SHUTDOWN;
  227. //
  228. // Make sure we have threads actively processing this queue before
  229. // we settle down and wait for them to stop.
  230. //
  231. _ASSERT(!cGetWorkQueueItems() || m_asyncq.dwGetTotalThreads());
  232. m_asyncq.StartRetry();
  233. //Let the worker threads have some fun before we stop and do the single
  234. //theaded initialization
  235. while (cLastCount && (cIterationsNoProgress < MAX_ITERATIONS_NO_PROGRESS))
  236. {
  237. if (cLastCount <= cGetWorkQueueItems())
  238. cIterationsNoProgress++;
  239. //I'd like to see this case
  240. _ASSERT(cIterationsNoProgress < MAX_ITERATIONS_NO_PROGRESS);
  241. cLastCount = cGetWorkQueueItems();
  242. paqinst->ServerStopHintFunction();
  243. //Since it may take longer than our stop hint to process a
  244. //single item in the queue, we need to sleep instead of
  245. //attempting to process an item (Bug #X5:118258).
  246. Sleep(10000);
  247. }
  248. hr = m_asyncq.HrDeinitialize(CAsyncWorkQueue::HrShutdownWalkFn,
  249. paqinst);
  250. return hr;
  251. }
  252. //---[ CAsyncWorkQueue::HrQueueWorkItem ]--------------------------------------
  253. //
  254. //
  255. // Description:
  256. // Queues items to async work queue
  257. // Parameters:
  258. // pvData Data item to pass to completion function
  259. // pfCompletion Completion function
  260. // Returns:
  261. // S_OK on success
  262. // E_OUTOFMEMORY if queue item could not be allocated
  263. // History:
  264. // 3/8/99 - MikeSwa Created
  265. //
  266. //-----------------------------------------------------------------------------
  267. HRESULT CAsyncWorkQueue::HrQueueWorkItem(PVOID pvData,
  268. PASYNC_WORK_QUEUE_FN pfnCompletion)
  269. {
  270. HRESULT hr = S_OK;
  271. CAsyncWorkQueueItem *pawqi = NULL;
  272. _ASSERT(pvData);
  273. _ASSERT(pfnCompletion);
  274. if (!pfnCompletion)
  275. {
  276. hr = E_INVALIDARG;
  277. goto Exit;
  278. }
  279. //Create queue item, initialize it, and queue it
  280. pawqi = new CAsyncWorkQueueItem(pvData, pfnCompletion);
  281. if (!pawqi)
  282. {
  283. hr = E_OUTOFMEMORY;
  284. goto Exit;
  285. }
  286. hr = m_asyncq.HrQueueRequest(pawqi, FALSE);
  287. if (FAILED(hr))
  288. goto Exit;
  289. InterlockedIncrement((PLONG) &m_cWorkQueueItems);
  290. Exit:
  291. if (FAILED(hr) && pfnCompletion)
  292. {
  293. //call completion function
  294. pfnCompletion(pvData,
  295. ASYNC_WORK_QUEUE_FAILURE |
  296. ASYNC_WORK_QUEUE_ENQUEUE_THREAD);
  297. }
  298. if (pawqi)
  299. pawqi->Release();
  300. return hr;
  301. }
  302. //---[ CAsyncWorkQueue::fQueueCompletion ]-------------------------------------
  303. //
  304. //
  305. // Description:
  306. // Completion function called by CAsyncQueue
  307. // Parameters:
  308. // pawqi CAsyncWorkQueueItem to process
  309. // pvContext "this" pointer
  310. // Returns:
  311. // TRUE if item was process
  312. // FALSE otherwise
  313. // History:
  314. // 3/8/99 - MikeSwa Created
  315. //
  316. //-----------------------------------------------------------------------------
  317. BOOL CAsyncWorkQueue::fQueueCompletion(CAsyncWorkQueueItem *pawqi,
  318. PVOID pvContext)
  319. {
  320. BOOL fRet = TRUE;
  321. CAsyncWorkQueue *pawq = (CAsyncWorkQueue *) pvContext;
  322. _ASSERT(pawqi);
  323. _ASSERT(pawq);
  324. _ASSERT(ASYNC_WORK_QUEUE_ENTRY == pawqi->m_dwSignature);
  325. _ASSERT(ASYNC_WORK_QUEUE_SIG == pawq->m_dwSignature);
  326. fRet = pawqi->m_pfnCompletion(pawqi->m_pvData,
  327. pawq->m_dwStateFlags);
  328. if (fRet)
  329. InterlockedDecrement((PLONG)
  330. &(((CAsyncWorkQueue *)pawq)->m_cWorkQueueItems));
  331. return fRet;
  332. }
  333. //---[ CAsyncWorkQueue::fQueueFailure ]----------------------------------------
  334. //
  335. //
  336. // Description:
  337. // Function to handle internal failures in CAsyncQueue
  338. // Parameters:
  339. // pawq "this" pointer
  340. // pawqi CAsyncWorkQueueItem to process
  341. // Returns:
  342. // TRUE always
  343. // History:
  344. // 3/8/99 - MikeSwa Created
  345. //
  346. //-----------------------------------------------------------------------------
  347. BOOL CAsyncWorkQueue::fQueueFailure(CAsyncWorkQueueItem *pawqi,
  348. PVOID pawq)
  349. {
  350. _ASSERT(pawqi);
  351. _ASSERT(pawq);
  352. _ASSERT(ASYNC_WORK_QUEUE_ENTRY == pawqi->m_dwSignature);
  353. _ASSERT(ASYNC_WORK_QUEUE_SIG == ((CAsyncWorkQueue *)pawq)->m_dwSignature);
  354. pawqi->m_pfnCompletion(pawqi->m_pvData, ASYNC_WORK_QUEUE_FAILURE);
  355. InterlockedDecrement((PLONG) &(((CAsyncWorkQueue *)pawq)->m_cWorkQueueItems));
  356. return TRUE;
  357. }
  358. //---[ CAsyncWorkQueue::HrShutdownWalkFn ]-------------------------------------
  359. //
  360. //
  361. // Description:
  362. // Function to walk an CAsyncWorkQueue queue at shutdown and clear out
  363. // all of the pending work items
  364. // Parameters:
  365. // IN CAsyncWorkQueueItem ptr to data on queue
  366. // IN PVOID pvContext AQ server intstance
  367. // OUT BOOL *pfContinue, TRUE if we should continue
  368. // OUT BOOL *pfDelete); TRUE if item should be deleted
  369. // Returns:
  370. // S_OK always
  371. // History:
  372. // 3/8/99 - MikeSwa Created
  373. //
  374. //-----------------------------------------------------------------------------
  375. HRESULT CAsyncWorkQueue::HrShutdownWalkFn(
  376. CAsyncWorkQueueItem *pawqi,
  377. PVOID pvContext,
  378. BOOL *pfContinue,
  379. BOOL *pfDelete)
  380. {
  381. CAQSvrInst *paqinst = (CAQSvrInst *) pvContext;
  382. _ASSERT(pfContinue);
  383. _ASSERT(pfDelete);
  384. _ASSERT(pawqi);
  385. _ASSERT(ASYNC_WORK_QUEUE_ENTRY == pawqi->m_dwSignature);
  386. *pfContinue = TRUE;
  387. *pfDelete = TRUE;
  388. //call server stop hint function
  389. paqinst->ServerStopHintFunction();
  390. pawqi->m_pfnCompletion(pawqi->m_pvData, ASYNC_WORK_QUEUE_SHUTDOWN);
  391. return S_OK;
  392. }