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.

256 lines
10 KiB

  1. //-----------------------------------------------------------------------------
  2. //
  3. //
  4. // File: asyncq.cpp
  5. //
  6. // Description: Non-template asyncq implementations
  7. //
  8. // Author: Mike Swafford (MikeSwa)
  9. //
  10. // History:
  11. // 2/23/99 - MikeSwa Created
  12. //
  13. // Copyright (C) 1999 Microsoft Corporation
  14. //
  15. //-----------------------------------------------------------------------------
  16. #include "aqprecmp.h"
  17. #include "asyncq.h"
  18. #include "asyncq.inl"
  19. DWORD CAsyncQueueBase::s_cAsyncQueueStaticInitRefCount = 0;
  20. DWORD CAsyncQueueBase::s_cMaxPerProcATQThreadAdjustment = 0;
  21. DWORD CAsyncQueueBase::s_cDefaultMaxAsyncThreads = 0;
  22. // Some counters for debugging thread management
  23. DWORD CAsyncQueueBase::s_cThreadCompletion_QueueEmpty = 0;
  24. DWORD CAsyncQueueBase::s_cThreadCompletion_CompletedScheduledItems = 0;
  25. DWORD CAsyncQueueBase::s_cThreadCompletion_UnacceptableThreadCount = 0;
  26. DWORD CAsyncQueueBase::s_cThreadCompletion_Timeout = 0;
  27. DWORD CAsyncQueueBase::s_cThreadCompletion_Failure = 0;
  28. DWORD CAsyncQueueBase::s_cThreadCompletion_Paused = 0;
  29. // state transition table for the async queue state machine
  30. STATE_TRANSITION CAsyncQueueBase::s_rgTransitionTable[] =
  31. {
  32. // start state normal:
  33. { ASYNC_QUEUE_STATUS_NORMAL, ASYNC_QUEUE_ACTION_KICK, ASYNC_QUEUE_STATUS_NORMAL },
  34. { ASYNC_QUEUE_STATUS_NORMAL, ASYNC_QUEUE_ACTION_PAUSE, ASYNC_QUEUE_STATUS_PAUSED },
  35. { ASYNC_QUEUE_STATUS_NORMAL, ASYNC_QUEUE_ACTION_UNPAUSE, ASYNC_QUEUE_STATUS_NORMAL },
  36. { ASYNC_QUEUE_STATUS_NORMAL, ASYNC_QUEUE_ACTION_FREEZE, ASYNC_QUEUE_STATUS_FROZEN },
  37. { ASYNC_QUEUE_STATUS_NORMAL, ASYNC_QUEUE_ACTION_THAW, ASYNC_QUEUE_STATUS_NORMAL },
  38. { ASYNC_QUEUE_STATUS_NORMAL, ASYNC_QUEUE_ACTION_SHUTDOWN, ASYNC_QUEUE_STATUS_SHUTDOWN },
  39. // start state paused:
  40. { ASYNC_QUEUE_STATUS_PAUSED, ASYNC_QUEUE_ACTION_KICK, ASYNC_QUEUE_STATUS_NORMAL },
  41. { ASYNC_QUEUE_STATUS_PAUSED, ASYNC_QUEUE_ACTION_PAUSE, ASYNC_QUEUE_STATUS_PAUSED },
  42. { ASYNC_QUEUE_STATUS_PAUSED, ASYNC_QUEUE_ACTION_UNPAUSE, ASYNC_QUEUE_STATUS_NORMAL },
  43. { ASYNC_QUEUE_STATUS_PAUSED, ASYNC_QUEUE_ACTION_FREEZE, ASYNC_QUEUE_STATUS_FROZENPAUSED },
  44. { ASYNC_QUEUE_STATUS_PAUSED, ASYNC_QUEUE_ACTION_THAW, ASYNC_QUEUE_STATUS_PAUSED },
  45. { ASYNC_QUEUE_STATUS_PAUSED, ASYNC_QUEUE_ACTION_SHUTDOWN, ASYNC_QUEUE_STATUS_SHUTDOWN },
  46. // start state frozen:
  47. { ASYNC_QUEUE_STATUS_FROZEN, ASYNC_QUEUE_ACTION_KICK, ASYNC_QUEUE_STATUS_NORMAL },
  48. { ASYNC_QUEUE_STATUS_FROZEN, ASYNC_QUEUE_ACTION_PAUSE, ASYNC_QUEUE_STATUS_FROZENPAUSED },
  49. { ASYNC_QUEUE_STATUS_FROZEN, ASYNC_QUEUE_ACTION_UNPAUSE, ASYNC_QUEUE_STATUS_FROZEN },
  50. { ASYNC_QUEUE_STATUS_FROZEN, ASYNC_QUEUE_ACTION_FREEZE, ASYNC_QUEUE_STATUS_FROZEN },
  51. { ASYNC_QUEUE_STATUS_FROZEN, ASYNC_QUEUE_ACTION_THAW, ASYNC_QUEUE_STATUS_NORMAL },
  52. { ASYNC_QUEUE_STATUS_FROZEN, ASYNC_QUEUE_ACTION_SHUTDOWN, ASYNC_QUEUE_STATUS_SHUTDOWN },
  53. // start state frozenpaused:
  54. { ASYNC_QUEUE_STATUS_FROZENPAUSED, ASYNC_QUEUE_ACTION_KICK, ASYNC_QUEUE_STATUS_NORMAL },
  55. { ASYNC_QUEUE_STATUS_FROZENPAUSED, ASYNC_QUEUE_ACTION_PAUSE, ASYNC_QUEUE_STATUS_FROZENPAUSED },
  56. { ASYNC_QUEUE_STATUS_FROZENPAUSED, ASYNC_QUEUE_ACTION_UNPAUSE, ASYNC_QUEUE_STATUS_FROZEN },
  57. { ASYNC_QUEUE_STATUS_FROZENPAUSED, ASYNC_QUEUE_ACTION_FREEZE, ASYNC_QUEUE_STATUS_FROZENPAUSED },
  58. { ASYNC_QUEUE_STATUS_FROZENPAUSED, ASYNC_QUEUE_ACTION_THAW, ASYNC_QUEUE_STATUS_PAUSED },
  59. { ASYNC_QUEUE_STATUS_FROZENPAUSED, ASYNC_QUEUE_ACTION_SHUTDOWN, ASYNC_QUEUE_STATUS_SHUTDOWN },
  60. // start state shutdown:
  61. { ASYNC_QUEUE_STATUS_SHUTDOWN, ASYNC_QUEUE_ACTION_KICK, ASYNC_QUEUE_STATUS_SHUTDOWN },
  62. { ASYNC_QUEUE_STATUS_SHUTDOWN, ASYNC_QUEUE_ACTION_PAUSE, ASYNC_QUEUE_STATUS_SHUTDOWN },
  63. { ASYNC_QUEUE_STATUS_SHUTDOWN, ASYNC_QUEUE_ACTION_UNPAUSE, ASYNC_QUEUE_STATUS_SHUTDOWN },
  64. { ASYNC_QUEUE_STATUS_SHUTDOWN, ASYNC_QUEUE_ACTION_FREEZE, ASYNC_QUEUE_STATUS_SHUTDOWN },
  65. { ASYNC_QUEUE_STATUS_SHUTDOWN, ASYNC_QUEUE_ACTION_THAW, ASYNC_QUEUE_STATUS_SHUTDOWN },
  66. { ASYNC_QUEUE_STATUS_SHUTDOWN, ASYNC_QUEUE_ACTION_SHUTDOWN, ASYNC_QUEUE_STATUS_SHUTDOWN },
  67. };
  68. //---[ CAsyncQueueBase::getTransitionTable ]------------
  69. //
  70. //
  71. // Description:
  72. // returns the state transition table and its size to
  73. // CStateMachineBase whenever needed.
  74. // Parameters:
  75. // - ppTransitionTable pointer to the state transition table
  76. // pdwNumTransitions pointer to the number of transitions in
  77. // the table
  78. // Returns:
  79. // -
  80. // History:
  81. // 6/5/2000 - t-toddc Created
  82. // 12/11/2000 - MikeSwa Merged for Hg checkin
  83. //
  84. //------------------------------------------------------------------
  85. void CAsyncQueueBase::getTransitionTable(const STATE_TRANSITION** ppTransitionTable,
  86. DWORD* pdwNumTransitions)
  87. {
  88. TraceFunctEnter("CAsyncQueueStateMachine::getTransitionTable");
  89. ASSERT(ppTransitionTable && "NULL transition table pointer");
  90. ASSERT(pdwNumTransitions && "NULL num transitions pointer");
  91. ASSERT(s_rgTransitionTable && "transition table uninitialized");
  92. // bail on bad input or no good transition table
  93. if (!ppTransitionTable || !pdwNumTransitions || !s_rgTransitionTable)
  94. goto Exit;
  95. *ppTransitionTable = s_rgTransitionTable;
  96. *pdwNumTransitions = sizeof(CAsyncQueueBase::s_rgTransitionTable) /
  97. sizeof(STATE_TRANSITION);
  98. Exit:
  99. TraceFunctLeave();
  100. }
  101. //---[ CAsyncQueueBase::ThreadPoolInitialize ]---------------------------------
  102. //
  103. //
  104. // Description:
  105. // Performs static ATQ initialization. This call is ref-counted. If
  106. // it succeeds, the caller should call ThreadPoolDeinitialze();
  107. // Parameters:
  108. // -
  109. // Returns:
  110. // -
  111. // History:
  112. // 3/30/2000 - MikeSwa Created
  113. //
  114. //-----------------------------------------------------------------------------
  115. void CAsyncQueueBase::ThreadPoolInitialize()
  116. {
  117. TraceFunctEnterEx((LPARAM) this, "CAsyncQueueBase::ThreadPoolInitialize");
  118. DWORD cATQMaxAsyncThreads = 0;
  119. DWORD cATQMaxTotalAsyncThreads = 0;
  120. DWORD cOurMaxAsyncThreads = 0;
  121. SYSTEM_INFO sinf;
  122. //
  123. // On 0 -> 1 transition, adjust ATQ according to our config
  124. //
  125. if (!s_cAsyncQueueStaticInitRefCount)
  126. {
  127. //
  128. // Get max threads per proc
  129. //
  130. cATQMaxAsyncThreads = (DWORD)AtqGetInfo(AtqMaxPoolThreads);
  131. _ASSERT(cATQMaxAsyncThreads && "AtqGetInfo says there are no threads!");
  132. if (!cATQMaxAsyncThreads)
  133. cATQMaxAsyncThreads = 1;
  134. cOurMaxAsyncThreads = cATQMaxAsyncThreads;
  135. //
  136. // Adjust value by our config value
  137. //
  138. cOurMaxAsyncThreads += g_cPerProcMaxThreadPoolModifier;
  139. //
  140. // Get # of procs (using GetSystemInfo)
  141. //
  142. GetSystemInfo(&sinf);
  143. cOurMaxAsyncThreads *= sinf.dwNumberOfProcessors;
  144. //
  145. // We will throttle our requests at g_cMaxATQPercent
  146. // the max number of ATQ threads
  147. //
  148. cOurMaxAsyncThreads = (g_cMaxATQPercent*cOurMaxAsyncThreads)/100;
  149. if (!cOurMaxAsyncThreads)
  150. cOurMaxAsyncThreads = 1;
  151. //
  152. // Set static so people later on can use this calculation
  153. //
  154. s_cDefaultMaxAsyncThreads = cOurMaxAsyncThreads;
  155. //
  156. // Now we need to adjust our threads
  157. //
  158. s_cMaxPerProcATQThreadAdjustment = g_cPerProcMaxThreadPoolModifier;
  159. //
  160. // Per proc thread limit
  161. //
  162. if (s_cMaxPerProcATQThreadAdjustment)
  163. {
  164. AtqSetInfo(AtqMaxPoolThreads,
  165. cATQMaxAsyncThreads + s_cMaxPerProcATQThreadAdjustment);
  166. DebugTrace((LPARAM) this,
  167. "Adjusting per proc ATQ thread limit by %d (orig %d)",
  168. s_cMaxPerProcATQThreadAdjustment, cATQMaxAsyncThreads);
  169. }
  170. _ASSERT(!(0xFF000000 & cOurMaxAsyncThreads)); //sanity check number
  171. }
  172. s_cAsyncQueueStaticInitRefCount++;
  173. TraceFunctLeave();
  174. }
  175. //---[ CAsyncQueueBase::ThreadPoolDeinitialize ]-------------------------------
  176. //
  177. //
  178. // Description:
  179. // Will re-adjust ATQ data if we changed them during initialization
  180. // Parameters:
  181. // -
  182. // Returns:
  183. // -
  184. // History:
  185. // 3/30/2000 - MikeSwa Created
  186. //
  187. //-----------------------------------------------------------------------------
  188. void CAsyncQueueBase::ThreadPoolDeinitialize()
  189. {
  190. TraceFunctEnterEx((LPARAM) this, "CAsyncQueueBase::ThreadPoolDeinitialize");
  191. DWORD cATQMaxAsyncThreads = 0;
  192. DWORD cATQMaxTotalAsyncThreads = 0;
  193. _ASSERT(s_cAsyncQueueStaticInitRefCount != 0);
  194. s_cAsyncQueueStaticInitRefCount--;
  195. //
  196. // If this is the last queue, adjust our configuration so back to
  197. // the way we found it.
  198. //
  199. if (!s_cAsyncQueueStaticInitRefCount)
  200. {
  201. cATQMaxAsyncThreads = (DWORD)AtqGetInfo(AtqMaxPoolThreads);
  202. cATQMaxTotalAsyncThreads = (DWORD) AtqGetInfo(AtqMaxThreadLimit);
  203. //
  204. // Reset per-proc threads if it makes sense
  205. //
  206. if (s_cMaxPerProcATQThreadAdjustment &&
  207. (cATQMaxAsyncThreads > s_cMaxPerProcATQThreadAdjustment))
  208. {
  209. AtqSetInfo(AtqMaxPoolThreads,
  210. cATQMaxAsyncThreads - s_cMaxPerProcATQThreadAdjustment);
  211. DebugTrace((LPARAM) this,
  212. "Resetting ATQ Max per proc threads to %d",
  213. cATQMaxAsyncThreads - s_cMaxPerProcATQThreadAdjustment);
  214. s_cMaxPerProcATQThreadAdjustment = 0;
  215. }
  216. }
  217. // Verify that m_cThreadsNeeded has reached zero
  218. _ASSERT(!m_cThreadsNeeded);
  219. TraceFunctLeave();
  220. }