windows-nt/Source/XPSP1/NT/admin/wmi/wbem/winmgmt/wbemcomn/sleeper.cpp
2020-09-26 16:20:57 +08:00

298 lines
6.7 KiB
C++

/*++
Copyright (C) 1996-2001 Microsoft Corporation
Module Name:
SLEEPER.CPP
Abstract:
MinMax controls.
History:
--*/
#include "precomp.h"
#include <stdio.h>
#include <wbemcomn.h>
#include "sleeper.h"
CLimitControl::CLimitControl()
: m_dwMembers(0)
{
}
HRESULT CLimitControl::AddMember()
{
InterlockedIncrement((long*)&m_dwMembers);
return S_OK;
}
HRESULT CLimitControl::RemoveMember()
{
InterlockedDecrement((long*)&m_dwMembers);
return S_OK;
}
CMinMaxLimitControl::CMinMaxLimitControl(int nLog, LPCWSTR wszName)
: m_dwMin(10000000), m_dwMax(20000000), m_dwSleepAtMax(60000),
m_nLog(nLog), m_wsName(wszName), m_dwCurrentTotal(0),
m_bMessageLogged(FALSE)
{
}
HRESULT CMinMaxLimitControl::Add(DWORD dwHowMuch, DWORD dwMemberTotal,
DWORD* pdwSleep)
{
// Add amount to the total
// =======================
DWORD dwNewTotal;
{
CInCritSec ics(&m_cs);
m_dwCurrentTotal += dwHowMuch;
dwNewTotal = m_dwCurrentTotal;
}
// Calculate the penalty
// =====================
DWORD dwSleep = 0;
BOOL bLog = TRUE;
HRESULT hres = ComputePenalty(dwNewTotal, dwMemberTotal, &dwSleep, &bLog);
if(FAILED(hres))
return hres;
if(dwSleep)
{
DEBUGTRACE(((char) m_nLog, "Penalty for %d out of %d \n\tof %S (%d members) "
"is %d ms\n", dwMemberTotal, dwNewTotal, (LPCWSTR)m_wsName,
m_dwMembers, dwSleep));
}
// Log a message if required
// =========================
if(bLog)
{
ERRORTRACE(((char) m_nLog, "The limit of %d was exceeded for %S. The system "
"is under extreme stress and out-of-memory conditions can ensue\n",
m_dwMax, (LPCWSTR)m_wsName));
}
// Sleep, if required
// ==================
if(pdwSleep == NULL)
{
if(dwSleep)
Sleep(dwSleep);
}
else
{
// Just return the required amount
// ===============================
*pdwSleep = dwSleep;
}
return hres;
}
HRESULT CMinMaxLimitControl::ComputePenalty(DWORD dwNewTotal,
DWORD dwMemberTotal,
DWORD* pdwSleep, BOOL* pbLog)
{
CInCritSec ics(&m_cs);
*pdwSleep = 0;
*pbLog = FALSE;
if(dwNewTotal > m_dwMin)
{
// Threshold exceeded --- non-zero penalty
// =======================================
// Compute a linear value between 0 and m_dwSleepAtMax
// ===================================================
__int64 i64Temp = (__int64)(dwNewTotal - m_dwMin);
i64Temp *= (__int64)m_dwSleepAtMax;
i64Temp /= (__int64)(m_dwMax - m_dwMin);
// i64Temp is how much we would have to sleep if all queues were
// equal.
// =============================================================
if(dwMemberTotal * m_dwMembers < dwNewTotal)
{
for(int i = 0; i < 2; i++)
{
i64Temp *= (__int64)dwMemberTotal;
i64Temp *= (__int64)m_dwMembers;
i64Temp /= (__int64)dwNewTotal;
}
}
*pdwSleep = (DWORD)i64Temp;
// Check if we have exceeeded m_dwMax
// ==================================
if(dwNewTotal >= m_dwMax)
{
// Max exceeded --- log a message if not already done so
// =====================================================
if(!m_bMessageLogged)
{
*pbLog = TRUE;
m_bMessageLogged = TRUE;
}
return S_FALSE; // to let the caller know that things are bad
}
else
{
return S_OK;
}
}
else
{
// No penalty
// ==========
*pdwSleep = 0;
return S_OK;
}
return S_OK;
}
HRESULT CMinMaxLimitControl::Remove(DWORD dwHowMuch)
{
// Determine if we crossed the critical boundary back.
// ===================================================
BOOL bLog = FALSE;
{
CInCritSec ics(&m_cs);
m_dwCurrentTotal -= dwHowMuch;
if(m_dwCurrentTotal < (m_dwMax * 0.9) && m_bMessageLogged)
{
// We have crossed the boundary
// ============================
bLog = TRUE;
m_bMessageLogged = FALSE;
}
}
// Log the message if required
// ===========================
if(bLog)
{
ERRORTRACE(((char) m_nLog, "%S is back in its normal range: below %d\n",
(LPCWSTR)m_wsName, m_dwMax));
}
return S_OK;
}
HRESULT CRegistryMinMaxLimitControl::Reread()
{
// Open the key
// ============
#ifdef UNICODE
Registry r(m_wsKey);
#else
char *szKey = m_wsKey.GetLPSTR();
CDeleteMe <char>delMe(szKey);
Registry r(szKey);
#endif
if(r.GetLastError())
{
ERRORTRACE(((char) m_nLog, "Unable to open registry key %S to read control "
"information for %S. Error code: %d. Default values will be "
"used\n", (const wchar_t*)m_wsKey, (LPCWSTR)m_wsName, r.GetLastError()));
return WBEM_E_FAILED;
}
// Read the values
// ===============
DWORD dwMin, dwMax, dwSleepAtMax;
#ifdef UNICODE
if(r.GetDWORDStr(m_wsMinValueName, &dwMin) != Registry::no_error)
{
r.SetDWORDStr(m_wsMinValueName, m_dwMin);
dwMin = m_dwMin;
}
#else
char *pStr = m_wsMinValueName.GetLPSTR();
if(r.GetDWORDStr(pStr, &dwMin) != Registry::no_error)
{
r.SetDWORDStr(pStr, m_dwMin);
dwMin = m_dwMin;
}
delete [] pStr;
#endif
#ifdef UNICODE
if(r.GetDWORDStr(m_wsMaxValueName, &dwMax) != Registry::no_error)
{
r.SetDWORDStr(m_wsMaxValueName, m_dwMax);
dwMax = m_dwMax;
}
#else
pStr = m_wsMaxValueName.GetLPSTR();
if(r.GetDWORDStr(pStr, &dwMax) != Registry::no_error)
{
r.SetDWORDStr(pStr, m_dwMax);
dwMax = m_dwMax;
}
delete [] pStr;
#endif
#ifdef UNICODE
if(r.GetDWORDStr(m_wsSleepAtMaxValueName, &dwSleepAtMax) != Registry::no_error)
{
r.SetDWORDStr(m_wsSleepAtMaxValueName, m_dwSleepAtMax);
dwSleepAtMax = m_dwSleepAtMax;
}
#else
pStr = m_wsSleepAtMaxValueName.GetLPSTR();
if(r.GetDWORDStr(pStr, &dwSleepAtMax) != Registry::no_error)
{
r.SetDWORDStr(pStr, m_dwSleepAtMax);
dwSleepAtMax = m_dwSleepAtMax;
}
delete [] pStr;
#endif
// Now store them in the member variables
// ======================================
{
CInCritSec ics(&m_cs);
m_dwMin = dwMin;
m_dwMax = dwMax;
m_dwSleepAtMax = dwSleepAtMax;
}
return WBEM_S_NO_ERROR;
}