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.
488 lines
11 KiB
488 lines
11 KiB
/*
|
|
- PERFAPP.CPP
|
|
-
|
|
* Purpose:
|
|
* Implements the GLOBCNTR object used by Apps to initialize, update,
|
|
* and deinitialize the PerfMon counters.
|
|
*
|
|
*
|
|
* References:
|
|
*
|
|
|
|
*/
|
|
#include <windows.h>
|
|
#include <winperf.h>
|
|
#include <winerror.h>
|
|
|
|
#include <perfutil.h>
|
|
#include <perfapp.h>
|
|
#include <tchar.h>
|
|
|
|
|
|
static const DWORD g_cMaxInst = 128;
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Prototypes
|
|
// ---------------------------------------------------------------------------
|
|
static HRESULT HrLogEvent(HANDLE hEventLog, WORD wType, DWORD msgid);
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// GLOBCNTR methods
|
|
//-----------------------------------------------------------------------------
|
|
|
|
HRESULT
|
|
GLOBCNTR::HrInit(GLOBAL_CNTR cCounters, LPWSTR szGlobalSMName, LPWSTR szSvcName)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HANDLE hEventLog = NULL;
|
|
BOOL fExist;
|
|
|
|
if (0 == cCounters ||
|
|
NULL == szGlobalSMName ||
|
|
NULL == szSvcName ||
|
|
128 < cCounters ) //We should not have more than 128 counters
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if (m_fInit)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
|
|
m_cCounters = cCounters;
|
|
|
|
hEventLog = RegisterEventSource(NULL, szSvcName);
|
|
|
|
// This must be called before any calls to HrOpenSharedMemory()
|
|
|
|
hr = HrInitializeSecurityAttribute(&m_sa);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
goto ret;
|
|
}
|
|
|
|
// Open shared memory to the process wide Perf Counters. Our member
|
|
// variable m_ppc will be mapped onto this address space and counters are
|
|
// simply indexes into this address space.
|
|
|
|
hr = HrOpenSharedMemory(szGlobalSMName,
|
|
(sizeof(DWORD) * m_cCounters),
|
|
&m_sa,
|
|
&m_hsm,
|
|
(LPVOID *) &m_rgdwPerfData,
|
|
&fExist);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
goto ret;
|
|
}
|
|
|
|
ZeroMemory(m_rgdwPerfData, (sizeof(DWORD) * m_cCounters));
|
|
|
|
// Open for business!
|
|
m_fInit = TRUE;
|
|
|
|
ret:
|
|
if (hEventLog)
|
|
DeregisterEventSource(hEventLog);
|
|
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*
|
|
- Shutdown
|
|
-
|
|
* Purpose:
|
|
* Cleanup and shutdown the GLOBCNTR object
|
|
*/
|
|
|
|
void
|
|
GLOBCNTR::Shutdown(void)
|
|
{
|
|
if (m_fInit)
|
|
{
|
|
m_fInit = FALSE;
|
|
|
|
if (m_rgdwPerfData)
|
|
{
|
|
// Set all counters to zero at shutdown time
|
|
|
|
ZeroMemory(m_rgdwPerfData, (sizeof(DWORD) * m_cCounters));
|
|
|
|
UnmapViewOfFile(m_rgdwPerfData);
|
|
m_rgdwPerfData = NULL;
|
|
}
|
|
|
|
if (m_hsm)
|
|
{
|
|
CloseHandle(m_hsm);
|
|
m_hsm = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// INSTCNTR methods
|
|
//-----------------------------------------------------------------------------
|
|
|
|
/*
|
|
- Destructor
|
|
-
|
|
* Purpose:
|
|
* Object cleanup & verify consistency
|
|
*/
|
|
|
|
INSTCNTR::~INSTCNTR()
|
|
{
|
|
if(m_sa.lpSecurityDescriptor)
|
|
LocalFree(m_sa.lpSecurityDescriptor);
|
|
}
|
|
|
|
/*
|
|
- HrInit
|
|
-
|
|
* Purpose:
|
|
* Setup shared memory blocks
|
|
* Prep Admin & Counter blocks for use
|
|
*/
|
|
|
|
HRESULT
|
|
INSTCNTR::HrInit(INST_CNTR cCounters,
|
|
LPWSTR szInstSMName,
|
|
LPWSTR szInstMutexName,
|
|
LPWSTR szSvcName)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DWORD cbAdm = 0;
|
|
DWORD cbCntr = 0;
|
|
WCHAR szAdmName[MAX_PATH]; // Admin SM Name
|
|
WCHAR szCntrName[MAX_PATH]; // Counter SM Name
|
|
LPVOID pv;
|
|
HANDLE hEventLog;
|
|
BOOL fExist;
|
|
BOOL fInMutex = FALSE;
|
|
|
|
// Validate args
|
|
if (0 == cCounters || !szInstSMName || !szInstMutexName || !szSvcName)
|
|
return E_INVALIDARG;
|
|
|
|
// Save Number of Counters
|
|
m_cCounters = cCounters;
|
|
|
|
if (m_fInit)
|
|
{
|
|
return E_FAIL;
|
|
}
|
|
|
|
// Open Application Event Log
|
|
hEventLog = RegisterEventSource(NULL, szSvcName);
|
|
|
|
// This must be called before any calls to HrOpenSharedMemory() and
|
|
// HrCreatePerfMutex() and must only be called once!!!
|
|
|
|
hr = HrInitializeSecurityAttribute(&m_sa);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
goto ret;
|
|
}
|
|
|
|
// Obtain Mutex. If call returns okay, we hold the mutex.
|
|
hr = HrCreatePerfMutex(&m_sa, szInstMutexName, &m_hmtx);
|
|
if (FAILED(hr))
|
|
{
|
|
goto ret;
|
|
}
|
|
|
|
fInMutex = TRUE;
|
|
|
|
// Calc required memory sizes
|
|
cbAdm = sizeof(INSTCNTR_DATA) + (sizeof(INSTREC) * g_cMaxInst);
|
|
cbCntr = ((sizeof(DWORD) * cCounters) * g_cMaxInst);
|
|
|
|
// Build names for the two shared memory blocks
|
|
if(wcslen(szInstSMName) >= (MAX_PATH - 6)) // Enough space to wsprintf.
|
|
{
|
|
hr=E_FAIL;
|
|
goto ret;
|
|
}
|
|
wsprintf(szAdmName, L"%s_ADM", szInstSMName);
|
|
wsprintf(szCntrName,L"%s_CNTR", szInstSMName);
|
|
|
|
// Open Admin Shared Memory Block
|
|
hr = HrOpenSharedMemory(szAdmName,
|
|
cbAdm,
|
|
&m_sa,
|
|
&m_hsmAdm,
|
|
(LPVOID *) &pv,
|
|
&fExist);
|
|
if (FAILED(hr))
|
|
{
|
|
goto ret;
|
|
}
|
|
|
|
|
|
// Fixup Pointers
|
|
m_picd = (INSTCNTR_DATA *) pv;
|
|
m_rgInstRec = (INSTREC *) ((char *) pv + sizeof(INSTCNTR_DATA));
|
|
|
|
|
|
if (!fExist)
|
|
{
|
|
ZeroMemory(pv, cbAdm);
|
|
m_picd->cMaxInstRec = g_cMaxInst;
|
|
m_picd->cInstRecInUse = 0;
|
|
}
|
|
|
|
// Open Counters Shared Memory Block
|
|
hr = HrOpenSharedMemory(szCntrName,
|
|
cbCntr,
|
|
&m_sa,
|
|
&m_hsmCntr,
|
|
(LPVOID *) &m_rgdwCntr,
|
|
&fExist);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
goto ret;
|
|
}
|
|
|
|
|
|
if ( !fExist)
|
|
{
|
|
ZeroMemory(m_rgdwCntr, cbCntr);
|
|
}
|
|
|
|
// Open for business!
|
|
m_fInit = TRUE;
|
|
|
|
ret:
|
|
|
|
if (hEventLog)
|
|
DeregisterEventSource(hEventLog);
|
|
|
|
|
|
if (m_hmtx && fInMutex)
|
|
ReleaseMutex(m_hmtx);
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*
|
|
- Shutdown
|
|
-
|
|
* Purpose:
|
|
* Cleanup and shutdown the INSTCNTR object
|
|
*/
|
|
|
|
void
|
|
INSTCNTR::Shutdown(BOOL fWipeOut)
|
|
{
|
|
if (m_fInit)
|
|
{
|
|
m_fInit = FALSE;
|
|
|
|
if (m_rgdwCntr)
|
|
{
|
|
// Zero out this shared memory block too. All counters should
|
|
// start at zero.
|
|
if ( fWipeOut )
|
|
{
|
|
ZeroMemory(m_rgdwCntr, (sizeof(DWORD) * m_cCounters) * g_cMaxInst);
|
|
}
|
|
UnmapViewOfFile(m_rgdwCntr);
|
|
m_rgdwCntr = NULL;
|
|
}
|
|
|
|
// NOTE: m_picd points at the head of the
|
|
// Admin shared memory block. Do not UnmapViewOfFile on
|
|
// the m_rgInstRec pointer!
|
|
if (m_picd)
|
|
{
|
|
// Zero out the shared memory block
|
|
if ( fWipeOut )
|
|
{
|
|
ZeroMemory(m_picd, sizeof(INSTCNTR_DATA) + (sizeof(INSTREC) * g_cMaxInst));
|
|
m_picd->cMaxInstRec = g_cMaxInst;
|
|
m_picd->cInstRecInUse = 0;
|
|
}
|
|
UnmapViewOfFile(m_picd);
|
|
m_picd = NULL;
|
|
m_rgInstRec = NULL;
|
|
}
|
|
|
|
if (m_hsmAdm)
|
|
{
|
|
CloseHandle(m_hsmAdm);
|
|
m_hsmAdm = NULL;
|
|
}
|
|
|
|
if (m_hsmCntr)
|
|
{
|
|
|
|
CloseHandle(m_hsmCntr);
|
|
m_hsmCntr = NULL;
|
|
}
|
|
|
|
if (m_hmtx)
|
|
{
|
|
CloseHandle(m_hmtx);
|
|
m_hmtx = NULL;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
- HrCreateOrGetInstance
|
|
-
|
|
* Purpose:
|
|
* Return a token corresponding to an Instance Counter Block
|
|
* Returns:
|
|
* S_OK ID Found; picid contains a valid INSTCNTR_ID
|
|
* E_FAIL Object not initialized *OR* ID not found
|
|
* E_INVALIDARG Bad parameter/NULL pointer
|
|
*/
|
|
|
|
HRESULT
|
|
INSTCNTR::HrCreateOrGetInstance(LPCWSTR wszInstName, INSTCNTR_ID *picid)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (!m_fInit)
|
|
return E_FAIL;
|
|
|
|
// Validate args
|
|
if (!picid || !wszInstName)
|
|
return E_INVALIDARG;
|
|
|
|
*picid = INVALID_INST_ID;
|
|
|
|
// Obtain exclusive access to SM blocks
|
|
DWORD dwWait = WaitForSingleObject(m_hmtx, INFINITE);
|
|
if (WAIT_OBJECT_0 != dwWait)
|
|
{
|
|
// No simple way to translate the return into an HRESULT
|
|
return E_FAIL;
|
|
}
|
|
|
|
// We have the mutex; we must release before leaving
|
|
|
|
// Linear probe through list looking for a matching or open slot
|
|
for (unsigned int i = 0; i < m_picd->cMaxInstRec; i++)
|
|
{
|
|
if ( m_rgInstRec[i].fInUse && (0 == wcscmp(m_rgInstRec[i].szInstName, wszInstName)) )
|
|
{
|
|
// Found first instance with matching name.
|
|
*picid = (INSTCNTR_ID) i;
|
|
break;
|
|
}
|
|
else if (!m_rgInstRec[i].fInUse && (INVALID_INST_ID == *picid))
|
|
{
|
|
// Found the first free slot -- remember its number
|
|
*picid = (INSTCNTR_ID) i;
|
|
}
|
|
}
|
|
|
|
if (INVALID_INST_ID == *picid)
|
|
{
|
|
// No matching or free slots found
|
|
hr = E_FAIL;
|
|
goto Cleanup;
|
|
}
|
|
else if (!m_rgInstRec[*picid].fInUse)
|
|
{
|
|
// Found no matching slot, but found a free slot -- mark as
|
|
// in use and set instance name
|
|
wcsncpy(m_rgInstRec[*picid].szInstName, wszInstName, min((wcslen(wszInstName) + 1),MAX_PATH));
|
|
m_rgInstRec[*picid].fInUse = TRUE;
|
|
m_picd->cInstRecInUse++;
|
|
|
|
// Zero out corresponding counter block
|
|
ZeroMemory(&m_rgdwCntr[(m_cCounters * (*picid))], (sizeof(DWORD) * m_cCounters));
|
|
}
|
|
|
|
Cleanup:
|
|
ReleaseMutex(m_hmtx);
|
|
|
|
return hr;
|
|
}
|
|
|
|
/*
|
|
- HrDestroyInstance
|
|
-
|
|
* Purpose:
|
|
* Release Instance Counter Block associated with the token icid.
|
|
*/
|
|
|
|
HRESULT
|
|
INSTCNTR::HrDestroyInstance(INSTCNTR_ID icid)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
if (!m_fInit)
|
|
return E_FAIL;
|
|
|
|
// Get exclusive access to SM blocks
|
|
DWORD dwWait = WaitForSingleObject(m_hmtx, INFINITE);
|
|
if (WAIT_OBJECT_0 != dwWait)
|
|
{
|
|
// No simple way to translate the return into an HRESULT
|
|
return E_FAIL;
|
|
}
|
|
|
|
|
|
if (m_rgInstRec[icid].fInUse)
|
|
{
|
|
// Mark the block as Not In Use
|
|
m_rgInstRec[icid].fInUse = FALSE;
|
|
|
|
// Zero out corresponding counter block
|
|
ZeroMemory(&m_rgdwCntr[(m_cCounters * (icid))], (sizeof(DWORD) * m_cCounters));
|
|
|
|
//Assert(m_picd->cInstRecInUse != 0);
|
|
m_picd->cInstRecInUse--;
|
|
} else
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
ReleaseMutex(m_hmtx);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/*
|
|
- HrLogEvent
|
|
-
|
|
* Purpose:
|
|
* Wrap up the call to ReportEvent to make things look nicer.
|
|
*/
|
|
HRESULT
|
|
HrLogEvent(HANDLE hEventLog, WORD wType, DWORD msgid)
|
|
{
|
|
if (hEventLog)
|
|
return ReportEvent(hEventLog,
|
|
wType,
|
|
(WORD)0,//facPerfMonDll,
|
|
msgid,
|
|
NULL,
|
|
0,
|
|
0,
|
|
NULL,
|
|
NULL);
|
|
|
|
else
|
|
return E_FAIL;
|
|
}
|
|
|
|
|