diff -r 185201be11b0 -r 516af714ebb4 perfsrv/memspy/Driver/Kernel/Source/MemSpyDriverInspectedProcess.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/perfsrv/memspy/Driver/Kernel/Source/MemSpyDriverInspectedProcess.cpp Fri Sep 17 08:38:31 2010 +0300 @@ -0,0 +1,1268 @@ +/* +* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: +* +*/ + +#include "MemSpyDriverInspectedProcess.h" + +// System includes +#include +#include +#include + +#ifdef __MARM__ +#include "kdebug.h" +#endif //__MARM__ + +// User includes +#include "MemSpyDriverUtils.h" +#include "MemSpyDriverDevice.h" +#include "MemSpyDriverOSAdaption.h" +#include "MemSpyDriverInspectedProcessManager.h" + +// Constants +_LIT8( KMemSpyLitDollarHeap, "$HEAP" ); +_LIT8( KMemSpyLitDollarDllData, "DLL$DATA" ); +_LIT8( KMemSpyLitDollarDat, "$DAT" ); +_LIT( KMemSpyInspectedProcessMutexName, "MemSpyInspectedProcess_0x" ); + + +DMemSpyInspectedProcess::DMemSpyInspectedProcess( DMemSpyDriverDevice& aDevice ) +: iDevice( aDevice ) + { + } + + +DMemSpyInspectedProcess::~DMemSpyInspectedProcess() + { + TRACE( Kern::Printf("DMemSpyInspectedProcess::~DMemSpyInspectedProcess() - START - this: 0x%08x, %O", this, iProcess )); + EventMonitor().RequestEventsCancel( *this ); + + TRACE( Kern::Printf("DMemSpyInspectedProcess::~DMemSpyInspectedProcess() - calling NotifyOnChangeCancel..." ) ); + NotifyOnChangeCancel(); + + TRACE( Kern::Printf("DMemSpyInspectedProcess::~DMemSpyInspectedProcess() - calling ResetTrackedList..." ) ); + ResetTrackedList(); + + TRACE( Kern::Printf("DMemSpyInspectedProcess::~DMemSpyInspectedProcess() - calling ResetPendingChanges..." ) ); + ResetPendingChanges(); + + if ( iLock ) + { + TRACE( Kern::Printf("DMemSpyInspectedProcess::~DMemSpyInspectedProcess() - closing mutex..." ) ); + iLock->Close(NULL); + } + + if ( iProcess ) + { + TRACE( Kern::Printf("DMemSpyInspectedProcess::~DMemSpyInspectedProcess() - closing process..." ) ); + Kern::SafeClose( (DObject*&) iProcess, NULL ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::~DMemSpyInspectedProcess() - closed process!" ) ); + } + + TRACE( Kern::Printf("DMemSpyInspectedProcess::~DMemSpyInspectedProcess() - END - this: 0x%08x", this ) ); + } + + +TInt DMemSpyInspectedProcess::Open( DProcess* aProcess ) + { + __ASSERT_CRITICAL; + TRACE( Kern::Printf("DMemSpyInspectedProcess::Open() - START - this: 0x%08x, aProcess: 0x%08x (%O)", this, aProcess, aProcess )); + + TInt error = KErrNone; + // + iProcess = aProcess; + error = iProcess->Open(); + // + if ( error == KErrNone ) + { + iProcessId = iDevice.OSAdaption().DProcess().GetId( *aProcess ); + + // Create mutex + TName name( KMemSpyInspectedProcessMutexName ); + name.AppendNumFixedWidth( (TUint) this, EHex, 8 ); + error = Kern::MutexCreate( iLock, name, KMutexOrdNone ); + // + if ( error == KErrNone ) + { + // Get size of all stacks (user & supervsior) for process. Also + // updates iUserThreadStackSize with the current size of just + // the user-side thread stacks. + iInfoCurrent.iMemoryStack = StackSize( *aProcess ); + + // Request events + EventMonitor().RequestEvents( *this ); + + // Find initial chunks that are mapped into process + FindChunks( *aProcess ); + + // Indicate that we have data waiting for client. This will + // cause the client's RS to be completed as soon as it + // registers with us... + UpdateStatistics(); + CompleteClientsRequest( KErrNone, &iInfoCurrent ); + } + } + // + TRACE( Kern::Printf("DMemSpyInspectedProcess::Open() - END - this: 0x%08x, error: %d", this, error )); + return error; + } + + + + + + + + +TInt DMemSpyInspectedProcess::NotifyOnChange( DThread* aThread, TRequestStatus* aRequestStatus, TMemSpyDriverProcessInspectionInfo* aInfo ) + { + Lock(); + + TInt err = KErrInUse; + const TBool notificationQueued = NotifyOnChangeQueued(); + TRACE( Kern::Printf("DMemSpyInspectedProcess::NotifyOnChange() - START - this: 0x%08x, iAmDead: %d, aRequestStatus: 0x%08x, notificationQueued: %d, iChangeObserverThread: 0x%08x (%O)", this, iAmDead, aRequestStatus, notificationQueued, iChangeObserverThread, iChangeObserverThread ) ); + // + if ( notificationQueued == EFalse ) + { + TRACE( Kern::Printf("DMemSpyInspectedProcess::NotifyOnChange() - Saving client RS..." ) ); + iChangeObserverThread = aThread; + iChangeObserverRS = aRequestStatus; + iChangeObserverInfo = aInfo; + + // Whilst we still have items in the buffer, we let the client drain them fully. + // However, if the process is now marked as dead and the buffer is exhausted, + // we indicate this via KErrDied completion which will cause the client to + // stop requesting any more changes. + if ( !iPendingChanges.IsEmpty() ) + { + TRACE( Kern::Printf("DMemSpyInspectedProcess::NotifyOnChange() - Have buffered changes - SENDING TO CLIENT IMMEDIATELY..." ) ); + + // We have something in the pending buffer so we can + // give it back to the client immediately. + TMemSpyTrackedChunkChangeInfo* cachedChange = _LOFF( iPendingChanges.First(), TMemSpyTrackedChunkChangeInfo, iLink ); + cachedChange->iLink.Deque(); + + // Notify about change + CompleteClientsRequest( KErrNone, &cachedChange->iInfo ); + + // Discard cached entry + delete cachedChange; + } + else if ( iAmDead ) + { + // We must stop listening outside of an event monitor callback... + EventMonitor().RequestEventsCancel( *this ); + CompleteClientsRequest( KErrDied ); + } + // + err = KErrNone; + } + // + TRACE( Kern::Printf("DMemSpyInspectedProcess::NotifyOnChange() - END - this: 0x%08x, err: %d", this, err ) ); + + Unlock(); + return err; + } + + +TInt DMemSpyInspectedProcess::NotifyOnChangeCancel() + { + Lock(); + TRACE( Kern::Printf("DMemSpyInspectedProcess::NotifyOnChangeCancel() - START - this: 0x%08x, queued: %d, iChangeObserverThread: 0x%08x, iChangeObserverRS: 0x%08x", this, NotifyOnChangeQueued(), iChangeObserverThread, iChangeObserverRS ) ); + // + if ( NotifyOnChangeQueued() ) + { + TRACE( Kern::Printf( "DMemSpyInspectedProcess::NotifyOnChangeCancel() - this: 0x%08x, iChangeObserverRS: 0x%08x, iProcessId: %d (0x%04x)", this, iChangeObserverRS, iProcessId, iProcessId ) ); + Kern::RequestComplete( iChangeObserverThread, iChangeObserverRS, KErrCancel ); + iChangeObserverThread = NULL; + iChangeObserverRS = NULL; + iChangeObserverInfo = NULL; + } + // + TRACE( Kern::Printf("DMemSpyInspectedProcess::NotifyOnChangeCancel() - END - this: 0x%08x", this ) ); + Unlock(); + + return KErrNone; + } + + +TBool DMemSpyInspectedProcess::NotifyOnChangeQueued() const + { + TRACE( Kern::Printf("DMemSpyInspectedProcess::NotifyOnChangeQueued() - START - this: 0x%08x", this ) ); + // + Lock(); + const TBool queued = ( iChangeObserverRS != NULL ); + Unlock(); + // + TRACE( Kern::Printf("DMemSpyInspectedProcess::NotifyOnChangeQueued() - END - this: 0x%08x, queued: %d", this, queued ) ); + return queued; + } + + + + + + + + + +void DMemSpyInspectedProcess::CompleteClientsRequest( TInt aCompletionCode, TMemSpyDriverProcessInspectionInfo* aInfo ) + { + const TBool notificationQueued = NotifyOnChangeQueued(); + TRACE( Kern::Printf( "DMemSpyInspectedProcess::CompleteClientsRequest() - START - this: 0x%08x, iChangeObserverThread: 0x%08x, iChangeObserverRS: 0x%08x, iChangeObserverInfo: 0x%08x, notificationQueued: %d", this, iChangeObserverThread, iChangeObserverRS, iChangeObserverInfo, notificationQueued ) ); + TRACE( Kern::Printf( "DMemSpyInspectedProcess::CompleteClientsRequest() - iAmDead: %d, buffer is empty: %d, aCompletionCode: %d, iProcessId: %d (0x%04x), aInfo: 0x%08x, iChangeDeliveryCounter: %d", iAmDead, iPendingChanges.IsEmpty(), aCompletionCode, iProcessId, iProcessId, aInfo, iChangeDeliveryCounter ) ); + + if ( notificationQueued ) + { + ++iChangeDeliveryCounter; + TInt completionCode = aCompletionCode; + + // Write them to client... + if ( aInfo != NULL ) + { + const TInt writeErr = Kern::ThreadRawWrite( iChangeObserverThread, iChangeObserverInfo, aInfo, sizeof(TMemSpyDriverProcessInspectionInfo) ); + if ( writeErr != KErrNone ) + { + completionCode = writeErr; + } + } + + // Complete client's async request + DThread* changeThread = iChangeObserverThread; + TRequestStatus* changeRS = iChangeObserverRS; + + // Zero these out first to avoid race condition + iChangeObserverThread = NULL; + iChangeObserverRS = NULL; + iChangeObserverInfo = NULL; + + // ...and then tell client. + TRACE( Kern::Printf( "DMemSpyInspectedProcess::CompleteClientsRequest() - SENDING CHANGE [%4d] TO CLIENT [err: %d]", iChangeDeliveryCounter, completionCode ) ); + Kern::RequestComplete( changeThread, changeRS, completionCode ); + } + else if ( aInfo ) + { + // Buffer the change for next time around... + TRACE( Kern::Printf("DMemSpyInspectedProcess::CompleteClientsRequest() - BUFFERING change event whilst client is AWOL...", this ) ); + NKern::ThreadEnterCS(); + + TMemSpyTrackedChunkChangeInfo* changeInfo = new TMemSpyTrackedChunkChangeInfo(); + if ( changeInfo ) + { + changeInfo->iInfo = *aInfo; + iPendingChanges.Add( &changeInfo->iLink ); + } + // + NKern::ThreadLeaveCS(); + } + + TRACE( Kern::Printf("DMemSpyInspectedProcess::CompleteClientsRequest() - END - this: 0x%08x", this ) ); + } + + + + + + + + + + + + +void DMemSpyInspectedProcess::ResetTrackedList() + { + TRACE( Kern::Printf("DMemSpyInspectedProcess::ResetTrackedList() - START - this: 0x%08x", this ) ); + NKern::ThreadEnterCS(); + // + SDblQueLink* link = iTrackedChunks.GetFirst(); + while( link ) + { + TMemSpyTrackedChunk* object = _LOFF( link, TMemSpyTrackedChunk, iLink ); + delete object; + link = iTrackedChunks.GetFirst(); + } + // + NKern::ThreadLeaveCS(); + TRACE( Kern::Printf("DMemSpyInspectedProcess::ResetTrackedList() - END - this: 0x%08x", this ) ); + } + + +void DMemSpyInspectedProcess::SetTrackedListUnused() + { + TRACE( Kern::Printf("DMemSpyInspectedProcess::SetTrackedListUnused() - START - this: 0x%08x", this ) ); + SDblQueLink* anchor = &iTrackedChunks.iA; + for (SDblQueLink* link = iTrackedChunks.First(); link != anchor; link = link->iNext) + { + TMemSpyTrackedChunk* trackedChunk = _LOFF( link, TMemSpyTrackedChunk, iLink ); + trackedChunk->SetUnused( ETrue ); + } + TRACE( Kern::Printf("DMemSpyInspectedProcess::SetTrackedListUnused() - END - this: 0x%08x", this ) ); + } + + +void DMemSpyInspectedProcess::SetTrackedListUnusedStatusByType( TMemSpyTrackedChunk::TType aType, TBool aUnusedStatus ) + { + TRACE( Kern::Printf("DMemSpyInspectedProcess::SetTrackedListUnusedStatusByType() - START - this: 0x%08x", this ) ); + SDblQueLink* anchor = &iTrackedChunks.iA; + for (SDblQueLink* link = iTrackedChunks.First(); link != anchor; link = link->iNext) + { + TMemSpyTrackedChunk* trackedChunk = _LOFF( link, TMemSpyTrackedChunk, iLink ); + if ( trackedChunk->Type() == aType ) + { + trackedChunk->SetUnused( aUnusedStatus ); + } + } + TRACE( Kern::Printf("DMemSpyInspectedProcess::SetTrackedListUnusedStatusByType() - END - this: 0x%08x", this ) ); + } + + +void DMemSpyInspectedProcess::DiscardUnusedTrackListItems() + { + TRACE( Kern::Printf("DMemSpyInspectedProcess::DiscardUnusedTrackListItems() - START - this: 0x%08x", this ) ); + NKern::ThreadEnterCS(); + const SDblQueLink* const anchor = &iTrackedChunks.iA; + // + SDblQueLink* link = iTrackedChunks.First(); + while( link && link != anchor ) + { + TMemSpyTrackedChunk* trackedChunk = _LOFF( link, TMemSpyTrackedChunk, iLink ); + const TBool unused = trackedChunk->iUnused; + // + link = link->iNext; + // + if ( unused ) + { + trackedChunk->iLink.Deque(); + delete trackedChunk; + } + else + { + trackedChunk->SetUnused( EFalse ); + } + } + // + NKern::ThreadLeaveCS(); + TRACE( Kern::Printf("DMemSpyInspectedProcess::DiscardUnusedTrackListItems() - END - this: 0x%08x", this ) ); + } + + +void DMemSpyInspectedProcess::AddTrackedChunk( DChunk* aChunk, TMemSpyTrackedChunk::TType aType ) + { + TRACE( Kern::Printf("DMemSpyInspectedProcess::AddTrackedChunk() - START - this: 0x%08x, aChunk: 0x%08x (%O)", this, aChunk, aChunk ) ); + NKern::ThreadEnterCS(); + // + TMemSpyTrackedChunk* wrapper = new TMemSpyTrackedChunk( aChunk, aType ); + if ( wrapper ) + { + DMemSpyDriverOSAdaptionDChunk& chunkAdaption = iDevice.OSAdaption().DChunk(); + const TInt cSize = chunkAdaption.GetSize( *aChunk ); + wrapper->SetSize( cSize ); + iTrackedChunks.Add( &wrapper->iLink ); + } + // + NKern::ThreadLeaveCS(); + TRACE( Kern::Printf("DMemSpyInspectedProcess::AddTrackedChunk() - END - this: 0x%08x", this ) ); + } + + +TMemSpyTrackedChunk* DMemSpyInspectedProcess::TrackedChunkByHandle( TAny* aHandle ) + { + TRACE( Kern::Printf("DMemSpyInspectedProcess::TrackedChunkByHandle() - START - this: 0x%08x", this ) ); + TMemSpyTrackedChunk* ret = NULL; + // + const SDblQueLink* const anchor = &iTrackedChunks.iA; + for (SDblQueLink* link = iTrackedChunks.First(); link != anchor; link = link->iNext) + { + TMemSpyTrackedChunk* const trackedChunk = _LOFF( link, TMemSpyTrackedChunk, iLink ); + + if ( trackedChunk && trackedChunk->Handle() == aHandle ) + { + ret = trackedChunk; + break; + } + } + // + TRACE( Kern::Printf("DMemSpyInspectedProcess::TrackedChunkByHandle() - END - this: 0x%08x, entry: 0x%08x (%O)", this, ret, ret ? ret->iChunk : NULL ) ); + return ret; + } + + + + + + + + + + + +DMemSpyInspectedProcessManager& DMemSpyInspectedProcess::PManager() + { + return iDevice.ProcessInspectionManager(); + } + + +DMemSpyEventMonitor& DMemSpyInspectedProcess::EventMonitor() + { + return iDevice.EventMonitor(); + } + + + + + + + +TUint DMemSpyInspectedProcess::EMTypeMask() const + { + TUint ret = EMemSpyEventThreadAdd | EMemSpyEventThreadRemove | EMemSpyEventThreadKill | + EMemSpyEventProcessUpdate | EMemSpyEventProcessRemove | + EMemSpyEventChunkAdd | EMemSpyEventChunkUpdate | EMemSpyEventChunkDelete; + + if ( iAmDead ) + { + // Not interested anymore... + ret = 0; + } + + return ret; + } + + +void DMemSpyInspectedProcess::EMHandleProcessUpdated( DProcess& aProcess ) + { + const TUint procId = iDevice.OSAdaption().DProcess().GetId( aProcess ); + if ( procId == iProcessId ) + { + Lock(); + + TRACE( Kern::Printf("DMemSpyInspectedProcess::EMHandleProcessUpdated() - START - this: 0x%08x, iProcess: 0x%08x (%O)", this, iProcess, iProcess ) ); + + // Mark all tracked chunks as dirty whilst we work out + // what is and isn't mapped into the process + SetTrackedListUnused(); + SetTrackedListUnusedStatusByType( TMemSpyTrackedChunk::ETypeChunkGlobalData, EFalse /* global data chunks are still in use */ ); + + // Locate any suitable chunks, tagging existing entries as + // 'in use' so that we can easily spot ones which are no longer + // mapped into the process. + FindChunks( *iProcess ); + + // Throw away and tracked chunks which aren't mapped into the + // process anymore. + DiscardUnusedTrackListItems(); + + // Calculate latest statistics... + const TBool changeDetected = UpdateStatistics(); + if ( changeDetected ) + { + // Inform observer about new results. + CompleteClientsRequest( KErrNone, &iInfoCurrent ); + } + + TRACE( Kern::Printf("DMemSpyInspectedProcess::EMHandleProcessUpdated() - END - this: 0x%08x", this ) ); + + Unlock(); + } + } + + +void DMemSpyInspectedProcess::EMHandleProcessRemoved( DProcess& aProcess ) + { + DMemSpyDriverOSAdaptionDProcess& dProcessAdaption = iDevice.OSAdaption().DProcess(); + const TUint pid = dProcessAdaption.GetId( aProcess ); + + if ( pid == iProcessId ) + { + Lock(); + + TRACE( Kern::Printf("DMemSpyInspectedProcess::EMHandleProcessRemoved() - START - this: 0x%08x", this ) ); + + // We will implement a multi phased approach to the process being removed. + // + // The first notification we will send will show that the process heap and + // local chunks have been removed, leaving shared chunk sizes intact. + // + // We will then send another change, this time setting everything to zero... + SetTrackedListUnused(); + SetTrackedListUnusedStatusByType( TMemSpyTrackedChunk::ETypeChunkShared, EFalse /* shared chunks are still in use */ ); + SetTrackedListUnusedStatusByType( TMemSpyTrackedChunk::ETypeChunkGlobalData, EFalse /* global data chunks are still in use */ ); + DiscardUnusedTrackListItems(); + const TBool changeDetected1 = UpdateStatistics(); + if ( changeDetected1 ) + { + // Inform observer about new results. + CompleteClientsRequest( KErrNone, &iInfoCurrent ); + } + + // Now repeat the exercise, this time removing everything. + ResetTrackedList(); + + // ... including stack + iInfoCurrent.iMemoryStack = 0; + + const TBool changeDetected2 = UpdateStatistics(); + if ( changeDetected2 ) + { + // Inform observer about new results. + CompleteClientsRequest( KErrNone, &iInfoCurrent ); + } + + // Stop listening to events since we've drained everything now... + iAmDead = ETrue; + + TRACE( Kern::Printf("DMemSpyInspectedProcess::EMHandleProcessRemoved() - END - this: 0x%08x", this ) ); + + Unlock(); + } + } + + +void DMemSpyInspectedProcess::EMHandleThreadAdd( DThread& aThread ) + { + DMemSpyDriverOSAdaptionDThread& dThreadAdaption = iDevice.OSAdaption().DThread(); + DMemSpyDriverOSAdaptionDProcess& dProcessAdaption = iDevice.OSAdaption().DProcess(); + // + DProcess* owningProcess = dThreadAdaption.GetOwningProcess( aThread ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::EMHandleThreadAdd() - this: 0x%08x, aThread: 0x%08x, owningProcess: 0x%08x", this, &aThread, owningProcess ) ); + if ( owningProcess ) + { + const TUint owningProcessId = dProcessAdaption.GetId( *owningProcess ); + const TUint myId = dProcessAdaption.GetId( *iProcess ); + // + if ( myId == owningProcessId ) + { + EMHandleThreadChanged( aThread ); + } + } + } + + +void DMemSpyInspectedProcess::EMHandleThreadRemoved( DThread& aThread ) + { + DMemSpyDriverOSAdaptionDThread& dThreadAdaption = iDevice.OSAdaption().DThread(); + DMemSpyDriverOSAdaptionDProcess& dProcessAdaption = iDevice.OSAdaption().DProcess(); + // + DProcess* owningProcess = dThreadAdaption.GetOwningProcess( aThread ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::EMHandleThreadRemoved() - this: 0x%08x, aThread: 0x%08x, owningProcess: 0x%08x", this, &aThread, owningProcess ) ); + if ( owningProcess ) + { + const TUint owningProcessId = dProcessAdaption.GetId( *owningProcess ); + const TUint myId = dProcessAdaption.GetId( *iProcess ); + // + if ( myId == owningProcessId ) + { + EMHandleThreadChanged( aThread ); + } + } + } + + +void DMemSpyInspectedProcess::EMHandleThreadKilled( DThread& aThread ) + { + // + DMemSpyDriverOSAdaptionDThread& dThreadAdaption = iDevice.OSAdaption().DThread(); + DMemSpyDriverOSAdaptionDProcess& dProcessAdaption = iDevice.OSAdaption().DProcess(); + // + DProcess* owningProcess = dThreadAdaption.GetOwningProcess( aThread ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::EMHandleThreadKilled() - this: 0x%08x, aThread: 0x%08x, owningProcess: 0x%08x", this, &aThread, owningProcess ) ); + if ( owningProcess ) + { + const TUint owningProcessId = dProcessAdaption.GetId( *owningProcess ); + const TUint myId = dProcessAdaption.GetId( *iProcess ); + // + if ( myId == owningProcessId ) + { + EMHandleThreadChanged( aThread ); + } + } + } + + +void DMemSpyInspectedProcess::EMHandleThreadChanged( DThread& /*aThread*/ ) + { + Lock(); + + TRACE( Kern::Printf("DMemSpyInspectedProcess::EMHandleThreadChanged() - START - this: 0x%08x", this ) ); + + // This is called when a thread is added, changed, or terminated/killed. + // We must be careful to only access the members of aThread that still + // exist as if it is being destroyed, the object may be in an intermediate + // state. + + // All we are really interested in is recalculating the stack usage + // for the process... + iInfoCurrent.iMemoryStack = StackSize( *iProcess ); + + // Always inform observer about new results. + CompleteClientsRequest( KErrNone, &iInfoCurrent ); + + TRACE( Kern::Printf("DMemSpyInspectedProcess::EMHandleThreadChanged() - END - this: 0x%08x", this ) ); + + Unlock(); + } + + +void DMemSpyInspectedProcess::EMHandleChunkAdd( DChunk& aChunk ) + { + Lock(); + + TRACE( Kern::Printf("DMemSpyInspectedProcess::EMHandleChunkAdd() - START - this: 0x%08x, aChunk: 0x%08x (%O)", this, &aChunk, &aChunk ) ); + + // Is this chunk related to our process somehow? + if ( IsChunkRelevantToOurProcess( aChunk ) ) + { + TRACE( Kern::Printf("DMemSpyInspectedProcess::EMHandleChunkAdd() - processes match, checking chunk type..." ) ); + + const TMemSpyTrackedChunk::TType type = ChunkType( &aChunk ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::EMHandleChunkAdd() - chunkType: %d", type ) ); + + if ( type != TMemSpyTrackedChunk::ETypeNotRelevant ) + { + // It's a new entry in our process + TRACE( Kern::Printf("DMemSpyInspectedProcess::EMHandleChunkAdd() - this: 0x%08x, creating new entry for chunk: 0x%08x", this, &aChunk ) ); + + AddTrackedChunk( &aChunk, type ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::EMHandleChunkAdd() - added chunk..." )); + + const TBool changeDetected = UpdateStatistics(); + if ( changeDetected ) + { + // Inform observer about new results. + CompleteClientsRequest( KErrNone, &iInfoCurrent ); + } + } + } + + TRACE( Kern::Printf("DMemSpyInspectedProcess::EMHandleChunkAdd() - END - this: 0x%08x", this ) ); + + Unlock(); + } + + +void DMemSpyInspectedProcess::EMHandleChunkUpdated( DChunk& aChunk ) + { + Lock(); + + TRACE( Kern::Printf("DMemSpyInspectedProcess::EMHandleChunkUpdated() - START - this: 0x%08x, aChunk: 0x%08x [S: %8d] (%O)", this, &aChunk, aChunk.Size(), &aChunk ) ); + + // Is this chunk mapped into our process? + TMemSpyTrackedChunk* trackedEntry = TrackedChunkByHandle( &aChunk ); + if ( trackedEntry != NULL ) + { + const TInt oldSize = trackedEntry->Size(); + const TInt newSize = iDevice.OSAdaption().DChunk().GetSize( aChunk ); + + TRACE( Kern::Printf("DMemSpyInspectedProcess::EMHandleChunkUpdated() - was tracked entry [0x%08x, size; %10d, type: %d] vs new size: %d", trackedEntry, oldSize, trackedEntry->Type(), newSize ) ); + + // If the existing entry had a size of 0 and the new size is non-zero + // then we may have enough data such that we can validate type information. + // For example, any secondary heap chunk that is created within the process will + // most likely have a Local-NNNNNN style name, and this chunk will be created with + // an initial size of zero. + // + // We can only identify it's type once the chunk has been updated with some data + // that supports vTable verification. Hence the type may fluctuate... + if ( oldSize == 0 && newSize > 0 ) + { + TRACE( Kern::Printf("DMemSpyInspectedProcess::EMHandleChunkUpdated() - checking type again as chunk size was zero..." ) ); + + PrintChunkInfo( aChunk ); + const TMemSpyTrackedChunk::TType type = ChunkType( &aChunk ); + if ( type != trackedEntry->Type() ) + { + // Type has changed + TRACE( Kern::Printf("DMemSpyInspectedProcess::EMHandleChunkUpdated() - type has transitioned from: %d to %d", trackedEntry->Type(), type ) ); + trackedEntry->SetType( type ); + } + } + + // Update our record with new chunk size + trackedEntry->SetSize( newSize ); + + const TBool changeDetected = UpdateStatistics(); + if ( changeDetected ) + { + // Inform observer about new results. + CompleteClientsRequest( KErrNone, &iInfoCurrent ); + } + } + + TRACE( Kern::Printf("DMemSpyInspectedProcess::EMHandleChunkUpdated() - END - this: 0x%08x", this ) ); + + Unlock(); + } + + +void DMemSpyInspectedProcess::EMHandleChunkDeleted( DChunk& aChunk ) + { + Lock(); + + TRACE( Kern::Printf("DMemSpyInspectedProcess::EMHandleChunkDeleted() - START - this: 0x%08x", this ) ); + + // Is this chunk mapped into our process? + TMemSpyTrackedChunk* trackedEntry = TrackedChunkByHandle( &aChunk ); + if ( trackedEntry != NULL ) + { + // Delete entry + trackedEntry->iLink.Deque(); + delete trackedEntry; + + const TBool changeDetected = UpdateStatistics(); + if ( changeDetected ) + { + // Inform observer about new results. + CompleteClientsRequest( KErrNone, &iInfoCurrent ); + } + } + + TRACE( Kern::Printf("DMemSpyInspectedProcess::EMHandleChunkDeleted() - END - this: 0x%08x", this ) ); + + Unlock(); + } + + +void DMemSpyInspectedProcess::PrintChunkInfo( DChunk& aChunk ) const + { + TRACE( Kern::Printf("DMemSpyInspectedProcess::PrintChunkInfo() - iProcess*: 0x%08x", iProcess ) ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::PrintChunkInfo() - iProcess id: 0x%04x", iProcessId ) ); + MemSpyDriverUtils::PrintChunkInfo( aChunk, iDevice.OSAdaption() ); + } + + +TBool DMemSpyInspectedProcess::IsChunkRelevantToOurProcess( DChunk& aChunk ) const + { + TRACE( Kern::Printf("DMemSpyInspectedProcess::IsChunkRelevantToOurProcess() - START - this: 0x%08x, iProcess: 0x%08x (%4d), aChunk: 0x%08x (%O)", this, iProcess, iProcessId, &aChunk, &aChunk) ); + + TBool relevant = EFalse; + DMemSpyDriverOSAdaptionDChunk& chunkAdaption = iDevice.OSAdaption().DChunk(); + // + PrintChunkInfo( aChunk ); + // + DProcess* chunkProc = chunkAdaption.GetOwningProcess( aChunk ); + if ( chunkProc ) + { + const TUint procId = iDevice.OSAdaption().DProcess().GetId( *chunkProc ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::IsChunkRelevantToOurProcess() - [Owning Process] Comparing chunk pid: 0x%04x with procPid: 0x%04x", this, procId, iProcessId ) ); + relevant = ( procId == iProcessId ); + } + else if ( chunkAdaption.GetOwner( aChunk ) == iProcess ) + { + TRACE( Kern::Printf("DMemSpyInspectedProcess::IsChunkRelevantToOurProcess() - [Owner Match]" ) ); + relevant = ETrue; + } + else + { + const TUint controllingOwnerPid = chunkAdaption.GetControllingOwnerId( aChunk ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::IsChunkRelevantToOurProcess() - [Controlling Owner] Comparing chunk owner: 0x%04x with procPid: 0x%04x", this, controllingOwnerPid, iProcessId ) ); + relevant = ( controllingOwnerPid == iProcessId ); + } + + TRACE( Kern::Printf("DMemSpyInspectedProcess::IsChunkRelevantToOurProcess() - END - this: 0x%08x, relevant: %d", this, relevant ) ); + return relevant; + } + + +TMemSpyTrackedChunk::TType DMemSpyInspectedProcess::ChunkType( DObject* aObject ) const + { + TRACE( Kern::Printf("DMemSpyInspectedProcess::ChunkType() - START - this: 0x%08x, iProcess: 0x%08x, aObject: 0x%08x (%O)", this, iProcess, aObject, aObject ) ); + TMemSpyTrackedChunk::TType ret = TMemSpyTrackedChunk::ETypeNotRelevant; + + // Firstly, check if it's actually held within the chunk container. + if ( aObject ) + { + DMemSpyDriverOSAdaptionDChunk& chunkAdaption = iDevice.OSAdaption().DChunk(); + const TObjectType objectType = chunkAdaption.GetObjectType( *aObject ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::ChunkType() - objectType: %d vs EChunk (%d)", objectType, EChunk ) ); + + if ( objectType == EChunk ) + { + DChunk* chunk = (DChunk*) aObject; + // + if ( IsChunkRelevantToOurProcess( *chunk ) ) + { + TName name; + TRACE( Kern::Printf("DMemSpyInspectedProcess::ChunkType() - getting chunk name..." ) ); + chunk->Name( name ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::ChunkType() - name: %S", &name ) ); + + // It is definitely owned by this process. That means that + // it could be a heap, or then it's a just some other kind + // of data chunk which our process happens to have created. + // + // The main thread within a process results in the creation + // of a heap called $HEAP, but that isn't the case for other + // secondary (etc) threads. + // + // Only way I can think to identify these is via vTables. + if ( name == KMemSpyLitDollarDllData ) + { + // This chunk contains Dll Global Data for the process + TRACE( Kern::Printf("DMemSpyInspectedProcess::ChunkType() - TMemSpyTrackedChunk::ETypeChunkGlobalData" ) ); + ret = TMemSpyTrackedChunk::ETypeChunkGlobalData; + } + else if ( name == KMemSpyLitDollarDat ) + { + // This chunk contains process global data as well as user-side stacks for + // the process. However, we calculate the stacks independently, so we must + // adjust this later on to remove stack overhead. + TRACE( Kern::Printf("DMemSpyInspectedProcess::ChunkType() - TMemSpyTrackedChunk::ETypeChunkProcessGlobalDataAndUserStack" ) ); + ret = TMemSpyTrackedChunk::ETypeChunkProcessGlobalDataAndUserStack; + } + else if ( IsHeapChunk( *chunk, name ) ) + { + TRACE( Kern::Printf("DMemSpyInspectedProcess::ChunkType() - TMemSpyTrackedChunk::ETypeChunkHeap" ) ); + ret = TMemSpyTrackedChunk::ETypeChunkHeap; + } + else + { + TRACE( Kern::Printf("DMemSpyInspectedProcess::ChunkType() - TMemSpyTrackedChunk::ETypeChunkLocal" ) ); + ret = TMemSpyTrackedChunk::ETypeChunkLocal; + } + } + else + { + // It's a chunk that is mapped into our process, + // but isn't owned by us. Therefore it is shared by some + // other process. + TRACE( Kern::Printf("DMemSpyInspectedProcess::ChunkType() - TMemSpyTrackedChunk::ETypeChunkShared" ) ); + ret = TMemSpyTrackedChunk::ETypeChunkShared; + } + } + } + + TRACE( Kern::Printf("DMemSpyInspectedProcess::ChunkType() - END - this: 0x%08x, ret: %d", this, ret ) ); + return ret; + } + + +TBool DMemSpyInspectedProcess::IsHeapChunk( DChunk& aChunk, const TName& aName ) const + { + const TUint rHeapVTable = iDevice.RHeapVTable(); + TRACE( Kern::Printf("DMemSpyInspectedProcess::IsHeapChunk() - START - this: 0x%08x, aChunk: 0x%08x, RHeapVTable: 0x%08x, iProcess: 0x%08x, aName: %S, (%O)", this, &aChunk, rHeapVTable, iProcess, &aName, &aChunk ) ); + + // The first 4 bytes of every chunk correspond to the allocator VTable (For heap chunks). + // If it matches RHeap's vtable, we'll treat it as a heap. + TBool isHeap = EFalse; + + DMemSpyDriverOSAdaptionDChunk& chunkAdaption = iDevice.OSAdaption().DChunk(); + TUint8* base = chunkAdaption.GetBase( aChunk ); + const TInt size = chunkAdaption.GetSize( aChunk ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::IsHeapChunk() - base: 0x%08x, size: %d", base, size ) ); + + if ( iProcess && size >= 4 ) + { + // Chunks are mapped into entire process so any thread within the process is enough... + DThread* firstThread = iProcess->FirstThread(); + TRACE( Kern::Printf("DMemSpyInspectedProcess::IsHeapChunk() - firstThread: 0x%08x (%O)", firstThread, firstThread ) ); + if ( firstThread != NULL ) + { + NKern::ThreadEnterCS(); + TInt err = firstThread->Open(); + TRACE( Kern::Printf("DMemSpyInspectedProcess::IsHeapChunk() - firstThread open result: %d", err ) ); + + if ( err == KErrNone ) + { + TBuf8<4> allocatorVTableBuffer; + err = Kern::ThreadRawRead( firstThread, base, (TUint8*) allocatorVTableBuffer.Ptr(), allocatorVTableBuffer.MaxLength() ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::IsHeapChunk - read result of vtable data from requested thread is: %d", err )); + // + if ( err == KErrNone ) + { + TRACE( MemSpyDriverUtils::DataDump("possible chunk vtable data - %lS", allocatorVTableBuffer.Ptr(), allocatorVTableBuffer.MaxLength(), allocatorVTableBuffer.MaxLength() ) ); + allocatorVTableBuffer.SetLength( allocatorVTableBuffer.MaxLength() ); + + const TUint32 vtable = allocatorVTableBuffer[0] + + (allocatorVTableBuffer[1] << 8) + + (allocatorVTableBuffer[2] << 16) + + (allocatorVTableBuffer[3] << 24); + TRACE( Kern::Printf("DMemSpyInspectedProcess::IsHeapChunk - [possible] vTable within chunk is: 0x%08x", vtable) ); + + // Check the v-table to work out if it really is an RHeap + isHeap = ( vtable == rHeapVTable ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::IsHeapChunk() - isHeap: %d", isHeap ) ); + } + + TRACE( Kern::Printf("DMemSpyInspectedProcess::IsHeapChunk() - closing first thread..." ) ); + Kern::SafeClose( (DObject*&) firstThread, NULL ); + } + NKern::ThreadLeaveCS(); + } + } + // + if ( !isHeap && aName == KMemSpyLitDollarHeap ) + { + TRACE( Kern::Printf("DMemSpyInspectedProcess::IsHeapChunk() - is standard Symbian OS initial heap chunk - $HEAP" ) ); + isHeap = ETrue; + } + // + TRACE( Kern::Printf("DMemSpyInspectedProcess::IsHeapChunk() - END - this: 0x%08x, isHeap: %d", this, isHeap ) ); + return isHeap; + } + + +TUint32 DMemSpyInspectedProcess::TotalStatistics( const TMemSpyDriverProcessInspectionInfo& aStats, TBool aIncludeShared ) + { + TUint32 total = aStats.iMemoryStack + + aStats.iMemoryHeap + + aStats.iMemoryChunkLocal + + aStats.iMemoryGlobalData; + // + if ( aIncludeShared ) + { + total += aStats.iMemoryChunkShared; + } + // + return total; + } + + +TBool DMemSpyInspectedProcess::IsEqual( const TMemSpyDriverProcessInspectionInfo& aLeft, const TMemSpyDriverProcessInspectionInfo& aRight ) + { + const TBool equal = ( aLeft.iMemoryStack == aRight.iMemoryStack && + aLeft.iMemoryHeap == aRight.iMemoryHeap && + aLeft.iMemoryChunkLocal == aRight.iMemoryChunkLocal && + aLeft.iMemoryChunkShared == aRight.iMemoryChunkShared && + aLeft.iMemoryGlobalData == aRight.iMemoryGlobalData + ); + return equal; + } + + +void DMemSpyInspectedProcess::ResetStatistics( TMemSpyDriverProcessInspectionInfo& aStats ) + { + TRACE( Kern::Printf("DMemSpyInspectedProcess::ResetStatistics() - START - this: 0x%08x", this ) ); + aStats.iProcessId = iProcessId; + aStats.iMemoryHeap = 0; + aStats.iMemoryChunkLocal = 0; + aStats.iMemoryChunkShared = 0; + aStats.iMemoryGlobalData = 0; + aStats.iTime = Kern::SystemTime(); + TRACE( Kern::Printf("DMemSpyInspectedProcess::ResetStatistics() - END - this: 0x%08x", this ) ); + } + + +TBool DMemSpyInspectedProcess::UpdateStatistics() + { + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() - START - this: 0x%08x, iChangeDeliveryCounter: %04d, iProcess: 0x%08x %O", this, iChangeDeliveryCounter, iProcess, iProcess ) ); + + // Preserve last stats so we can identify if something really changed... + iInfoLast = iInfoCurrent; + + // Reset current stats ready for updating. This doesn't wipe the stack field, since + // that only changes when some kind of thread event occurs... + ResetStatistics( iInfoCurrent ); + + // Go through all tracked chunks and update our stats based upon + // their current values... + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() " ) ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() " ) ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() " ) ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() CHUNK ENTRIES:" ) ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() " ) ); + const SDblQueLink* const anchor = &iTrackedChunks.iA; + for (SDblQueLink* link = iTrackedChunks.First(); link != anchor; link = link->iNext) + { + TMemSpyTrackedChunk* const trackedChunk = _LOFF( link, TMemSpyTrackedChunk, iLink ); + // + switch( trackedChunk->Type() ) + { + case TMemSpyTrackedChunk::ETypeChunkHeap: + iInfoCurrent.iMemoryHeap += trackedChunk->Size(); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() - [0x%08x] TMemSpyTrackedChunk::ETypeChunkHeap - %12d (0x%08x, %O)", trackedChunk, trackedChunk->Size(), trackedChunk->iChunk, trackedChunk->iChunk ) ); + break; + case TMemSpyTrackedChunk::ETypeChunkLocal: + iInfoCurrent.iMemoryChunkLocal += trackedChunk->Size(); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() - [0x%08x] TMemSpyTrackedChunk::ETypeChunkLocal - %12d (0x%08x, %O)", trackedChunk, trackedChunk->Size(), trackedChunk->iChunk, trackedChunk->iChunk ) ); + break; + case TMemSpyTrackedChunk::ETypeChunkShared: + iInfoCurrent.iMemoryChunkShared += trackedChunk->Size(); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() - [0x%08x] TMemSpyTrackedChunk::ETypeChunkShared - %12d (0x%08x, %O)", trackedChunk, trackedChunk->Size(), trackedChunk->iChunk, trackedChunk->iChunk ) ); + break; + case TMemSpyTrackedChunk::ETypeChunkGlobalData: + iInfoCurrent.iMemoryGlobalData += trackedChunk->Size(); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() - [0x%08x] TMemSpyTrackedChunk::ETypeChunkGlobalData - %12d (0x%08x, %O)", trackedChunk, trackedChunk->Size(), trackedChunk->iChunk, trackedChunk->iChunk ) ); + break; + case TMemSpyTrackedChunk::ETypeChunkProcessGlobalDataAndUserStack: + break; + + default: + case TMemSpyTrackedChunk::ETypeNotRelevant: + break; + } + } + + const TUint32 totalLastIncShared = TotalStatistics( iInfoLast ); + const TUint32 totalLastExcShared = TotalStatistics( iInfoLast, EFalse ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() " ) ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() " ) ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() LAST:" ) ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() " ) ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() - iInfoLast.iMemoryStack: %12d", iInfoLast.iMemoryStack ) ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() - iInfoLast.iMemoryHeap: %12d", iInfoLast.iMemoryHeap ) ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() - iInfoLast.iMemoryChunkLocal: %12d", iInfoLast.iMemoryChunkLocal ) ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() - iInfoLast.iMemoryChunkShared: %12d", iInfoLast.iMemoryChunkShared ) ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() - iInfoLast.iMemoryGlobalData: %12d", iInfoLast.iMemoryGlobalData ) ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() - --------------------------------------------------------------------------" ) ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() - iInfoLast total: %12d / %12d", totalLastIncShared, totalLastExcShared ) ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() " ) ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() " ) ); + + + const TUint32 totalCurrentIncShared = TotalStatistics( iInfoCurrent ); + const TUint32 totalCurrentExcShared = TotalStatistics( iInfoCurrent, EFalse ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() CURRENT:" ) ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() " ) ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() - iInfoCurrent.iMemoryStack: %12d", iInfoCurrent.iMemoryStack ) ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() - iInfoCurrent.iMemoryHeap: %12d", iInfoCurrent.iMemoryHeap ) ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() - iInfoCurrent.iMemoryChunkLocal: %12d", iInfoCurrent.iMemoryChunkLocal ) ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() - iInfoCurrent.iMemoryChunkShared: %12d", iInfoCurrent.iMemoryChunkShared ) ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() - iInfoCurrent.iMemoryGlobalData: %12d", iInfoCurrent.iMemoryGlobalData ) ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() - --------------------------------------------------------------------------" ) ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() - iInfoCurrent total: %12d / %12d", totalCurrentIncShared, totalCurrentExcShared ) ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() " ) ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() " ) ); + + // Update peaks, i.e. how large each individual element reached + const TUint32 totalPeaks = TotalStatistics( iInfoPeaks ); + iInfoPeaks.iMemoryStack = Max( iInfoPeaks.iMemoryStack, iInfoCurrent.iMemoryStack ); + iInfoPeaks.iMemoryHeap = Max( iInfoPeaks.iMemoryHeap, iInfoCurrent.iMemoryHeap ); + iInfoPeaks.iMemoryChunkLocal = Max( iInfoPeaks.iMemoryChunkLocal, iInfoCurrent.iMemoryChunkLocal ); + iInfoPeaks.iMemoryChunkShared = Max( iInfoPeaks.iMemoryChunkShared, iInfoCurrent.iMemoryChunkShared ); + iInfoPeaks.iMemoryGlobalData = Max( iInfoPeaks.iMemoryGlobalData, iInfoCurrent.iMemoryGlobalData ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() PEAK:" ) ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() " ) ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() - iInfoPeaks.iMemoryStack: %12d", iInfoPeaks.iMemoryStack ) ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() - iInfoPeaks.iMemoryHeap: %12d", iInfoPeaks.iMemoryHeap ) ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() - iInfoPeaks.iMemoryChunkLocal: %12d", iInfoPeaks.iMemoryChunkLocal ) ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() - iInfoPeaks.iMemoryChunkShared: %12d", iInfoPeaks.iMemoryChunkShared ) ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() - iInfoPeaks.iMemoryGlobalData: %12d", iInfoPeaks.iMemoryGlobalData ) ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() - -----------------------------------------------------" ) ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() - iInfoPeaks total: %12d", totalPeaks ) ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() " ) ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() " ) ); + + // Update HWM, i.e. the largest total so far. + const TUint32 totalHWMIncShared = TotalStatistics( iInfoHWMIncShared ); + const TUint32 totalHWMExcShared = TotalStatistics( iInfoHWMIncShared, EFalse ); + if ( totalCurrentIncShared > totalHWMIncShared ) + { + iInfoHWMIncShared = iInfoCurrent; + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() HWM INC SHARED:" ) ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() " ) ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() - iInfoHWMIncShared.iMemoryStack: %12d", iInfoHWMIncShared.iMemoryStack ) ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() - iInfoHWMIncShared.iMemoryHeap: %12d", iInfoHWMIncShared.iMemoryHeap ) ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() - iInfoHWMIncShared.iMemoryChunkLocal: %12d", iInfoHWMIncShared.iMemoryChunkLocal ) ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() - iInfoHWMIncShared.iMemoryChunkShared: %12d", iInfoHWMIncShared.iMemoryChunkShared ) ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() - iInfoHWMIncShared.iMemoryGlobalData: %12d", iInfoHWMIncShared.iMemoryGlobalData ) ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() - -----------------------------------------------------" ) ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() - iInfoHWMIncShared total: %12d", totalHWMIncShared ) ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() " ) ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() " ) ); + } + if ( totalCurrentExcShared > totalHWMExcShared ) + { + iInfoHWMExcShared = iInfoCurrent; + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() HWM EXC SHARED:" ) ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() " ) ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() - iInfoHWMExcShared.iMemoryStack: %12d", iInfoHWMExcShared.iMemoryStack ) ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() - iInfoHWMExcShared.iMemoryHeap: %12d", iInfoHWMExcShared.iMemoryHeap ) ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() - iInfoHWMExcShared.iMemoryChunkLocal: %12d", iInfoHWMExcShared.iMemoryChunkLocal ) ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() - iInfoHWMExcShared.iMemoryChunkShared: %12d", iInfoHWMExcShared.iMemoryChunkShared ) ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() - iInfoHWMExcShared.iMemoryGlobalData: %12d", iInfoHWMExcShared.iMemoryGlobalData ) ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() - -----------------------------------------------------" ) ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() - iInfoHWMExcShared total: %12d", totalHWMExcShared ) ); + } + + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() " ) ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() " ) ); + + // Work out if something changed... + const TBool statsChanged = !IsEqual( iInfoLast, iInfoCurrent ); + if ( statsChanged ) + { + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() - STATS CHANGED!" ) ); + } + + TRACE( Kern::Printf("DMemSpyInspectedProcess::UpdateStatistics() - END - this: 0x%08x, statsChanged: %d, iChangeDeliveryCounter: %04d, iProcess: 0x%08x %O", this, statsChanged, iChangeDeliveryCounter, iProcess, iProcess ) ); + return statsChanged; + } + + +void DMemSpyInspectedProcess::FindChunks( DProcess& aProcess ) + { + __ASSERT_CRITICAL; + TRACE( Kern::Printf("DMemSpyInspectedProcess::FindChunks() - START - this: 0x%08x", this ) ); + + DMemSpyDriverOSAdaptionDChunk& chunkAdaption = iDevice.OSAdaption().DChunk(); + DMemSpyDriverOSAdaptionDProcess& processAdaption = iDevice.OSAdaption().DProcess(); + + // Iterate through each handle in the process + if ( processAdaption.IsHandleIndexValid( aProcess ) ) + { + MemSpyObjectIx* processHandles = processAdaption.GetHandles( aProcess ); + + MemSpyObjectIx_HandleLookupLock(); + const TInt count = processHandles->Count(); + MemSpyObjectIx_HandleLookupUnlock(); + + TRACE( Kern::Printf("DMemSpyInspectedProcess::FindChunks() - got: %d handles...", count ) ); + + for( TInt i=0; i= processHandles->Count()) break; // Count may have changed in the meantime + DObject* object = (*processHandles)[ i ]; + if (object && object->Open() != KErrNone) object = NULL; + MemSpyObjectIx_HandleLookupUnlock(); + + const TObjectType objectType = ( object ? chunkAdaption.GetObjectType( *object ) : EObjectTypeAny ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::FindChunks() - object: 0x%08x, type: %2d (%O)", object, objectType, object ) ); + + // Is it a chunk that is already mapped into our process? + // See if we're already aware of this chunk... + if ( object != NULL && objectType == EChunk ) + { + TMemSpyTrackedChunk* existingEntry = TrackedChunkByHandle( object ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::FindChunks() - found a chunk, existing lookup entry: 0x%08x", existingEntry ) ); + + if ( existingEntry != NULL ) + { + const TInt cSize = chunkAdaption.GetSize( *existingEntry->iChunk ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::FindChunks() - setting existing entry size to: %d", cSize ) ); + + // It must be a chunk then... Update size + existingEntry->SetSize( cSize ); + + // This item is in use, i.e. it is not unused + existingEntry->SetUnused( EFalse ); + } + else + { + DChunk* chunk = (DChunk*) object; + TRACE( Kern::Printf("DMemSpyInspectedProcess::FindChunks() - chunk not known, checking type..." ) ); + + // We have no record of this item so far. Is it really a chunk? + const TMemSpyTrackedChunk::TType type = ChunkType( object ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::FindChunks() - type is: %d", type ) ); + + if ( type != TMemSpyTrackedChunk::ETypeNotRelevant ) + { + // It's a new entry + TRACE( Kern::Printf("DMemSpyInspectedProcess::FindChunks() - this: 0x%08x, creating new entry for chunk: 0x%08x", this, chunk ) ); + + AddTrackedChunk( chunk, type ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::FindChunks() - added chunk..." )); + } + } + } + if (object) object->Close(NULL); + } + } + + TRACE( Kern::Printf("DMemSpyInspectedProcess::FindChunks() - END - this: 0x%08x", this ) ); + } + + +TInt DMemSpyInspectedProcess::StackSize( DProcess& aProcess ) + { + TRACE( Kern::Printf("DMemSpyInspectedProcess::StackSize() - START - this: 0x%08x", this ) ); + TInt ret = 0; + // + DMemSpyDriverOSAdaptionDThread& dThreadAdaption = iDevice.OSAdaption().DThread(); + + iUserThreadStackSize = 0; + // + SDblQueLink* pLink = aProcess.iThreadQ.First(); + while(pLink != &aProcess.iThreadQ.iA) + { + DThread* pT = _LOFF( pLink, DThread, iProcessLink ); + // + const TUint32 userStackSize = dThreadAdaption.GetUserStackSize( *pT ); + const TUint32 suprStackSize = dThreadAdaption.GetSupervisorStackSize( *pT ); + TRACE( Kern::Printf("DMemSpyInspectedProcess::StackSize() - thread: 0x%08x, userStack: %8d, suprStack: %8d, total: %8d %O", pT, userStackSize, suprStackSize, userStackSize + suprStackSize, pT )); + // + iUserThreadStackSize += userStackSize; + ret += userStackSize + suprStackSize; + // + pLink = pLink->iNext; + } + // + TRACE( Kern::Printf("DMemSpyInspectedProcess::StackSize() - END - this: 0x%08x, total stack size for process: %8d, iUserThreadStackSize: %8d", this, ret, iUserThreadStackSize ) ); + return ret; + } + + +void DMemSpyInspectedProcess::ResetPendingChanges() + { + TRACE( Kern::Printf("DMemSpyInspectedProcess::ResetPendingChanges() - START - this: 0x%08x", this ) ); + NKern::ThreadEnterCS(); + // + SDblQueLink* link = iPendingChanges.GetFirst(); + while( link ) + { + TMemSpyTrackedChunkChangeInfo* cachedChange = _LOFF( link, TMemSpyTrackedChunkChangeInfo, iLink ); + delete cachedChange; + link = iPendingChanges.GetFirst(); + } + // + NKern::ThreadLeaveCS(); + TRACE( Kern::Printf("DMemSpyInspectedProcess::ResetPendingChanges() - END - this: 0x%08x", this ) ); + } + + +void DMemSpyInspectedProcess::Lock() const + { + NKern::ThreadEnterCS(); + Kern::MutexWait(*iLock); + } + +void DMemSpyInspectedProcess::Unlock() const + { + Kern::MutexSignal(*iLock); + NKern::ThreadLeaveCS(); + } + + + + + + + + + + +TMemSpyTrackedChunk::TMemSpyTrackedChunk( DChunk* aChunk, TType aType ) +: iChunk( aChunk ), iType( aType ), iSize( 0 ), iUnused( EFalse ) + { + } + + +void TMemSpyTrackedChunk::SetSize( TInt aSize ) + { + iSize = aSize; + } + + +void TMemSpyTrackedChunk::SetUnused( TBool aUnused ) + { + iUnused = aUnused; + } +