/* - PERFAPP.CPP - * Purpose: * Implements the GLOBCNTR object used by Apps to initialize, update, * and deinitialize the PerfMon counters. * * * References: * */ #include #include #include #include #include #include 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; }