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.

267 lines
8.0 KiB

  1. /*++
  2. Copyright (C) 1996-2001 Microsoft Corporation
  3. Module Name:
  4. THROTTLE.CPP
  5. Abstract:
  6. see throttle.h
  7. History:
  8. 24-Oct-200 ivanbrug created.
  9. --*/
  10. #include "precomp.h"
  11. #include <throttle.h>
  12. #include <arrtempl.h>
  13. #include <wbemint.h>
  14. typedef NTSTATUS (NTAPI * fnNtQuerySystemInformation )(
  15. IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
  16. OUT PVOID SystemInformation,
  17. IN ULONG SystemInformationLength,
  18. OUT PULONG ReturnLength OPTIONAL
  19. );
  20. fnNtQuerySystemInformation MyNtQuerySystemInformation = NULL;
  21. HRESULT POLARITY
  22. Throttle(DWORD dwFlags,
  23. DWORD IdleMSec, // in MilliSeconds
  24. DWORD IoIdleBytePerSec, // in BytesPerSec
  25. DWORD SleepLoop, // in MilliSeconds
  26. DWORD MaxWait) // in MilliSeconds
  27. //
  28. // This function will wait until one of this two/three things have happened:
  29. // - the system has been idle for at least IdleMSec milliseconds
  30. // (no user input within IdleMSec milliseconds)
  31. // - the Number of bytes per seconds passed through
  32. // the IO system is below a threashold
  33. // - the MaxWait time has elapsed
  34. //
  35. // Reasonable Params are
  36. // 3000-5000 millisecond with THROTTLE_USER
  37. // 300.000 - 500.000 bytes/second with THROTTLE_IO
  38. // 200 - 500 milliseconds for SleepLoop
  39. // several minutes for MaxWait
  40. //
  41. // remarks:
  42. // - the function will SUCCEDED(Throttle), no matter
  43. // - if the MaxWait has been reached or if the Idle conditions
  44. // have been met the function will fail in any other case
  45. // - the function is 'precise' within the range if a System Tick
  46. // (15ms on professional)
  47. // - in the case of an IO throttling, there will always be a Sleep(150)
  48. //
  49. {
  50. //
  51. // init static and globals
  52. //
  53. if (!MyNtQuerySystemInformation)
  54. {
  55. HMODULE hDll = GetModuleHandleW(L"ntdll.dll");
  56. if (hDll){
  57. MyNtQuerySystemInformation = (fnNtQuerySystemInformation)GetProcAddress(hDll,"NtQuerySystemInformation");
  58. if ( MyNtQuerySystemInformation == NULL )
  59. {
  60. return WBEM_E_FAILED;
  61. }
  62. } else {
  63. return WBEM_E_FAILED;
  64. }
  65. }
  66. static DWORD TimeInc = 0;
  67. if (!TimeInc)
  68. {
  69. BOOL bIsValid;
  70. DWORD dwAdj;
  71. if (!GetSystemTimeAdjustment(&dwAdj,&TimeInc,&bIsValid))
  72. {
  73. return WBEM_E_FAILED;
  74. }
  75. }
  76. static DWORD PageSize = 0;
  77. if (!PageSize)
  78. {
  79. SYSTEM_INFO SysInfo;
  80. GetSystemInfo(&SysInfo);
  81. PageSize = SysInfo.dwPageSize;
  82. }
  83. //
  84. // param validation
  85. //
  86. if ((dwFlags & ~THROTTLE_ALLOWED_FLAGS) ||
  87. (0 == SleepLoop))
  88. return WBEM_E_INVALID_PARAMETER;
  89. DWORD nTimes = MaxWait/SleepLoop;
  90. // user input structures
  91. LASTINPUTINFO LInInfo;
  92. LInInfo.cbSize = sizeof(LASTINPUTINFO);
  93. DWORD i;
  94. DWORD Idle100ns = 10000*IdleMSec; // conversion from 1ms to 100ns
  95. // io throttling
  96. SYSTEM_PERFORMANCE_INFORMATION SPI[2];
  97. BOOL bFirstIOSampleDone = FALSE;
  98. DWORD dwWhich = 0;
  99. DWORD cbIO = 1+IoIdleBytePerSec;
  100. DWORD cbIOOld = 0;
  101. // boolean logic
  102. BOOL bCnd1 = FALSE;
  103. BOOL bCnd2 = FALSE;
  104. // registry stuff for wmisvc to force exit from this function
  105. HKEY hKey = NULL;
  106. LONG lRes;
  107. DWORD dwType;
  108. DWORD dwLen = sizeof(DWORD);
  109. DWORD dwVal;
  110. lRes = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  111. HOME_REG_PATH,
  112. 0,
  113. KEY_READ,
  114. &hKey);
  115. if (ERROR_SUCCESS != lRes)
  116. return WBEM_E_FAILED;
  117. CRegCloseMe cm_(hKey);
  118. if (dwFlags & THROTTLE_IO)
  119. {
  120. NTSTATUS Status;
  121. Status = MyNtQuerySystemInformation(SystemPerformanceInformation,
  122. &SPI[dwWhich],
  123. sizeof(SYSTEM_PERFORMANCE_INFORMATION),
  124. 0);
  125. if (0 != Status)
  126. {
  127. return WBEM_E_FAILED;
  128. }
  129. dwWhich = (dwWhich+1)%2;
  130. Sleep(150);
  131. }
  132. for (i=0;i<nTimes;i++)
  133. {
  134. //
  135. // check if someone is telling us to stop waiting
  136. //
  137. lRes = RegQueryValueEx(hKey,
  138. DO_THROTTLE,
  139. 0,
  140. &dwType,
  141. (BYTE*)&dwVal,
  142. &dwLen);
  143. if(ERROR_SUCCESS == lRes &&
  144. 0 == dwVal)
  145. return THROTTLE_FORCE_EXIT;
  146. //
  147. // check the user-input idleness
  148. //
  149. if (dwFlags & THROTTLE_USER)
  150. {
  151. if (!GetLastInputInfo(&LInInfo))
  152. return WBEM_E_FAILED;
  153. DWORD Now = GetTickCount();
  154. if (Now < LInInfo.dwTime)
  155. {
  156. continue; // one of the 49.7 days events
  157. }
  158. DWORD LastInput100ns = (Now - LInInfo.dwTime)*TimeInc;
  159. if (LastInput100ns >= Idle100ns)
  160. {
  161. if (0 == (dwFlags & ~THROTTLE_USER)) {
  162. return THROTTLE_USER_IDLE;
  163. } else {
  164. bCnd1 = TRUE;
  165. };
  166. }
  167. }
  168. //
  169. // avoid checking the second condition
  170. // if the first is FALSE
  171. //
  172. if (((dwFlags & (THROTTLE_IO|THROTTLE_USER)) == (THROTTLE_IO|THROTTLE_USER)) &&
  173. !bCnd1)
  174. {
  175. goto sleep_label;
  176. }
  177. //
  178. // check the io idleness
  179. //
  180. if (dwFlags & THROTTLE_IO)
  181. {
  182. NTSTATUS Status;
  183. Status = MyNtQuerySystemInformation(SystemPerformanceInformation,
  184. &SPI[dwWhich],
  185. sizeof(SYSTEM_PERFORMANCE_INFORMATION),
  186. 0);
  187. if (0 == Status){
  188. cbIOOld = cbIO;
  189. cbIO = (DWORD)((SPI[dwWhich].IoReadTransferCount.QuadPart - SPI[(dwWhich-1)%2].IoReadTransferCount.QuadPart) +
  190. (SPI[dwWhich].IoWriteTransferCount.QuadPart - SPI[(dwWhich-1)%2].IoWriteTransferCount.QuadPart) +
  191. (SPI[dwWhich].IoOtherTransferCount.QuadPart - SPI[(dwWhich-1)%2].IoOtherTransferCount.QuadPart) +
  192. ((SPI[dwWhich].PageReadCount - SPI[(dwWhich-1)%2].PageReadCount) +
  193. (SPI[dwWhich].CacheReadCount - SPI[(dwWhich-1)%2].CacheReadCount) +
  194. (SPI[dwWhich].DirtyPagesWriteCount - SPI[(dwWhich-1)%2].DirtyPagesWriteCount) +
  195. (SPI[dwWhich].MappedPagesWriteCount - SPI[(dwWhich-1)%2].MappedPagesWriteCount)) * PageSize);
  196. cbIO = (cbIO * 1000)/SleepLoop;
  197. //DBG_PRINTFA((pBuff,"%d - ",cbIO));
  198. cbIO = (cbIOOld+cbIO)/2;
  199. dwWhich = (dwWhich+1)%2;
  200. //DBG_PRINTFA((pBuff,"%d < %d\n",cbIO,IoIdleBytePerSec));
  201. if (cbIO < IoIdleBytePerSec)
  202. {
  203. if (0 == (dwFlags & ~THROTTLE_IO)) {
  204. return THROTTLE_IO_IDLE;
  205. } else {
  206. bCnd2 = TRUE;
  207. };
  208. }
  209. }
  210. else
  211. {
  212. return WBEM_E_FAILED;
  213. }
  214. }
  215. //
  216. // check the combined condition
  217. //
  218. if (dwFlags & (THROTTLE_IO|THROTTLE_USER))
  219. {
  220. if (bCnd1 && bCnd2)
  221. {
  222. return (THROTTLE_IO_IDLE|THROTTLE_USER_IDLE);
  223. }
  224. else
  225. {
  226. bCnd1 = FALSE;
  227. bCnd2 = FALSE;
  228. }
  229. }
  230. sleep_label:
  231. Sleep(SleepLoop);
  232. }
  233. return THROTTLE_MAX_WAIT;
  234. }