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.

380 lines
14 KiB

  1. //-----------------------------------------------------------------------------
  2. //
  3. //
  4. // File: asyncq.h
  5. //
  6. // Description: Header file for CAsyncQueue class, which provides the
  7. // underlying implementation of pre-local delivery and pre-categorization
  8. // queue.
  9. //
  10. // Author: Mike Swafford (MikeSwa)
  11. //
  12. // History:
  13. // 7/16/98 - MikeSwa Created
  14. // 2/2/99 - MikeSwa Added CAsyncRetryQueue
  15. // 2/22/99 - MikeSwa Added CAsyncRetryAdminMsgRefQueue
  16. //
  17. // Copyright (C) 1998 Microsoft Corporation
  18. //
  19. //-----------------------------------------------------------------------------
  20. #ifndef __ASYNCQ_H__
  21. #define __ASYNCQ_H__
  22. #include <fifoq.h>
  23. #include <intrnlqa.h>
  24. #include <baseobj.h>
  25. #include <aqstats.h>
  26. #include "statemachinebase.h"
  27. _declspec(selectany) BOOL g_fRetryAtFrontOfAsyncQueue = FALSE;
  28. // global count of total number of async threads needed
  29. _declspec(selectany) DWORD g_cTotalThreadsNeeded = 0;
  30. class CAQSvrInst;
  31. class CAsyncWorkQueueItem;
  32. // sig for state machine
  33. #define ASYNC_QUEUE_STATE_MACHINE_SIG 'MSQA'
  34. #define ASYNC_QUEUE_SIG 'QnsA'
  35. #define ASYNC_RETRY_QUEUE_SIG ' QRA'
  36. //Add new template signatures here
  37. #define ASYNC_QUEUE_MAILMSG_SIG 'MMIt'
  38. #define ASYNC_QUEUE_MSGREF_SIG 'frMt'
  39. #define ASYNC_QUEUE_WORK_SIG 'krWt'
  40. //---[ CAsyncQueueBase ]-------------------------------------------------------
  41. //
  42. //
  43. // Description:
  44. // Base class for CAsyncQueue. This is a separate class for 2 reasons.
  45. // The most important reason to to allow access to standard member data
  46. // with out knowing the template type of the class (for ATQ completion
  47. // functions). The 2nd reason is to make it easier to write a debugger
  48. // extension to dump this information.
  49. //
  50. // This class should only be used as a baseclass for CAsyncQueue... it
  51. // is not designed to be used by itself.
  52. // Hungarian:
  53. // asyncqb, pasyncqb
  54. //
  55. //-----------------------------------------------------------------------------
  56. class CAsyncQueueBase : public CStateMachineBase
  57. {
  58. protected:
  59. DWORD m_dwSignature;
  60. DWORD m_dwTemplateSignature; //signature that defines type of PQDATA (for ATQ)
  61. DWORD m_cMaxSyncThreads; //max threads that can complete sync
  62. DWORD m_cCurrentSyncThreads; //current sync threads
  63. DWORD m_cCurrentAsyncThreads; //current number of async threads
  64. DWORD m_cItemsPending; //# of items pending in the queue
  65. LONG m_cItemsPerATQThread; //max # of items an atq thread will process
  66. LONG m_cItemsPerSyncThread; //max # of items a pilfered thread will process
  67. DWORD m_cScheduledWorkItems; // Number of items that a thread has been allocated for
  68. DWORD m_cCurrentCompletionThreads;//# of threads processing end of queue
  69. DWORD m_cTotalAsyncCompletionThreads;//Total # of async completion threads
  70. DWORD m_cTotalSyncCompletionThreads; //Total # of sync completion threads
  71. DWORD m_cTotalShortCircuitThreads; //Total # of threads that proccess data without queue
  72. DWORD m_cCompletionThreadsRequested; //# of threads requested to process queue
  73. DWORD m_cPendingAsyncCompletions; //# of async completions that we know about
  74. DWORD m_cMaxPendingAsyncCompletions;
  75. PVOID m_pvContext; //Context that is passed to completion function
  76. PATQ_CONTEXT m_pAtqContext; //ATQ Context for this object
  77. SOCKET m_hAtqHandle; //Handle used for atq stuff
  78. DWORD m_cThreadsNeeded; // Number of threads we need currently to ideally
  79. // process the queue - used for thread management
  80. friend VOID AsyncQueueAtqCompletion(PVOID pvContext, DWORD vbBytesWritten,
  81. DWORD dwStatus, OVERLAPPED *pOverLapped);
  82. inline CAsyncQueueBase(DWORD dwTemplateSignature);
  83. // possible states
  84. enum
  85. {
  86. ASYNC_QUEUE_STATUS_NORMAL = 0x00000000,
  87. ASYNC_QUEUE_STATUS_PAUSED = 0x00000001,
  88. ASYNC_QUEUE_STATUS_FROZEN = 0x00000002,
  89. ASYNC_QUEUE_STATUS_FROZENPAUSED = 0x00000003,
  90. ASYNC_QUEUE_STATUS_SHUTDOWN = 0x00000004,
  91. };
  92. // possible internal queue actions
  93. enum
  94. {
  95. ASYNC_QUEUE_ACTION_KICK = 0x00000000,
  96. ASYNC_QUEUE_ACTION_FREEZE = 0x00000001,
  97. ASYNC_QUEUE_ACTION_THAW = 0x00000002,
  98. ASYNC_QUEUE_ACTION_PAUSE = 0x00000003,
  99. ASYNC_QUEUE_ACTION_UNPAUSE = 0x00000004,
  100. ASYNC_QUEUE_ACTION_SHUTDOWN = 0x00000005,
  101. };
  102. //
  103. // Statics used for ATQ stuff.
  104. //
  105. static DWORD s_cAsyncQueueStaticInitRefCount;
  106. static DWORD s_cMaxPerProcATQThreadAdjustment;
  107. static DWORD s_cDefaultMaxAsyncThreads;
  108. //
  109. // Statics uses for debugging thread management
  110. //
  111. static DWORD s_cThreadCompletion_QueueEmpty; // Completed because the queue was empty
  112. static DWORD s_cThreadCompletion_CompletedScheduledItems; // Completed because we processed all items we were scheduled for
  113. static DWORD s_cThreadCompletion_UnacceptableThreadCount; // Completed because our queue was consuming more threads than allowed
  114. static DWORD s_cThreadCompletion_Timeout; // Completed because the thread was taking too long to process
  115. static DWORD s_cThreadCompletion_Failure; // Completed because an item failed
  116. static DWORD s_cThreadCompletion_Paused; // Completed because the queue was paused
  117. void ThreadPoolInitialize();
  118. void ThreadPoolDeinitialize();
  119. // used for state machine stuff
  120. static STATE_TRANSITION s_rgTransitionTable[];
  121. virtual void getTransitionTable(const STATE_TRANSITION** ppTransitionTable,
  122. DWORD* pdwNumTransitions);
  123. public:
  124. DWORD dwGetTotalThreads()
  125. {
  126. return ( m_cCurrentSyncThreads +
  127. m_cCurrentAsyncThreads +
  128. m_cCompletionThreadsRequested);
  129. }
  130. //
  131. // Start point for worker threads
  132. //
  133. virtual void StartThreadCompletionRoutine(BOOL fSync) = 0;
  134. };
  135. //---[ CAsyncQueue ]-----------------------------------------------------------
  136. //
  137. //
  138. // Description:
  139. // FIFO queue that allows thread-throttling and async completion.
  140. // Inherits from CAsyncQueueBase.
  141. // Hungarian:
  142. // asyncq, pasyncq
  143. //
  144. //-----------------------------------------------------------------------------
  145. template<class PQDATA, DWORD TEMPLATE_SIG>
  146. class CAsyncQueue : public CAsyncQueueBase
  147. {
  148. public:
  149. typedef BOOL (*QCOMPFN)(PQDATA pqdItem, PVOID pvContext); //function type for Queue completion
  150. CAsyncQueue();
  151. ~CAsyncQueue();
  152. HRESULT HrInitialize(
  153. DWORD cMaxSyncThreads,
  154. DWORD cItemsPerATQThread,
  155. DWORD cItemsPerSyncThread,
  156. PVOID pvContext,
  157. QCOMPFN pfnQueueCompletion,
  158. QCOMPFN pfnFailedItem,
  159. typename CFifoQueue<PQDATA>::MAPFNAPI pfnQueueFailure,
  160. DWORD cMaxPendingAsyncCompletions = 0);
  161. HRESULT HrDeinitialize(typename CFifoQueue<PQDATA>::MAPFNAPI pfnQueueShutdown,
  162. CAQSvrInst *paqinst);
  163. HRESULT HrQueueRequest(PQDATA pqdata, BOOL fRetry = FALSE); //Queue request for processing
  164. void StartThreadCompletionRoutine(BOOL fSync); //Start point for worker threads
  165. void RequestCompletionThreadIfNeeded();
  166. BOOL fThreadNeededAndMarkWorkPending(BOOL fSync);
  167. virtual BOOL fHandleCompletionFailure(PQDATA pqdata);
  168. void StartRetry() {UnpauseQueue();RequestCompletionThreadIfNeeded();};
  169. virtual HRESULT HrMapFn(typename CFifoQueue<PQDATA>::MAPFNAPI pfnQueueFn, PVOID pvContext);
  170. DWORD cGetItemsPending() {return m_cItemsPending;};
  171. //
  172. // "Pause" API - This is used to throttle async completions
  173. //
  174. void PauseQueue() { dwGetNextState(ASYNC_QUEUE_ACTION_PAUSE); UpdateThreadsNeeded();};
  175. void UnpauseQueue();
  176. inline BOOL fIsPaused() {return (ASYNC_QUEUE_STATUS_PAUSED == dwGetCurrentState());};
  177. //
  178. // "Freeze" API - This is used to allow the QAPI to freeze/thaw a queue
  179. //
  180. void FreezeQueue() { dwGetNextState(ASYNC_QUEUE_ACTION_FREEZE); UpdateThreadsNeeded();};
  181. void ThawQueue();
  182. inline BOOL fIsFrozen() {return (ASYNC_QUEUE_STATUS_FROZEN == dwGetCurrentState());};
  183. // "Kick" API
  184. // kicking the queue overrides freezing, so if it is frozen it should be thawed.
  185. void KickQueue() { ThawQueue(); StartRetry(); };
  186. // chefking for shutdown
  187. inline BOOL fInShutdown() {return (ASYNC_QUEUE_STATUS_SHUTDOWN == dwGetCurrentState());};
  188. // Denotes whether threads should stop processing. (replaces fIsPaused)
  189. inline BOOL fShouldStopProcessing() { return (fIsFrozen() || fIsPaused());};
  190. //
  191. // Tells the queue about pending async completions, so it can be
  192. // intelligent about throttling. As we hit the limit, we will
  193. // pause/unpause the queue
  194. //
  195. void IncPendingAsyncCompletions();
  196. void DecPendingAsyncCompletions();
  197. BOOL fNoPendingAsyncCompletions();
  198. //
  199. // Basic QAPI functionality
  200. //
  201. DWORD cQueueAdminGetNumItems() {return m_cItemsPending;};
  202. DWORD dwQueueAdminLinkGetLinkState();
  203. protected:
  204. CFifoQueue<PQDATA> m_fqQueue; //queue for items
  205. //Function called to handle item pulled off of queue
  206. QCOMPFN m_pfnQueueCompletion;
  207. //Function called to handle items that could not be called due to resource
  208. //failures (for example during MergeRetryQueue).
  209. QCOMPFN m_pfnFailedItem;
  210. //Function called to walk the queues when the completion function fails
  211. typename CFifoQueue<PQDATA>::MAPFNAPI m_pfnQueueFailure;
  212. //Process the item at the head of the queue
  213. HRESULT HrProcessSingleQueueItem();
  214. //Handles callback for dropped data
  215. void HandleDroppedItem(PQDATA pqdItem);
  216. VOID IncrementPendingCount(LONG lCount=1)
  217. {
  218. if (!lCount)
  219. return;
  220. _ASSERT(lCount > 0); //should call decrement
  221. InterlockedExchangeAdd((PLONG) &m_cItemsPending, lCount);
  222. // Update threads needed
  223. UpdateThreadsNeeded();
  224. };
  225. VOID DecrementPendingCount(LONG lCount=-1)
  226. {
  227. if (!lCount)
  228. return;
  229. _ASSERT(lCount < 0); //should call increment instead
  230. InterlockedExchangeAdd((PLONG) &m_cItemsPending, lCount);
  231. // Update threads needed
  232. UpdateThreadsNeeded();
  233. };
  234. //Update the local and global threads needed counters
  235. void UpdateThreadsNeeded();
  236. //Used to decide if we should add or remove threads from this queue
  237. BOOL fIsThreadCountAcceptable();
  238. };
  239. //---[ CAsyncRetryQueue ]------------------------------------------------------
  240. //
  241. //
  242. // Description:
  243. // Derived class of CAsyncQueue adds an additional queue to gracefully
  244. // handle retry scenarios.
  245. //
  246. // Messages are first placed in the normal retry queue, If they fail,
  247. // they are placed in a secondary retry queue, which will not be retried
  248. // until this queue is kicked by an external retry timer.
  249. // Hungarian:
  250. // asyncrq, pasyncrq
  251. //
  252. //-----------------------------------------------------------------------------
  253. template<class PQDATA, DWORD TEMPLATE_SIG>
  254. class CAsyncRetryQueue : public CAsyncQueue<PQDATA, TEMPLATE_SIG>
  255. {
  256. public:
  257. CAsyncRetryQueue();
  258. ~CAsyncRetryQueue();
  259. HRESULT HrDeinitialize(typename CFifoQueue<PQDATA>::MAPFNAPI pfnQueueShutdown,
  260. CAQSvrInst *paqinst);
  261. void StartRetry()
  262. {
  263. MergeRetryQueue();
  264. CAsyncQueue<PQDATA, TEMPLATE_SIG>::StartRetry();
  265. };
  266. HRESULT HrQueueRequest(PQDATA pqdata, BOOL fRetry = FALSE); //Queue request for processing
  267. virtual BOOL fHandleCompletionFailure(PQDATA pqdata);
  268. virtual HRESULT HrMapFn(typename CFifoQueue<PQDATA>::MAPFNAPI pfnQueueFn, PVOID pvContext);
  269. virtual HRESULT HrMapFnBaseQueue(typename CFifoQueue<PQDATA>::MAPFNAPI pfnQueueFn, PVOID pvContext);
  270. virtual HRESULT HrMapFnRetryQueue(typename CFifoQueue<PQDATA>::MAPFNAPI pfnQueueFn, PVOID pvContext);
  271. DWORD cGetItemsPendingRetry() {return m_cRetryItems;};
  272. //
  273. // Basic QAPI functionality
  274. //
  275. DWORD cQueueAdminGetNumItems() {return (m_cItemsPending+m_cRetryItems);};
  276. DWORD dwQueueAdminLinkGetLinkState();
  277. protected:
  278. DWORD m_dwRetrySignature;
  279. DWORD m_cRetryItems;
  280. CFifoQueue<PQDATA> m_fqRetryQueue; //queue for items
  281. void MergeRetryQueue();
  282. };
  283. //Define typical asyncq type for casting
  284. typedef CAsyncQueue<CMsgRef *, ASYNC_QUEUE_MSGREF_SIG> ASYNCQ_TYPE;
  285. typedef ASYNCQ_TYPE *PASYNCQ_TYPE;
  286. //---[ AsyncQueueAtqCompletion ]-----------------------------------------------
  287. //
  288. //
  289. // Description:
  290. // Atq completion routine. This is slightly tricky since we cannot pass
  291. // a templated function to the ATQ context. This is the one place that
  292. // templating breaks down, and we actually need to list all of the
  293. // supported PQDATA types.
  294. // Parameters:
  295. // pvContext - ptr fo CAsyncQueue class
  296. // Returns:
  297. // -
  298. // History:
  299. // 7/17/98 - MikeSwa Created
  300. // 3/8/99 - MikeSwa Added ASYNC_QUEUE_WORK_SIG
  301. // 12/11/2000 - MikeSwa Added t-toddc's virtual code
  302. //
  303. //----------------------------------------------------------------------------
  304. inline VOID AsyncQueueAtqCompletion(PVOID pvContext, DWORD vbBytesWritten,
  305. DWORD dwStatus, OVERLAPPED *pOverLapped)
  306. {
  307. CAsyncQueueBase *pasyncqb = (PASYNCQ_TYPE) pvContext;
  308. DWORD dwTemplateSig = pasyncqb->m_dwTemplateSignature;
  309. DWORD dwCurrentQueueState = pasyncqb->dwGetCurrentState();
  310. _ASSERT(ASYNC_QUEUE_SIG == pasyncqb->m_dwSignature);
  311. //Up total async thread count (only async threads visit this function)
  312. InterlockedIncrement((PLONG) &(pasyncqb->m_cTotalAsyncCompletionThreads));
  313. InterlockedDecrement((PLONG) &(pasyncqb->m_cCompletionThreadsRequested));
  314. InterlockedIncrement((PLONG) &(pasyncqb->m_cCurrentAsyncThreads));
  315. //
  316. // Call completion routing if we are not shutting down
  317. //
  318. if (CAsyncQueueBase::ASYNC_QUEUE_STATUS_SHUTDOWN != dwCurrentQueueState)
  319. {
  320. pasyncqb->StartThreadCompletionRoutine(FALSE);
  321. }
  322. InterlockedDecrement((PLONG) &(pasyncqb->m_cCurrentAsyncThreads));
  323. }
  324. #endif //__ASYNCQ_H__