// This is a part of the Active Template Library. // Copyright (C) 1996-2001 Microsoft Corporation // All rights reserved. // // This source code is only intended as a supplement to the // Active Template Library Reference and related // electronic documentation provided with the library. // See these sources for detailed information regarding the // Active Template Library product. #include "stdafx.h" #include "Common.h" #include "Allocate.h" #include "AtlTraceModuleManager.h" #pragma comment(lib, "advapi32.lib") bool CAtlAllocator::Init(const CHAR *pszFileName, DWORD dwMaxSize) { // REVIEW: // We're relying on syncronization provided by the startup code (CRT DllMain/WinMain) Close(); ATLASSERT(!m_hMap && !m_pBufferStart); SECURITY_DESCRIPTOR sd; SECURITY_ATTRIBUTES sa, *psa = NULL; if(!(GetVersion() & 0x80000000)) { ::InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION); ::SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE); sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.lpSecurityDescriptor = &sd; sa.bInheritHandle = FALSE; psa = &sa; } __try { m_hMap = CreateFileMappingA(INVALID_HANDLE_VALUE, psa, PAGE_READWRITE | SEC_RESERVE, 0, dwMaxSize, pszFileName); if(!m_hMap) __leave; DWORD dwErr = ::GetLastError(); m_pBufferStart = (BYTE *) MapViewOfFile(m_hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0); if(!m_pBufferStart) __leave; SYSTEM_INFO si; GetSystemInfo(&si); if(dwErr == ERROR_ALREADY_EXISTS) { m_pProcess = reinterpret_cast(m_pBufferStart); // Looks like it's already mapped into this process space. // Let's do some checking... if(IsBadReadPtr(m_pProcess, sizeof(CAtlTraceProcess)) || IsBadReadPtr(m_pProcess->Base(), sizeof(CAtlTraceProcess)) || 0 != memcmp(m_pBufferStart, m_pProcess->Base(), m_pProcess->m_dwFrontAlloc)) { // something's not right __leave; } // sure looks valid m_pProcess->IncRef(); m_pProcess = static_cast(m_pProcess->Base()); UnmapViewOfFile(m_pBufferStart); m_pBufferStart = reinterpret_cast(m_pProcess); } else { // This is just in case sizeof(CAtlTraceProcess) is // ever > dwPageSize (doubtful that could ever // happen, but it's easy enough to avoid here) DWORD dwCurrAlloc = si.dwPageSize; while(dwCurrAlloc < sizeof(CAtlTraceProcess)) dwCurrAlloc += si.dwPageSize; if(!VirtualAlloc(m_pBufferStart, dwCurrAlloc, MEM_COMMIT, PAGE_READWRITE)) __leave; m_pProcess = new(m_pBufferStart) CAtlTraceProcess(dwMaxSize); m_pProcess->m_dwFrontAlloc = dwCurrAlloc; m_pProcess->m_dwCurrFront = sizeof(CAtlTraceProcess); } m_dwPageSize = si.dwPageSize; m_bValid = true; } __finally { if(!m_bValid) { if(m_pBufferStart) { UnmapViewOfFile(m_pBufferStart); m_pBufferStart = NULL; } if(m_hMap) { CloseHandle(m_hMap); m_hMap = NULL; } } } return m_bValid; } bool CAtlAllocator::Open(const CHAR *pszFileName) { Close(); __try { m_hMap = OpenFileMappingA(FILE_MAP_WRITE, FALSE, pszFileName); if(!m_hMap) __leave; m_pBufferStart = (BYTE *) MapViewOfFile(m_hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0); if(!m_pBufferStart) __leave; m_pProcess = reinterpret_cast(m_pBufferStart); m_pProcess->IncRef(); SYSTEM_INFO si; GetSystemInfo(&si); m_dwPageSize = si.dwPageSize; m_bValid = true; } __finally { if(!m_bValid) { if(m_pBufferStart) { UnmapViewOfFile(m_pBufferStart); m_pBufferStart = NULL; } if(m_hMap) { CloseHandle(m_hMap); m_hMap = NULL; } m_pProcess = NULL; } } return m_bValid; } void CAtlAllocator::Close(bool bForceUnmap) { if(m_bValid) { if(m_pProcess->DecRef() == 0 || bForceUnmap) UnmapViewOfFile(m_pBufferStart); m_pBufferStart = NULL; CloseHandle(m_hMap); m_hMap = NULL; m_bValid = false; } } CAtlTraceModule *CAtlAllocator::GetModule(int iModule) const { if( iModule == -1 ) { return NULL; } ATLASSERT(iModule < m_pProcess->ModuleCount()); if(iModule < m_pProcess->ModuleCount()) { BYTE *pb = reinterpret_cast(m_pProcess) + sizeof(CAtlTraceProcess); return reinterpret_cast(pb) + iModule; } else return NULL; } /* CAtlTraceCategory *CAtlAllocator::GetCategory(unsigned nModule, unsigned nCategory) const { ATLASSERT(nModule < m_pProcess->ModuleCount()); if(nModule < m_pProcess->ModuleCount()) { BYTE *pb = reinterpret_cast(m_pProcess) + sizeof(CAtlTraceProcess); CAtlTraceModule *pModule = reinterpret_cast(pb) + nModule; if(IsValidCategoryIndex(pModule->m_nFirstCategory)) { unsigned nOldIndex, nIndex = pModule->m_nFirstCategory; CAtlTraceCategory *pCategory; do { pCategory = GetCategoryByIndex(nIndex); if(pCategory->m_nCategory == nCategory) return pCategory; nOldIndex = nIndex; nIndex = pCategory->m_nNext; } while(nOldIndex != nIndex); } } return NULL; } */ /* bool CAtlAllocator::IsValidCategoryIndex(unsigned nIndex) const { return nIndex < m_pProcess->CategoryCount(); } */ CAtlTraceCategory *CAtlAllocator::GetCategory(int iCategory) const { if(iCategory == m_pProcess->CategoryCount()) return NULL; ATLASSERT((iCategory < m_pProcess->CategoryCount()) || (iCategory == -1)); CAtlTraceCategory *pCategory = NULL; if(iCategory >= 0) { BYTE *pb = reinterpret_cast(m_pProcess) + m_pProcess->MaxSize(); pCategory = reinterpret_cast(pb) - iCategory - 1; } return pCategory; } int CAtlAllocator::GetCategoryCount(int iModule) const { UINT nCategories = 0; CAtlTraceModule* pModule = GetModule(iModule); ATLASSERT(pModule != NULL); if(pModule != NULL) { nCategories = GetCategoryCount( *pModule ); } return nCategories; } int CAtlAllocator::GetCategoryCount(const CAtlTraceModule& rModule) const { UINT nCategories = 0; int iCategory = rModule.m_iFirstCategory; while( iCategory != -1 ) { CAtlTraceCategory* pCategory = GetCategory( iCategory ); nCategories++; iCategory = pCategory->m_iNextCategory; } return nCategories; } int CAtlAllocator::GetModuleCount() const { ATLASSERT(m_pProcess); return m_pProcess->ModuleCount(); } const ULONG kModuleBatchSize = 10; int CAtlAllocator::AddModule(HINSTANCE hInst) { // bug bug bug - overlap onto the categories!!?? CAtlTraceProcess *pProcess = GetProcess(); int iFoundModule = -1; while( iFoundModule == -1 ) { for(int iModule = 0; (iModule < pProcess->ModuleCount()) && (iFoundModule == -1); iModule++) { CAtlTraceModule *pModule = GetModule(iModule); ATLASSERT(pModule != NULL); bool bFound = pModule->TryAllocate(); if( bFound ) { pModule->Reset(hInst); pModule->m_iFirstCategory = -1; pModule->MarkValid( pProcess->GetNextCookie() ); iFoundModule = iModule; } } if( iFoundModule == -1 ) { ULONG nNewAllocSize = kModuleBatchSize*sizeof( CAtlTraceModule ); void* pNewModules = reinterpret_cast(pProcess) + pProcess->m_dwFrontAlloc; VirtualAlloc(pNewModules, nNewAllocSize, MEM_COMMIT, PAGE_READWRITE); pProcess->m_dwFrontAlloc += nNewAllocSize; for( ULONG iNewModule = 0; iNewModule < kModuleBatchSize; iNewModule++ ) { CAtlTraceModule* pNewModule = static_cast< CAtlTraceModule* >( pNewModules )+iNewModule; new( pNewModule ) CAtlTraceModule; } pProcess->IncModuleCount( kModuleBatchSize ); } } return iFoundModule; } const ULONG kCategoryBatchSize = 10; int CAtlAllocator::AddCategory(int iModule, const WCHAR *szCategoryName) { int iFoundCategory = -1; CAtlTraceProcess *pProcess = GetProcess(); CAtlTraceModule *pModule = GetModule(iModule); if(pModule) { pModule->TryAddRef(); while( iFoundCategory == -1 ) { for(int iCategory = 0; (iCategory < pProcess->CategoryCount()) && (iFoundCategory == -1); iCategory++) { CAtlTraceCategory *pCategory = GetCategory( iCategory ); ATLASSERT(pCategory != NULL); bool bFound = pCategory->TryAllocate(); if( bFound ) { pCategory->Reset( szCategoryName, pModule->m_nCookie ); pCategory->m_iNextCategory = pModule->m_iFirstCategory; pCategory->MarkValid( pProcess->GetNextCookie() ); pModule->m_iFirstCategory = iCategory; ::InterlockedIncrement( &pModule->m_nCategories ); iFoundCategory = iCategory; } } if( iFoundCategory == -1 ) { ULONG nNewAllocSize = kCategoryBatchSize*sizeof( CAtlTraceCategory ); void* pNewCategories = reinterpret_cast(pProcess) + pProcess->MaxSize()-pProcess->m_dwBackAlloc-nNewAllocSize; VirtualAlloc(pNewCategories, nNewAllocSize, MEM_COMMIT, PAGE_READWRITE); pProcess->m_dwBackAlloc += nNewAllocSize; for( ULONG iNewCategory = 0; iNewCategory < kCategoryBatchSize; iNewCategory++ ) { CAtlTraceCategory* pNewCategory = static_cast< CAtlTraceCategory* >( pNewCategories )+iNewCategory; new( pNewCategory ) CAtlTraceCategory; } pProcess->IncCategoryCount( kCategoryBatchSize ); } } pModule->Release(); } pProcess->m_bLoaded = false; return( iFoundCategory ); } bool CAtlAllocator::RemoveModule(int iModule) { CAtlTraceModule* pModule = GetModule(iModule); if(pModule) { int iCategory = pModule->m_iFirstCategory; while( iCategory != -1 ) { CAtlTraceCategory* pCategory = GetCategory( iCategory ); iCategory = pCategory->m_iNextCategory; ::InterlockedDecrement( &pModule->m_nCategories ); pModule->m_iFirstCategory = iCategory; pCategory->Release(); } pModule->Release(); return true; } return false; } void CAtlAllocator::CleanUp() { Close(); } void CAtlAllocator::TakeSnapshot() { if( m_bSnapshot ) { ReleaseSnapshot(); } int nModules = GetModuleCount(); for( int iModule = 0; iModule < nModules; iModule++ ) { CAtlTraceModule* pModule = GetModule( iModule ); bool bValidModule = pModule->TryAddRef(); if( bValidModule ) { CTraceSnapshot::CModuleInfo module; module.m_dwModule = DWORD_PTR( iModule )+1; module.m_iFirstCategory = m_snapshot.m_adwCategories.GetSize(); module.m_nCategories = pModule->m_nCategories; int iCategory = pModule->m_iFirstCategory; bool bCategoriesValid = true; int nCategories = 0; while( (iCategory != -1) && bCategoriesValid ) { CAtlTraceCategory* pCategory = GetCategory( iCategory ); bool bValidCategory = pCategory->TryAddRef(); if( bValidCategory ) { if( pCategory->m_nModuleCookie != pModule->m_nCookie ) { bValidCategory = false; pCategory->Release(); } else { m_snapshot.m_adwCategories.Add( DWORD_PTR( iCategory ) ); nCategories++; iCategory = pCategory->m_iNextCategory; } } if( !bValidCategory ) { bCategoriesValid = false; } } if( !bCategoriesValid ) { for( int iCategoryIndex = nCategories-1; iCategoryIndex >= 0; iCategoryIndex-- ) { DWORD_PTR dwCategory = m_snapshot.m_adwCategories[module.m_iFirstCategory+iCategoryIndex]; m_snapshot.m_adwCategories.RemoveAt( module.m_iFirstCategory+iCategoryIndex ); GetCategory( int( dwCategory ) )->Release(); } pModule->Release(); } else { m_snapshot.m_aModules.Add( module ); } } } m_bSnapshot = true; } void CAtlAllocator::ReleaseSnapshot() { if( m_bSnapshot ) { for( int iModule = 0; iModule < m_snapshot.m_aModules.GetSize(); iModule++ ) { GetModule( int( m_snapshot.m_aModules[iModule].m_dwModule-1 ) )->Release(); } for( int iCategory = 0; iCategory < m_snapshot.m_adwCategories.GetSize(); iCategory++ ) { GetCategory( int( m_snapshot.m_adwCategories[iCategory] ) )->Release(); } m_bSnapshot = false; } }