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.

297 lines
7.0 KiB

  1. /*++
  2. Copyright (C) 1996-2001 Microsoft Corporation
  3. Module Name:
  4. SLEEPER.CPP
  5. Abstract:
  6. MinMax controls.
  7. History:
  8. --*/
  9. #include "precomp.h"
  10. #include <stdio.h>
  11. #include <wbemcomn.h>
  12. #include "sleeper.h"
  13. CLimitControl::CLimitControl()
  14. : m_dwMembers(0)
  15. {
  16. }
  17. HRESULT CLimitControl::AddMember()
  18. {
  19. InterlockedIncrement((long*)&m_dwMembers);
  20. return S_OK;
  21. }
  22. HRESULT CLimitControl::RemoveMember()
  23. {
  24. InterlockedDecrement((long*)&m_dwMembers);
  25. return S_OK;
  26. }
  27. CMinMaxLimitControl::CMinMaxLimitControl(int nLog, LPCWSTR wszName)
  28. : m_dwMin(10000000), m_dwMax(20000000), m_dwSleepAtMax(60000),
  29. m_nLog(nLog), m_wsName(wszName), m_dwCurrentTotal(0),
  30. m_bMessageLogged(FALSE)
  31. {
  32. }
  33. HRESULT CMinMaxLimitControl::Add(DWORD dwHowMuch, DWORD dwMemberTotal,
  34. DWORD* pdwSleep)
  35. {
  36. // Add amount to the total
  37. // =======================
  38. DWORD dwNewTotal;
  39. {
  40. CInCritSec ics(&m_cs);
  41. m_dwCurrentTotal += dwHowMuch;
  42. dwNewTotal = m_dwCurrentTotal;
  43. }
  44. // Calculate the penalty
  45. // =====================
  46. DWORD dwSleep = 0;
  47. BOOL bLog = TRUE;
  48. HRESULT hres = ComputePenalty(dwNewTotal, dwMemberTotal, &dwSleep, &bLog);
  49. if(FAILED(hres))
  50. return hres;
  51. if(dwSleep)
  52. {
  53. DEBUGTRACE(((char) m_nLog, "Penalty for %d out of %d \n\tof %S (%d members) "
  54. "is %d ms\n", dwMemberTotal, dwNewTotal, (LPCWSTR)m_wsName,
  55. m_dwMembers, dwSleep));
  56. }
  57. // Log a message if required
  58. // =========================
  59. if(bLog)
  60. {
  61. ERRORTRACE(((char) m_nLog, "The limit of %d was exceeded for %S. The system "
  62. "is under extreme stress and out-of-memory conditions can ensue\n",
  63. m_dwMax, (LPCWSTR)m_wsName));
  64. }
  65. // Sleep, if required
  66. // ==================
  67. if(pdwSleep == NULL)
  68. {
  69. if(dwSleep)
  70. Sleep(dwSleep);
  71. }
  72. else
  73. {
  74. // Just return the required amount
  75. // ===============================
  76. *pdwSleep = dwSleep;
  77. }
  78. return hres;
  79. }
  80. HRESULT CMinMaxLimitControl::ComputePenalty(DWORD dwNewTotal,
  81. DWORD dwMemberTotal,
  82. DWORD* pdwSleep, BOOL* pbLog)
  83. {
  84. CInCritSec ics(&m_cs);
  85. *pdwSleep = 0;
  86. *pbLog = FALSE;
  87. if(dwNewTotal > m_dwMin)
  88. {
  89. // Threshold exceeded --- non-zero penalty
  90. // =======================================
  91. // Compute a linear value between 0 and m_dwSleepAtMax
  92. // ===================================================
  93. __int64 i64Temp = (__int64)(dwNewTotal - m_dwMin);
  94. i64Temp *= (__int64)m_dwSleepAtMax;
  95. i64Temp /= (__int64)(m_dwMax - m_dwMin);
  96. // i64Temp is how much we would have to sleep if all queues were
  97. // equal.
  98. // =============================================================
  99. if(dwMemberTotal * m_dwMembers < dwNewTotal)
  100. {
  101. for(int i = 0; i < 2; i++)
  102. {
  103. i64Temp *= (__int64)dwMemberTotal;
  104. i64Temp *= (__int64)m_dwMembers;
  105. i64Temp /= (__int64)dwNewTotal;
  106. }
  107. }
  108. *pdwSleep = (DWORD)i64Temp;
  109. // Check if we have exceeeded m_dwMax
  110. // ==================================
  111. if(dwNewTotal >= m_dwMax)
  112. {
  113. // Max exceeded --- log a message if not already done so
  114. // =====================================================
  115. if(!m_bMessageLogged)
  116. {
  117. *pbLog = TRUE;
  118. m_bMessageLogged = TRUE;
  119. }
  120. return S_FALSE; // to let the caller know that things are bad
  121. }
  122. else
  123. {
  124. return S_OK;
  125. }
  126. }
  127. else
  128. {
  129. // No penalty
  130. // ==========
  131. *pdwSleep = 0;
  132. return S_OK;
  133. }
  134. return S_OK;
  135. }
  136. HRESULT CMinMaxLimitControl::Remove(DWORD dwHowMuch)
  137. {
  138. // Determine if we crossed the critical boundary back.
  139. // ===================================================
  140. BOOL bLog = FALSE;
  141. {
  142. CInCritSec ics(&m_cs);
  143. m_dwCurrentTotal -= dwHowMuch;
  144. if(m_dwCurrentTotal < (m_dwMax * 0.9) && m_bMessageLogged)
  145. {
  146. // We have crossed the boundary
  147. // ============================
  148. bLog = TRUE;
  149. m_bMessageLogged = FALSE;
  150. }
  151. }
  152. // Log the message if required
  153. // ===========================
  154. if(bLog)
  155. {
  156. ERRORTRACE(((char) m_nLog, "%S is back in its normal range: below %d\n",
  157. (LPCWSTR)m_wsName, m_dwMax));
  158. }
  159. return S_OK;
  160. }
  161. HRESULT CRegistryMinMaxLimitControl::Reread()
  162. {
  163. // Open the key
  164. // ============
  165. #ifdef UNICODE
  166. Registry r(m_wsKey);
  167. #else
  168. char *szKey = m_wsKey.GetLPSTR();
  169. CDeleteMe <char>delMe(szKey);
  170. Registry r(szKey);
  171. #endif
  172. if(r.GetLastError())
  173. {
  174. ERRORTRACE(((char) m_nLog, "Unable to open registry key %S to read control "
  175. "information for %S. Error code: %d. Default values will be "
  176. "used\n", (const wchar_t*)m_wsKey, (LPCWSTR)m_wsName, r.GetLastError()));
  177. return WBEM_E_FAILED;
  178. }
  179. // Read the values
  180. // ===============
  181. DWORD dwMin, dwMax, dwSleepAtMax;
  182. #ifdef UNICODE
  183. if(r.GetDWORDStr(m_wsMinValueName, &dwMin) != Registry::no_error)
  184. {
  185. r.SetDWORDStr(m_wsMinValueName, m_dwMin);
  186. dwMin = m_dwMin;
  187. }
  188. #else
  189. char *pStr = m_wsMinValueName.GetLPSTR();
  190. if(r.GetDWORDStr(pStr, &dwMin) != Registry::no_error)
  191. {
  192. r.SetDWORDStr(pStr, m_dwMin);
  193. dwMin = m_dwMin;
  194. }
  195. delete [] pStr;
  196. #endif
  197. #ifdef UNICODE
  198. if(r.GetDWORDStr(m_wsMaxValueName, &dwMax) != Registry::no_error)
  199. {
  200. r.SetDWORDStr(m_wsMaxValueName, m_dwMax);
  201. dwMax = m_dwMax;
  202. }
  203. #else
  204. pStr = m_wsMaxValueName.GetLPSTR();
  205. if(r.GetDWORDStr(pStr, &dwMax) != Registry::no_error)
  206. {
  207. r.SetDWORDStr(pStr, m_dwMax);
  208. dwMax = m_dwMax;
  209. }
  210. delete [] pStr;
  211. #endif
  212. #ifdef UNICODE
  213. if(r.GetDWORDStr(m_wsSleepAtMaxValueName, &dwSleepAtMax) != Registry::no_error)
  214. {
  215. r.SetDWORDStr(m_wsSleepAtMaxValueName, m_dwSleepAtMax);
  216. dwSleepAtMax = m_dwSleepAtMax;
  217. }
  218. #else
  219. pStr = m_wsSleepAtMaxValueName.GetLPSTR();
  220. if(r.GetDWORDStr(pStr, &dwSleepAtMax) != Registry::no_error)
  221. {
  222. r.SetDWORDStr(pStr, m_dwSleepAtMax);
  223. dwSleepAtMax = m_dwSleepAtMax;
  224. }
  225. delete [] pStr;
  226. #endif
  227. // Now store them in the member variables
  228. // ======================================
  229. {
  230. CInCritSec ics(&m_cs);
  231. m_dwMin = dwMin;
  232. m_dwMax = dwMax;
  233. m_dwSleepAtMax = dwSleepAtMax;
  234. }
  235. return WBEM_S_NO_ERROR;
  236. }