Source code of Windows XP (NT5)
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.

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