mirror of https://github.com/tongzx/nt5src
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.
525 lines
17 KiB
525 lines
17 KiB
/*==========================================================================
|
|
*
|
|
* Copyright (C) 1999 - 2000 Microsoft Corporation. All Rights Reserved.
|
|
*
|
|
* File: perfinfo.h
|
|
* Content: Performance tracking related code
|
|
*
|
|
* History:
|
|
* Date By Reason
|
|
* ==== == ======
|
|
* ??-??-???? rodtoll Created
|
|
* 12-12-2000 rodtoll Re-organize performance struct to handle data misalignment errors on IA64
|
|
*
|
|
***************************************************************************/
|
|
|
|
#include "dncmni.h"
|
|
#include "PerfInfo.h"
|
|
#include <initguid.h>
|
|
|
|
// Name of block
|
|
#define PERF_INSTANCE_BLOCK_NAME "{F10932E0-2556-4620-9ADE-F572406CFAEA}"
|
|
|
|
// GUID of block
|
|
DEFINE_GUID(PERF_INSTANCE_BLOCK_GUID,
|
|
0xf10932e0, 0x2556, 0x4620, 0x9a, 0xde, 0xf5, 0x72, 0x40, 0x6c, 0xfa, 0xea);
|
|
|
|
#define PERF_INSTANCE_BLOCK_MUTEX_NAME "{2997F0C7-F135-405f-ABD4-8BAF491B3DAD}"
|
|
|
|
DEFINE_GUID(PERF_INSTANCE_BLOCK_MUTEX_GUID,
|
|
0x2997f0c7, 0xf135, 0x405f, 0xab, 0xd4, 0x8b, 0xaf, 0x49, 0x1b, 0x3d, 0xad);
|
|
|
|
HANDLE g_hMutexInstanceBlock = NULL;
|
|
HANDLE g_hFileInstanceBlock = NULL;
|
|
BYTE *g_pbInstanceBlock = NULL;
|
|
PPERF_HEADER g_pperfHeader = NULL;
|
|
LONG *g_plNumEntries = NULL;
|
|
PPERF_APPLICATION g_pperfAppEntries = NULL;
|
|
|
|
#define PERF_INSTANCE_BLOCK_MAXENTRIES 100
|
|
#define PERF_INSTANCE_BLOCK_SIZE ((sizeof( PERF_APPLICATION ) * PERF_INSTANCE_BLOCK_MAXENTRIES) + sizeof( PERF_HEADER ))
|
|
#define PERF_INFO_NAME_LENGTH 64 // 38 for GUID string + room for Global prefix and mutex suffix
|
|
|
|
void PERF_Coalesce( DWORD dwProcessID = 0xFFFFFFFF );
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "PERF_Initialize"
|
|
// PERF_Initialize
|
|
//
|
|
// Initialize the global "instance" list memory block
|
|
//
|
|
HRESULT PERF_Initialize( )
|
|
{
|
|
HRESULT hr = S_OK;
|
|
BOOL fAlreadyExists = FALSE;
|
|
|
|
|
|
if (DNGetOSType() == VER_PLATFORM_WIN32_NT)
|
|
{
|
|
g_hMutexInstanceBlock = CreateMutexA( DNGetNullDacl(), FALSE, "Global\\" PERF_INSTANCE_BLOCK_MUTEX_NAME );
|
|
}
|
|
else
|
|
{
|
|
g_hMutexInstanceBlock = CreateMutexA( DNGetNullDacl(), FALSE, PERF_INSTANCE_BLOCK_MUTEX_NAME );
|
|
}
|
|
|
|
if( g_hMutexInstanceBlock == NULL )
|
|
{
|
|
hr = GetLastError();
|
|
DPFX(DPFPREP, 0, "Error initializing instance block hr=0x%x", hr );
|
|
goto EXIT_ERROR;
|
|
}
|
|
|
|
if (DNGetOSType() == VER_PLATFORM_WIN32_NT)
|
|
{
|
|
g_hFileInstanceBlock = CreateFileMappingA(INVALID_HANDLE_VALUE,
|
|
DNGetNullDacl(),
|
|
PAGE_READWRITE,
|
|
0,
|
|
PERF_INSTANCE_BLOCK_SIZE,
|
|
"Global\\" PERF_INSTANCE_BLOCK_NAME);
|
|
}
|
|
else
|
|
{
|
|
g_hFileInstanceBlock = CreateFileMappingA(INVALID_HANDLE_VALUE,
|
|
DNGetNullDacl(),
|
|
PAGE_READWRITE,
|
|
0,
|
|
PERF_INSTANCE_BLOCK_SIZE,
|
|
PERF_INSTANCE_BLOCK_NAME);
|
|
}
|
|
if (g_hFileInstanceBlock == NULL)
|
|
{
|
|
hr = GetLastError();
|
|
DPFX(DPFPREP, 0, "CreateFileMapping() failed hr=0x%x", hr);
|
|
goto EXIT_ERROR;
|
|
}
|
|
|
|
if (GetLastError() == ERROR_ALREADY_EXISTS)
|
|
{
|
|
fAlreadyExists = TRUE;
|
|
}
|
|
|
|
// Map file
|
|
g_pbInstanceBlock = reinterpret_cast<BYTE*>(MapViewOfFile(g_hFileInstanceBlock,FILE_MAP_ALL_ACCESS,0,0,0));
|
|
if (g_pbInstanceBlock == NULL)
|
|
{
|
|
hr = GetLastError();
|
|
DPFX(DPFPREP, 0,"MapViewOfFile() failed");
|
|
goto EXIT_ERROR;
|
|
}
|
|
|
|
g_pperfHeader = (PPERF_HEADER) g_pbInstanceBlock;
|
|
|
|
g_plNumEntries = &g_pperfHeader->lNumEntries;
|
|
g_pperfAppEntries = (PPERF_APPLICATION) &g_pperfHeader[1];
|
|
|
|
// Access to entry count is protected by interlocked exchange
|
|
if( !fAlreadyExists )
|
|
{
|
|
// Wait for the mutex to enter the block
|
|
WaitForSingleObject( g_hMutexInstanceBlock, INFINITE );
|
|
|
|
*g_plNumEntries = 0;
|
|
|
|
// Zero the memory in the block
|
|
ZeroMemory( g_pbInstanceBlock, PERF_INSTANCE_BLOCK_SIZE );
|
|
|
|
ReleaseMutex( g_hMutexInstanceBlock );
|
|
}
|
|
else
|
|
{
|
|
PERF_Coalesce();
|
|
}
|
|
|
|
return hr;
|
|
|
|
EXIT_ERROR:
|
|
|
|
if( g_pbInstanceBlock )
|
|
{
|
|
UnmapViewOfFile(g_pbInstanceBlock);
|
|
g_pbInstanceBlock = NULL;
|
|
}
|
|
|
|
if( g_hFileInstanceBlock )
|
|
{
|
|
CloseHandle( g_hFileInstanceBlock );
|
|
g_hFileInstanceBlock = NULL;
|
|
}
|
|
|
|
if( g_hMutexInstanceBlock )
|
|
{
|
|
CloseHandle( g_hMutexInstanceBlock );
|
|
g_hMutexInstanceBlock = NULL;
|
|
}
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "PERF_CleanupEntry"
|
|
// PERF_CleanupEntry
|
|
//
|
|
// Cleanup global memory block for the entry
|
|
//
|
|
void PERF_CleanupEntry( PPERF_APPLICATION pperfApplication, PPERF_APPLICATION_INFO pperfApplicationInfo )
|
|
{
|
|
if( pperfApplication->dwFlags & PERF_APPLICATION_VALID )
|
|
{
|
|
// This entry belongs to this process
|
|
if( pperfApplicationInfo )
|
|
{
|
|
if( pperfApplicationInfo->pbMemoryBlock )
|
|
{
|
|
UnmapViewOfFile( pperfApplicationInfo->pbMemoryBlock );
|
|
}
|
|
|
|
if( pperfApplicationInfo->hFileMap )
|
|
{
|
|
CloseHandle( pperfApplicationInfo->hFileMap );
|
|
}
|
|
}
|
|
|
|
ZeroMemory( pperfApplication, sizeof( PERF_APPLICATION ) );
|
|
|
|
(*g_plNumEntries)--;
|
|
}
|
|
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "PERF_Coalesce"
|
|
// PERF_Coalesce
|
|
//
|
|
// Several routines run this function, the purpose is to run the list of processes
|
|
// and remove dead processes from the list.
|
|
//
|
|
// WARNING: You must have the mutex when you enter this function
|
|
//
|
|
// Should be called when adding entries or reading entries.
|
|
//
|
|
// If called with a valid process ID then all entries for that process are removed
|
|
//
|
|
void PERF_Coalesce( DWORD dwProcessID )
|
|
{
|
|
if( !g_pbInstanceBlock )
|
|
return;
|
|
|
|
HANDLE hProcess;
|
|
|
|
for( LONG lIndex = 0; lIndex < PERF_INSTANCE_BLOCK_MAXENTRIES; lIndex++ )
|
|
{
|
|
if( g_pperfAppEntries[lIndex].dwFlags & PERF_APPLICATION_VALID )
|
|
{
|
|
if( dwProcessID != 0xFFFFFFFF )
|
|
{
|
|
if( g_pperfAppEntries[lIndex].dwProcessID == dwProcessID )
|
|
PERF_CleanupEntry( &g_pperfAppEntries[lIndex], NULL );
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
hProcess = OpenProcess( PROCESS_DUP_HANDLE, FALSE, (DWORD) g_pperfAppEntries[lIndex].dwProcessID );
|
|
|
|
// Check for process existance -- if it exists then leave entry, otherwise leave
|
|
if( !hProcess )
|
|
PERF_CleanupEntry( &g_pperfAppEntries[lIndex], NULL);
|
|
else
|
|
CloseHandle( hProcess );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "PERF_AddEntry"
|
|
// PERF_AddEntry
|
|
//
|
|
// Requests the application be given a statistics block. If succesful a memory block is allocated of the given size and
|
|
// an entry is added to the central memory block. The format of the datablock is application defined.
|
|
//
|
|
// Parameters for the entry to be created are specified in pperfApplication. All entries in this structure should be
|
|
// initialized except for dwProcessID which will be filled in by the system.
|
|
//
|
|
// This function will fill the specified pperfApplicationInfo structure with information about the entry that was
|
|
// created. This structure should be stored because it is needed in the call to PERF_RemoveEntry.
|
|
//
|
|
HRESULT PERF_AddEntry( PPERF_APPLICATION pperfApplication, PPERF_APPLICATION_INFO pperfApplicationInfo )
|
|
{
|
|
if( !g_pbInstanceBlock )
|
|
return S_OK;
|
|
|
|
// Zero the pperfApplicationInfo structture so in case of error it can be cleaned up properly
|
|
ZeroMemory( pperfApplicationInfo, sizeof( PERF_APPLICATION_INFO ) );
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
// We need the mutex to access the block
|
|
WaitForSingleObject( g_hMutexInstanceBlock, INFINITE );
|
|
|
|
// Remove dead entries
|
|
PERF_Coalesce();
|
|
|
|
if( *g_plNumEntries >= PERF_INSTANCE_BLOCK_MAXENTRIES )
|
|
{
|
|
DPFX(DPFPREP, 0, "Instance block is full!" );
|
|
hr = E_FAIL;
|
|
ReleaseMutex( g_hMutexInstanceBlock );
|
|
return hr;
|
|
}
|
|
|
|
for( LONG lIndex = 0; lIndex < PERF_INSTANCE_BLOCK_MAXENTRIES; lIndex++ )
|
|
{
|
|
// We've found a slot
|
|
if( !(g_pperfAppEntries[lIndex].dwFlags & PERF_APPLICATION_VALID) )
|
|
{
|
|
DPFX(DPFPREP, 0, "Placing entry in index %i, pid=0x%x, flags=0x%x", lIndex, pperfApplication->dwProcessID, pperfApplication->dwFlags );
|
|
memcpy( &g_pperfAppEntries[lIndex], pperfApplication, sizeof( PERF_APPLICATION ) );
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Instance block is full -- wow. Shouldn't happen -- afterall we checked above.
|
|
if( lIndex == PERF_INSTANCE_BLOCK_MAXENTRIES )
|
|
{
|
|
// This should not happen, we have mutex AND checked entry count
|
|
DNASSERT( FALSE );
|
|
DPFX(DPFPREP, 0, "Unable to find an entry in the list" );
|
|
hr = E_FAIL;
|
|
ReleaseMutex( g_hMutexInstanceBlock );
|
|
return hr;
|
|
}
|
|
|
|
char szNameBuffer[PERF_INFO_NAME_LENGTH];
|
|
|
|
// Build name for shared memory block
|
|
if (DNGetOSType() == VER_PLATFORM_WIN32_NT)
|
|
{
|
|
wsprintfA( szNameBuffer, "Global\\{%-08.8X-%-04.4X-%-04.4X-%02.2X%02.2X-%02.2X%02.2X%02.2X%02.2X%02.2X%02.2X}",
|
|
g_pperfAppEntries[lIndex].guidInternalInstance.Data1, g_pperfAppEntries[lIndex].guidInternalInstance.Data2,
|
|
g_pperfAppEntries[lIndex].guidInternalInstance.Data3, g_pperfAppEntries[lIndex].guidInternalInstance.Data4[0],
|
|
g_pperfAppEntries[lIndex].guidInternalInstance.Data4[1], g_pperfAppEntries[lIndex].guidInternalInstance.Data4[2],
|
|
g_pperfAppEntries[lIndex].guidInternalInstance.Data4[3], g_pperfAppEntries[lIndex].guidInternalInstance.Data4[4],
|
|
g_pperfAppEntries[lIndex].guidInternalInstance.Data4[5], g_pperfAppEntries[lIndex].guidInternalInstance.Data4[6],
|
|
g_pperfAppEntries[lIndex].guidInternalInstance.Data4[7] );
|
|
}
|
|
else
|
|
{
|
|
wsprintfA( szNameBuffer, "{%-08.8X-%-04.4X-%-04.4X-%02.2X%02.2X-%02.2X%02.2X%02.2X%02.2X%02.2X%02.2X}",
|
|
g_pperfAppEntries[lIndex].guidInternalInstance.Data1, g_pperfAppEntries[lIndex].guidInternalInstance.Data2,
|
|
g_pperfAppEntries[lIndex].guidInternalInstance.Data3, g_pperfAppEntries[lIndex].guidInternalInstance.Data4[0],
|
|
g_pperfAppEntries[lIndex].guidInternalInstance.Data4[1], g_pperfAppEntries[lIndex].guidInternalInstance.Data4[2],
|
|
g_pperfAppEntries[lIndex].guidInternalInstance.Data4[3], g_pperfAppEntries[lIndex].guidInternalInstance.Data4[4],
|
|
g_pperfAppEntries[lIndex].guidInternalInstance.Data4[5], g_pperfAppEntries[lIndex].guidInternalInstance.Data4[6],
|
|
g_pperfAppEntries[lIndex].guidInternalInstance.Data4[7] );
|
|
}
|
|
|
|
// Create file mapping for memory block
|
|
pperfApplicationInfo->hFileMap = CreateFileMappingA(INVALID_HANDLE_VALUE,
|
|
DNGetNullDacl(),
|
|
PAGE_READWRITE,
|
|
0,
|
|
pperfApplication->dwMemoryBlockSize,
|
|
szNameBuffer);
|
|
if (pperfApplicationInfo->hFileMap == NULL)
|
|
{
|
|
hr = GetLastError();
|
|
DPFX(DPFPREP, 0, "CreateFileMapping() failed hr=0x%x", hr);
|
|
goto EXIT_ERROR;
|
|
}
|
|
|
|
// Create the shared memory block
|
|
pperfApplicationInfo->pbMemoryBlock = reinterpret_cast<BYTE*>(MapViewOfFile(pperfApplicationInfo->hFileMap,FILE_MAP_ALL_ACCESS,0,0,0));
|
|
|
|
if (pperfApplicationInfo->pbMemoryBlock == NULL)
|
|
{
|
|
hr = GetLastError();
|
|
DPFX(DPFPREP, 0,"MapViewOfFile() failed hr=0x%x", hr);
|
|
goto EXIT_ERROR;
|
|
}
|
|
|
|
strcat( szNameBuffer, "_M" );
|
|
|
|
// Create mutex to protect the mutex.
|
|
pperfApplicationInfo->hMutex = CreateMutexA( DNGetNullDacl(), FALSE, szNameBuffer );
|
|
|
|
if( !pperfApplicationInfo->hMutex )
|
|
{
|
|
hr = GetLastError();
|
|
DPFX(DPFPREP, 0,"MapViewOfFile() failed hr=0x%x", hr);
|
|
goto EXIT_ERROR;
|
|
}
|
|
|
|
// Copy all the settings back to the app specified structure
|
|
memcpy( pperfApplication, &g_pperfAppEntries[lIndex], sizeof( PERF_APPLICATION ) );
|
|
|
|
(*g_plNumEntries)++;
|
|
|
|
ReleaseMutex( g_hMutexInstanceBlock );
|
|
|
|
return S_OK;
|
|
|
|
EXIT_ERROR:
|
|
|
|
PERF_CleanupEntry( &g_pperfAppEntries[lIndex], pperfApplicationInfo );
|
|
ReleaseMutex( g_hMutexInstanceBlock );
|
|
return hr;
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "PERF_RemoveEntry"
|
|
// PERF_RemoveENtry
|
|
//
|
|
// When an entity no longer requires the statistics block they MUST call this function to free up the
|
|
// resources and to allow their slot in the central memory block to be used by other applications.
|
|
//
|
|
void PERF_RemoveEntry( GUID &guidInternalInstance, PPERF_APPLICATION_INFO pperfApplicationInfo )
|
|
{
|
|
if( !g_pbInstanceBlock )
|
|
return;
|
|
|
|
HRESULT hr = S_OK;
|
|
|
|
DPFX(DPFPREP, DVF_INFOLEVEL, "PERF: Shutting down perf info" );
|
|
|
|
// We need the mutex to access the block
|
|
WaitForSingleObject( g_hMutexInstanceBlock, INFINITE );
|
|
|
|
DPFX(DPFPREP, DVF_INFOLEVEL, "PERF: Removing dead entries" );
|
|
|
|
// Remove dead entries
|
|
PERF_Coalesce();
|
|
|
|
for( LONG lIndex = 0; lIndex < PERF_INSTANCE_BLOCK_MAXENTRIES; lIndex++ )
|
|
{
|
|
// We've found the entry, mark it as empty
|
|
if( g_pperfAppEntries[lIndex].guidInternalInstance == guidInternalInstance )
|
|
{
|
|
DPFX(DPFPREP, DVF_INFOLEVEL, "PERF: Removing our entry" );
|
|
PERF_CleanupEntry( &g_pperfAppEntries[lIndex], pperfApplicationInfo );
|
|
break;
|
|
}
|
|
}
|
|
|
|
ReleaseMutex( g_hMutexInstanceBlock );
|
|
|
|
DPFX(DPFPREP, DVF_INFOLEVEL, "PERF: Exiting" );
|
|
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "PERF_DeInitialize"
|
|
// PERF_DeInitialize
|
|
//
|
|
// Free up the global memory map. Must be called when process exits to cleanup
|
|
//
|
|
void PERF_DeInitialize()
|
|
{
|
|
if( g_hMutexInstanceBlock )
|
|
{
|
|
// We need the mutex to access the block
|
|
WaitForSingleObject( g_hMutexInstanceBlock, INFINITE );
|
|
PERF_Coalesce( GetCurrentProcessId() );
|
|
ReleaseMutex( g_hMutexInstanceBlock );
|
|
|
|
CloseHandle( g_hMutexInstanceBlock );
|
|
g_hMutexInstanceBlock = NULL;
|
|
}
|
|
|
|
if( g_pbInstanceBlock )
|
|
{
|
|
UnmapViewOfFile(g_pbInstanceBlock);
|
|
g_pbInstanceBlock = NULL;
|
|
}
|
|
|
|
if( g_hFileInstanceBlock )
|
|
{
|
|
CloseHandle( g_hFileInstanceBlock );
|
|
g_hFileInstanceBlock = NULL;
|
|
}
|
|
}
|
|
|
|
#undef DPF_MODNAME
|
|
#define DPF_MODNAME "PERF_DumpTable"
|
|
// PERF_DumpTable
|
|
//
|
|
// Helper function that calls the specified callback function once for each entry in the central performance
|
|
// table.
|
|
void PERF_DumpTable( BOOL fGrabMutex, PVOID pvContext, PFNDUMPPERFTABLE pperfAppEntry )
|
|
{
|
|
BOOL fSelfInitialized = FALSE;
|
|
HANDLE hMapInstance = NULL;
|
|
char szNameBuffer[PERF_INFO_NAME_LENGTH];
|
|
PBYTE pbDataBlob = NULL;
|
|
|
|
if( !g_pbInstanceBlock )
|
|
{
|
|
PERF_Initialize();
|
|
fSelfInitialized = TRUE;
|
|
}
|
|
|
|
if( fGrabMutex )
|
|
WaitForSingleObject( g_hMutexInstanceBlock, INFINITE );
|
|
|
|
for( LONG lIndex = 0; lIndex < PERF_INSTANCE_BLOCK_MAXENTRIES; lIndex++ )
|
|
{
|
|
// Build name for shared memory block
|
|
if (DNGetOSType() == VER_PLATFORM_WIN32_NT)
|
|
{
|
|
wsprintfA( szNameBuffer, "Global\\{%-08.8X-%-04.4X-%-04.4X-%02.2X%02.2X-%02.2X%02.2X%02.2X%02.2X%02.2X%02.2X}",
|
|
g_pperfAppEntries[lIndex].guidInternalInstance.Data1, g_pperfAppEntries[lIndex].guidInternalInstance.Data2,
|
|
g_pperfAppEntries[lIndex].guidInternalInstance.Data3, g_pperfAppEntries[lIndex].guidInternalInstance.Data4[0],
|
|
g_pperfAppEntries[lIndex].guidInternalInstance.Data4[1], g_pperfAppEntries[lIndex].guidInternalInstance.Data4[2],
|
|
g_pperfAppEntries[lIndex].guidInternalInstance.Data4[3], g_pperfAppEntries[lIndex].guidInternalInstance.Data4[4],
|
|
g_pperfAppEntries[lIndex].guidInternalInstance.Data4[5], g_pperfAppEntries[lIndex].guidInternalInstance.Data4[6],
|
|
g_pperfAppEntries[lIndex].guidInternalInstance.Data4[7] );
|
|
}
|
|
else
|
|
{
|
|
wsprintfA( szNameBuffer, "{%-08.8X-%-04.4X-%-04.4X-%02.2X%02.2X-%02.2X%02.2X%02.2X%02.2X%02.2X%02.2X}",
|
|
g_pperfAppEntries[lIndex].guidInternalInstance.Data1, g_pperfAppEntries[lIndex].guidInternalInstance.Data2,
|
|
g_pperfAppEntries[lIndex].guidInternalInstance.Data3, g_pperfAppEntries[lIndex].guidInternalInstance.Data4[0],
|
|
g_pperfAppEntries[lIndex].guidInternalInstance.Data4[1], g_pperfAppEntries[lIndex].guidInternalInstance.Data4[2],
|
|
g_pperfAppEntries[lIndex].guidInternalInstance.Data4[3], g_pperfAppEntries[lIndex].guidInternalInstance.Data4[4],
|
|
g_pperfAppEntries[lIndex].guidInternalInstance.Data4[5], g_pperfAppEntries[lIndex].guidInternalInstance.Data4[6],
|
|
g_pperfAppEntries[lIndex].guidInternalInstance.Data4[7] );
|
|
}
|
|
|
|
// Create file mapping for memory block
|
|
hMapInstance = OpenFileMappingA(PAGE_READWRITE,FALSE,szNameBuffer);
|
|
|
|
if( hMapInstance )
|
|
{
|
|
pbDataBlob = reinterpret_cast<BYTE*>(MapViewOfFile(hMapInstance,FILE_MAP_READ,0,0,0));
|
|
|
|
HRESULT hr = GetLastError();
|
|
}
|
|
|
|
if( FAILED( (*pperfAppEntry)( pvContext, &g_pperfAppEntries[lIndex], pbDataBlob ) ) )
|
|
break;
|
|
|
|
if( pbDataBlob )
|
|
{
|
|
UnmapViewOfFile( pbDataBlob );
|
|
pbDataBlob = NULL;
|
|
}
|
|
|
|
if( hMapInstance )
|
|
{
|
|
CloseHandle( hMapInstance );
|
|
hMapInstance = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
if( fGrabMutex )
|
|
ReleaseMutex( g_hMutexInstanceBlock );
|
|
|
|
|
|
if( fSelfInitialized )
|
|
PERF_DeInitialize();
|
|
}
|
|
|
|
|