--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/memspy/Engine/Source/ThreadAndProcess/MemSpyEngineObjectContainer.cpp Tue Feb 02 01:57:15 2010 +0200
@@ -0,0 +1,958 @@
+/*
+* 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 <memspy/engine/memspyengineobjectcontainer.h>
+
+// System includes
+#include <e32svr.h>
+
+// Driver includes
+#include <memspy/driver/memspydriverclient.h>
+
+// User includes
+#include <memspy/engine/memspyengine.h>
+#include <memspy/engine/memspyengineutils.h>
+#include <memspy/engine/memspyengineobjectprocess.h>
+#include <memspy/engine/memspyengineobjectthread.h>
+#include <memspy/engine/memspyenginehelperheap.h>
+#include <memspy/engine/memspyenginehelperstack.h>
+#include <memspy/engine/memspyenginehelpercodesegment.h>
+
+// Literal constants
+_LIT(KProcessFilter, "*");
+_LIT(KEKernProcessName, "ekern");
+
+
+CMemSpyEngineObjectContainer::CMemSpyEngineObjectContainer( CMemSpyEngine& aEngine )
+: iEngine( aEngine )
+ {
+ /*
+ TFindProcess procFinder( KProcessFilter );
+ TFullName nextMatch;
+ //
+ while( procFinder.Next( nextMatch ) == KErrNone )
+ {
+ _LIT(KProcListing, "%S");
+ RDebug::Print(KProcListing, &nextMatch);
+
+
+ _LIT(KFindMask, "*");
+ nextMatch += KFindMask;
+ //
+ TFindThread threadFinder( nextMatch );
+ //
+ while( threadFinder.Next( nextMatch ) == KErrNone )
+ {
+ _LIT(KThreadListing, "+--- %S");
+ RDebug::Print(KThreadListing, &nextMatch);
+ }
+ }
+ */
+ }
+
+
+CMemSpyEngineObjectContainer::~CMemSpyEngineObjectContainer()
+ {
+ DestroyProcesses( iGarbage );
+ DestroyProcesses( iProcesses );
+ delete iUndertaker;
+ delete iMidwife;
+ delete iIdleNotifyContainerChanged;
+ }
+
+
+void CMemSpyEngineObjectContainer::ConstructL( const TDesC& aFilter )
+ {
+ iUndertaker = CMemSpyEngineUndertaker::NewL( iEngine.Driver() );
+ iUndertaker->AddObserverL( *this );
+ //
+ iMidwife = CMemSpyEngineMidwife::NewL( iEngine.Driver() );
+ iMidwife->AddObserverL( *this );
+ //
+ iIdleNotifyContainerChanged = CIdle::NewL( CActive::EPriorityIdle );
+ //
+ RefreshL( aFilter );
+ }
+
+
+CMemSpyEngineObjectContainer* CMemSpyEngineObjectContainer::NewL( CMemSpyEngine& aEngine )
+ {
+ return NewL( KProcessFilter, aEngine );
+ }
+
+
+CMemSpyEngineObjectContainer* CMemSpyEngineObjectContainer::NewL( const TDesC& aFilter, CMemSpyEngine& aEngine )
+ {
+ CMemSpyEngineObjectContainer* self = new(ELeave) CMemSpyEngineObjectContainer( aEngine );
+ CleanupStack::PushL( self );
+ self->ConstructL( aFilter );
+ CleanupStack::Pop( self );
+ return self;
+ }
+
+
+EXPORT_C TInt CMemSpyEngineObjectContainer::Count() const
+ {
+ return iProcesses.Count();
+ }
+
+
+EXPORT_C TInt CMemSpyEngineObjectContainer::CountAll() const
+ {
+ TInt ret = 0;
+ //
+ const TInt count = iProcesses.Count();
+ for( TInt i=0; i<count; i++ )
+ {
+ CMemSpyProcess* process = iProcesses[ i ];
+ ret += process->Count();
+ }
+ //
+ return ret;
+ }
+
+
+EXPORT_C void CMemSpyEngineObjectContainer::RefreshL()
+ {
+ RefreshL( KProcessFilter );
+ }
+
+
+EXPORT_C void CMemSpyEngineObjectContainer::RefreshL( const TDesC& aFilter )
+ {
+ LocateProcessesL( aFilter );
+ }
+
+
+EXPORT_C CMemSpyProcess& CMemSpyEngineObjectContainer::At( TInt aIndex ) const
+ {
+ CMemSpyProcess* ret = iProcesses[ aIndex ];
+ return *ret;
+ }
+
+
+EXPORT_C CMemSpyProcess& CMemSpyEngineObjectContainer::ProcessByIdL( TProcessId aId ) const
+ {
+ CMemSpyProcess* ret = NULL;
+ //
+ const TInt count = iProcesses.Count();
+ for( TInt i=0; i<count; i++ )
+ {
+ CMemSpyProcess* process = iProcesses[ i ];
+ if ( process->Id() == aId )
+ {
+ ret = process;
+ break;
+ }
+ }
+ //
+ if ( ret == NULL )
+ {
+ User::Leave( KErrNotFound );
+ }
+ //
+ return *ret;
+ }
+
+
+EXPORT_C TInt CMemSpyEngineObjectContainer::ProcessIndexById( TProcessId aId ) const
+ {
+ TInt index = KErrNotFound;
+ //
+ const TInt count = iProcesses.Count();
+ for( TInt i=0; i<count; i++ )
+ {
+ const CMemSpyProcess* process = iProcesses[ i ];
+ if ( process->Id() == aId )
+ {
+ index = i;
+ break;
+ }
+ }
+ //
+ return index;
+ }
+
+
+EXPORT_C TInt CMemSpyEngineObjectContainer::ProcessAndThreadByThreadId( TThreadId aTid, CMemSpyProcess*& aProcess, CMemSpyThread*& aThread ) const
+ {
+ aProcess = NULL;
+ aThread = NULL;
+ TInt error = KErrNotFound;
+ //
+ const TInt count = iProcesses.Count();
+ for( TInt i=0; i<count; i++ )
+ {
+ CMemSpyProcess* process = iProcesses[ i ];
+
+ // Check whether this process contains the thread we are looking for...
+ const TInt index = process->ThreadIndexById( aTid );
+ if ( index >= 0 )
+ {
+ // Found it
+ aProcess = process;
+ aThread = &process->At( index );
+ error = KErrNone;
+ break;
+ }
+ }
+ //
+ if ( error == KErrNotFound )
+ {
+ CMemSpyEngineObjectContainer* self = const_cast< CMemSpyEngineObjectContainer* >( this );
+ TRAP( error, self->TryToCreateProcessAndThreadL( aTid, aProcess, aThread ) );
+ }
+ //
+ return error;
+ }
+
+
+EXPORT_C TInt CMemSpyEngineObjectContainer::ProcessAndThreadByFullName( const TDesC& aFullName, CMemSpyProcess*& aProcess, CMemSpyThread*& aThread ) const
+ {
+ aProcess = NULL;
+ aThread = NULL;
+ TInt error = KErrNotFound;
+ //
+ const TInt count = iProcesses.Count();
+ for( TInt i=0; i<count && aThread == NULL; i++ )
+ {
+ CMemSpyProcess& process = *iProcesses[ i ];
+ const TInt threadCount = process.Count();
+ //
+ for(TInt j=0; j<threadCount; j++)
+ {
+ CMemSpyThread& thread = process.At( j );
+ const TFullName threadName( thread.FullName() );
+ //
+ if ( threadName.CompareF( aFullName ) == 0 )
+ {
+ // Found it
+ aProcess = &process;
+ aThread = &thread;
+ error = KErrNone;
+ break;
+ }
+ }
+
+ }
+ //
+ if ( error == KErrNotFound )
+ {
+ // NB: cannot use driver API as we must open thread by name, and that only supports opening
+ // by id.
+ RThread thread;
+ error = thread.Open( aFullName );
+ if ( error == KErrNone )
+ {
+ const TThreadId threadId = thread.Id();
+ thread.Close();
+
+ CMemSpyEngineObjectContainer* self = const_cast< CMemSpyEngineObjectContainer* >( this );
+ TRAP( error, self->TryToCreateProcessAndThreadL( threadId, aProcess, aThread ) );
+ }
+ }
+ //
+ return error;
+ }
+
+
+EXPORT_C TInt CMemSpyEngineObjectContainer::ProcessAndThreadByPartialName( const TDesC& aPartialName, CMemSpyProcess*& aProcess, CMemSpyThread*& aThread ) const
+ {
+ aProcess = NULL;
+ aThread = NULL;
+ TInt error = KErrNotFound;
+ //
+ const TInt count = iProcesses.Count();
+ for( TInt i=0; i<count && aThread == NULL; i++ )
+ {
+ CMemSpyProcess& process = *iProcesses[ i ];
+ const TInt threadCount = process.Count();
+ //
+ for(TInt j=0; j<threadCount; j++)
+ {
+ CMemSpyThread& thread = process.At( j );
+ const TFullName threadName( thread.FullName() );
+ //
+ if ( threadName.FindF( aPartialName ) >= 0 )
+ {
+ // Found it
+ aProcess = &process;
+ aThread = &thread;
+ error = KErrNone;
+ break;
+ }
+ }
+
+ }
+ //
+ return error;
+ }
+
+
+EXPORT_C TBool CMemSpyEngineObjectContainer::IsAlive( TProcessId aPid ) const
+ {
+ const TInt processIndex = ProcessIndexById( aPid );
+ return ( processIndex >= 0 );
+ }
+
+
+EXPORT_C TBool CMemSpyEngineObjectContainer::IsAlive( TProcessId aPid, TThreadId aTid ) const
+ {
+ TBool isAlive = IsAlive( aPid );
+ if ( isAlive )
+ {
+ const TInt processIndex = ProcessIndexById( aPid );
+ const CMemSpyProcess& process = At( processIndex );
+
+ // Check whether the thread is alive
+ isAlive = ( process.ThreadIndexById( aTid ) >= 0 );
+ }
+ //
+ return isAlive;
+ }
+
+
+EXPORT_C TInt CMemSpyEngineObjectContainer::MdcaCount() const
+ {
+ return iProcesses.Count();
+ }
+
+
+EXPORT_C TPtrC CMemSpyEngineObjectContainer::MdcaPoint(TInt aIndex) const
+ {
+ const CMemSpyProcess* process = iProcesses[ aIndex ];
+ return TPtrC( process->NameForListBox() );
+ }
+
+
+void CMemSpyEngineObjectContainer::LocateProcessesL( const TDesC& aFilter )
+ {
+#ifdef _DEBUG
+ RDebug::Printf( "CMemSpyEngineObjectContainer::LocateProcessesL() - START" );
+#endif
+ DestroyProcesses( iProcesses );
+ //
+ const TProcessId myProcessId = RProcess().Id();
+ //
+ TFindProcess finder( aFilter );
+ TFullName nextMatch;
+ //
+ while( finder.Next( nextMatch ) == KErrNone )
+ {
+ if ( nextMatch.FindF(KEKernProcessName) == KErrNotFound )
+ {
+#ifdef _DEBUG
+ RDebug::Print(_L( "CMemSpyEngineObjectContainer::LocateProcessesL() - found Proc: %S"), &nextMatch );
+#endif
+
+ RProcess p;
+ const TInt r = p.Open( nextMatch );
+ TProcessId processId( KNullProcessId );
+ if ( r == KErrNone )
+ {
+ processId = p.Id();
+ }
+ p.Close();
+
+#ifdef _DEBUG
+ RDebug::Printf( "CMemSpyEngineObjectContainer::LocateProcessesL() - open err: %d", r );
+#endif
+
+ if ( r == KErrNone )
+ {
+ if ( processId != myProcessId )
+ {
+ TRAPD( err, CreateProcessL( processId ) );
+#ifdef _DEBUG
+ RDebug::Printf( "CMemSpyEngineObjectContainer::LocateProcessesL() - CreateProcessL err: %d", err );
+#endif
+ err = err;
+ }
+ }
+ }
+ }
+ //
+ SortByName();
+
+#ifdef _DEBUG
+ RDebug::Printf( "CMemSpyEngineObjectContainer::LocateProcessesL() - END" );
+#endif
+ }
+
+
+CMemSpyProcess* CMemSpyEngineObjectContainer::CreateProcessL( const TProcessId& aId )
+ {
+#ifdef _DEBUG
+ RDebug::Printf( "[MemSpy] CMemSpyEngineObjectContainer::CreateProcessL() - START - pid: 0x%04x", (TUint) aId );
+#endif
+
+ CMemSpyProcess* processObj = CMemSpyProcess::NewLC( aId, iEngine );
+ const TPtrC pName( processObj->Name() );
+
+ if ( pName.FindF( KEKernProcessName ) == KErrNotFound )
+ {
+ if ( processObj->Count() == 0 )
+ {
+ // Calls delete
+#ifdef _DEBUG
+ RDebug::Printf( "[MemSpy] CMemSpyEngineObjectContainer::CreateProcessL() - process has no threads... deleting it!" );
+#endif
+ processObj->Close();
+ processObj = NULL;
+ }
+ else
+ {
+ // Make sure we don't add duplicate processes...
+ AppendL( processObj );
+ }
+ }
+ else
+ {
+ // We don't support kernel-side threads
+#ifdef _DEBUG
+ RDebug::Printf( "[MemSpy] CMemSpyEngineObjectContainer::CreateProcessL() - kernel process... deleting it!" );
+#endif
+ processObj->Close();
+ processObj = NULL;
+ }
+
+ CleanupStack::Pop();
+
+#ifdef _DEBUG
+ RDebug::Printf( "[MemSpy] CMemSpyEngineObjectContainer::CreateProcessL() - END - pid: 0x%04x, processObj: 0x%08x", (TUint) aId, processObj );
+#endif
+ return processObj;
+ }
+
+
+void CMemSpyEngineObjectContainer::DestroyProcesses( RArray< CMemSpyProcess* >& aList )
+ {
+ while( aList.Count() )
+ {
+ CMemSpyProcess* process = aList[ 0 ];
+ aList.Remove( 0 );
+ process->Close();
+ }
+
+ aList.Close();
+ }
+
+
+void CMemSpyEngineObjectContainer::TryToCreateProcessAndThreadL( const TThreadId& aTid, CMemSpyProcess*& aProcess, CMemSpyThread*& aThread )
+ {
+#ifdef _DEBUG
+ RDebug::Printf( "[MemSpy] CMemSpyEngineObjectContainer::TryToCreateProcessAndThreadL(1) - START - aTid: 0x%04x", (TUint) aTid );
+#endif
+
+ // Must open thread and process in order to get process id.
+ RThread thread;
+ User::LeaveIfError( iEngine.Driver().OpenThread( aTid, thread ) );
+ CleanupClosePushL( thread );
+ RProcess process;
+ User::LeaveIfError( thread.Process( process ) );
+ const TProcessId processId = process.Id();
+ process.Close();
+
+ // Call overload
+ TryToCreateProcessAndThreadL( thread, aProcess, aThread );
+
+ CleanupStack::PopAndDestroy( &thread );
+
+#ifdef _DEBUG
+ RDebug::Printf( "[MemSpy] CMemSpyEngineObjectContainer::TryToCreateProcessAndThreadL(1) - END - aTid: 0x%04x", (TUint) aTid );
+#endif
+ }
+
+
+void CMemSpyEngineObjectContainer::TryToCreateProcessAndThreadL( const RThread& aRThread, CMemSpyProcess*& aProcess, CMemSpyThread*& aThread )
+ {
+#ifdef _DEBUG
+ RDebug::Printf( "[MemSpy] CMemSpyEngineObjectContainer::TryToCreateProcessAndThreadL(2) - START - aTid: 0x%04x", (TUint) aRThread.Id() );
+#endif
+
+ // Full name of process
+ TFullName* name = new(ELeave) TFullName();
+ CleanupStack::PushL( name );
+
+ // Must open thread and process in order to get process id.
+ RProcess process;
+ User::LeaveIfError( aRThread.Process( process ) );
+ process.FullName( *name );
+ const TProcessId processId = process.Id();
+ process.Close();
+
+ const TBool isKernel = ( name->FindF( KEKernProcessName ) >= KErrNone );
+
+#ifdef _DEBUG
+ RDebug::Print( _L("[MemSpy] CMemSpyEngineObjectContainer::TryToCreateProcessAndThreadL(2) - pid: 0x%04x, name: %S"), (TUint) processId, name );
+#endif
+
+ CleanupStack::PopAndDestroy( name );
+
+ // See if we have already created a process for this process id...
+ CMemSpyProcess* processObj = NULL;
+ const TInt procIndex = ProcessIndexById( processId );
+
+#ifdef _DEBUG
+ RDebug::Print( _L("[MemSpy] CMemSpyEngineObjectContainer::TryToCreateProcessAndThreadL(2) - pid: 0x%04x, index: %d"), (TUint) processId, procIndex );
+#endif
+
+ if ( isKernel )
+ {
+#ifdef _DEBUG
+ RDebug::Printf( "[MemSpy] CMemSpyEngineObjectContainer::TryToCreateProcessAndThreadL(2) - caller requested a kernel thread/process..." );
+#endif
+ __ASSERT_ALWAYS( procIndex == KErrNotFound, MemSpyEngineUtils::Panic( EMemSpyEnginePanicEncounteredKernelUnexpectedly ) );
+
+#ifdef _DEBUG
+ RDebug::Printf( "[MemSpy] CMemSpyEngineObjectContainer::TryToCreateProcessAndThreadL(2) - leaving with KErrNotSupported" );
+#endif
+ User::Leave( KErrNotSupported );
+ }
+ else if ( aRThread.Id() == RThread().Id() )
+ {
+ TRACE( RDebug::Printf( "[MemSpy] CMemSpyEngineObjectContainer::TryToCreateProcessAndThreadL(2) - trying to create MemSpy -> leaving with KErrNotSupported" ) );
+ User::Leave( KErrNotSupported );
+ }
+ else
+ {
+ if ( procIndex >= 0 )
+ {
+ // Existing process, but new thread?
+ processObj = iProcesses[ procIndex ];
+
+ // Make new thread
+ processObj->HandleThreadIsBornL( aRThread.Id() );
+ }
+ else
+ {
+ // Must also create a new process. This should, in theory, ensure
+ // the thread is also created.
+ processObj = CMemSpyProcess::NewLC( processId, iEngine );
+ if ( processObj->Count() == 0 )
+ {
+ // No threads, discard process and leave
+ User::Leave( KErrNotFound );
+ }
+ else
+ {
+ // Save process
+ AppendL( processObj );
+ }
+
+ // Tidy up
+ CleanupStack::Pop();
+ }
+
+ // Check to see if the process contains the specified thread (it should do, since we just found
+ // the process using it).
+ CMemSpyThread& threadObj = processObj->ThreadByIdL( aRThread.Id() );
+
+ // We're done now.
+ aProcess = processObj;
+ aThread = &threadObj;
+
+ // Update sort order
+ Resort();
+
+ // Signal UI
+ AsyncNotifyUiOfContainerChanges();
+ }
+
+#ifdef _DEBUG
+ RDebug::Printf( "[MemSpy] CMemSpyEngineObjectContainer::TryToCreateProcessAndThreadL(2) - END - aTid: 0x%04x, pid: 0x%04x", (TUint) aRThread.Id(), (TUint) processId );
+#endif
+ }
+
+
+void CMemSpyEngineObjectContainer::Resort()
+ {
+ switch( iSortType )
+ {
+ case ESortById:
+ {
+ TLinearOrder< CMemSpyProcess* > comparer( CompareById );
+ iProcesses.Sort( comparer );
+ }
+ break;
+ default:
+ case ESortByName:
+ {
+ TLinearOrder< CMemSpyProcess* > comparer( CompareByName );
+ iProcesses.Sort( comparer );
+ }
+ break;
+ case ESortByThreadCount:
+ {
+ TLinearOrder< CMemSpyProcess* > comparer( CompareByThreadCount );
+ iProcesses.Sort( comparer );
+ }
+ break;
+ case ESortByCodeSegs:
+ {
+ TLinearOrder< CMemSpyProcess* > comparer( CompareByCodeSegs );
+ iProcesses.Sort( comparer );
+ }
+ break;
+ case ESortByHeapUsage:
+ {
+ TLinearOrder< CMemSpyProcess* > comparer( CompareByHeapUsage );
+ iProcesses.Sort( comparer );
+ }
+ break;
+ case ESortByStackUsage:
+ {
+ TLinearOrder< CMemSpyProcess* > comparer( CompareByStackUsage );
+ iProcesses.Sort( comparer );
+ }
+ break;
+ }
+ }
+
+
+EXPORT_C void CMemSpyEngineObjectContainer::SortById()
+ {
+ iSortType = ESortById;
+ Resort();
+ }
+
+
+EXPORT_C void CMemSpyEngineObjectContainer::SortByName()
+ {
+ iSortType = ESortByName;
+ Resort();
+ }
+
+
+EXPORT_C void CMemSpyEngineObjectContainer::SortByThreadCount()
+ {
+ iSortType = ESortByThreadCount;
+ Resort();
+ }
+
+
+EXPORT_C void CMemSpyEngineObjectContainer::SortByCodeSegs()
+ {
+ iSortType = ESortByCodeSegs;
+ Resort();
+ }
+
+
+EXPORT_C void CMemSpyEngineObjectContainer::SortByHeapUsage()
+ {
+ iSortType = ESortByHeapUsage;
+ Resort();
+ }
+
+
+EXPORT_C void CMemSpyEngineObjectContainer::SortByStackUsage()
+ {
+ iSortType = ESortByStackUsage;
+ Resort();
+ }
+
+
+void CMemSpyEngineObjectContainer::Remove( CMemSpyProcess& aProcess )
+ {
+ const TInt index = ProcessIndexById( aProcess.Id() );
+ if ( index >= 0 )
+ {
+ iProcesses.Remove( index );
+ }
+ }
+
+
+void CMemSpyEngineObjectContainer::AppendL( CMemSpyProcess* aProcess )
+ {
+ const TInt error = iProcesses.Append( aProcess );
+ User::LeaveIfError( error );
+ }
+
+
+TInt CMemSpyEngineObjectContainer::CompareById( CMemSpyProcess* const & aLeft, CMemSpyProcess* const & aRight )
+ {
+ TInt ret = 1;
+ //
+ if ( aLeft->Id() < aRight->Id() )
+ {
+ ret = -1;
+ }
+ else if ( aLeft->Id() == aRight->Id() )
+ {
+ ret = 0;
+ }
+ //
+ return ret;
+ }
+
+
+TInt CMemSpyEngineObjectContainer::CompareByThreadCount( CMemSpyProcess* const & aLeft, CMemSpyProcess* const & aRight )
+ {
+ TInt ret = -1;
+ //
+ if ( aLeft->Count() < aRight->Count() )
+ {
+ ret = 1;
+ }
+ else if ( aLeft->Count() == aRight->Count() )
+ {
+ // Sort by name when thread counts are the same
+ ret = aLeft->Name().CompareF( aRight->Name() );
+ }
+ //
+ return ret;
+ }
+
+
+TInt CMemSpyEngineObjectContainer::CompareByName( CMemSpyProcess* const & aLeft, CMemSpyProcess* const & aRight )
+ {
+ return aLeft->Name().CompareF( aRight->Name() );
+ }
+
+
+TInt CMemSpyEngineObjectContainer::CompareByCodeSegs( CMemSpyProcess* const & aLeft, CMemSpyProcess* const & aRight )
+ {
+ CMemSpyEngine& engine = aLeft->Engine();
+ CMemSpyEngineHelperCodeSegment& helper = engine.HelperCodeSegment();
+ //
+ TInt leftCount = 0;
+ TInt rightCount = 0;
+ //
+ TRAP_IGNORE(
+ CMemSpyEngineCodeSegList* leftList = helper.CodeSegmentListL( aLeft->Id() );
+ leftCount = leftList->Count();
+ delete leftList;
+ //
+ CMemSpyEngineCodeSegList* rightList = helper.CodeSegmentListL( aRight->Id() );
+ rightCount = rightList->Count();
+ delete rightList;
+ );
+ //
+ TInt ret = -1;
+ //
+ if ( leftCount < rightCount )
+ {
+ ret = 1;
+ }
+ else if ( leftCount == rightCount )
+ {
+ ret = 0;
+ }
+ //
+ return ret;
+ }
+
+
+TInt CMemSpyEngineObjectContainer::CompareByHeapUsage( CMemSpyProcess* const & aLeft, CMemSpyProcess* const & aRight )
+ {
+ CMemSpyEngine& engine = aLeft->Engine();
+ CMemSpyEngineHelperHeap& helper = engine.HelperHeap();
+ //
+ TInt leftSize = 0;
+ TInt rightSize = 0;
+ //
+ TRAP_IGNORE(
+ RArray< TMemSpyHeapInfo > leftInfos;
+ CleanupClosePushL( leftInfos );
+ helper.GetHeapInfoUserL( *aLeft, leftInfos );
+ const TInt leftCount = leftInfos.Count();
+ for( TInt i=0; i<leftCount; i++ )
+ {
+ const TMemSpyHeapInfo& info = leftInfos[ i ];
+ if ( info.Type() == TMemSpyHeapInfo::ETypeRHeap )
+ {
+ leftSize += (TInt) info.AsRHeap().ObjectData().Size();
+ }
+ }
+ CleanupStack::PopAndDestroy( &leftInfos );
+ );
+ //
+ TRAP_IGNORE(
+ RArray< TMemSpyHeapInfo > rightInfos;
+ CleanupClosePushL( rightInfos );
+ helper.GetHeapInfoUserL( *aRight, rightInfos );
+ const TInt rightCount = rightInfos.Count();
+ for( TInt i=0; i<rightCount; i++ )
+ {
+ const TMemSpyHeapInfo& info = rightInfos[ i ];
+ if ( info.Type() == TMemSpyHeapInfo::ETypeRHeap )
+ {
+ rightSize += (TInt) info.AsRHeap().ObjectData().Size();
+ }
+ }
+ CleanupStack::PopAndDestroy( &rightInfos );
+ );
+ //
+ TInt ret = -1;
+ //
+ if ( leftSize < rightSize )
+ {
+ ret = 1;
+ }
+ else if ( leftSize == rightSize )
+ {
+ ret = 0;
+ }
+ //
+ return ret;
+ }
+
+
+TInt CMemSpyEngineObjectContainer::CompareByStackUsage( CMemSpyProcess* const & aLeft, CMemSpyProcess* const & aRight )
+ {
+ CMemSpyEngine& engine = aLeft->Engine();
+ CMemSpyEngineHelperStack& helper = engine.HelperStack();
+ //
+ const TInt leftCount = helper.CalculateStackSizes( *aLeft );
+ const TInt rightCount = helper.CalculateStackSizes( *aRight );
+ //
+ TInt ret = -1;
+ //
+ if ( leftCount < rightCount )
+ {
+ ret = 1;
+ }
+ else if ( leftCount == rightCount )
+ {
+ ret = 0;
+ }
+ //
+ return ret;
+ }
+
+
+TBool CMemSpyEngineObjectContainer::MoveToGarbageL( const TProcessId& aId )
+ {
+ const TInt pos = ProcessIndexById( aId );
+
+ if ( pos >= 0 )
+ {
+ CMemSpyProcess* proc = iProcesses[ pos ];
+
+#ifdef _DEBUG
+ const TPtrC pName( proc->Name() );
+ RDebug::Print( _L("[MemSpy] CMemSpyEngineObjectContainer::MoveToGarbageL() - pid: 0x%04x, proc: 0x%08x, pos: %d, id: 0x%04x, name: %S"), (TUint) aId, proc, pos, (TUint) proc->Id(), &pName );
+#endif
+
+ User::LeaveIfError( iGarbage.Append( proc ) );
+ iProcesses.Remove( pos );
+ }
+ else
+ {
+#ifdef _DEBUG
+ RDebug::Printf( "[MemSpy] CMemSpyEngineObjectContainer::MoveToGarbageL() - pid: 0x%04x, pos: KErrNotFound", (TUint) aId );
+#endif
+ }
+
+ return ( pos >= 0 );
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+void CMemSpyEngineObjectContainer::ThreadIsDeadL( const TThreadId& aId, const RThread& aThread )
+ {
+ // Try to find the thread in question...
+ CMemSpyProcess* process = NULL;
+ CMemSpyThread* thread = NULL;
+ //
+ const TInt err = ProcessAndThreadByThreadId( aId, process, thread );
+ if ( err == KErrNone && thread )
+ {
+ // This will force the thread to detect if it is dead or not...
+ thread->SetDeadL( aThread );
+
+ // Signal UI
+ AsyncNotifyUiOfContainerChanges();
+ }
+ }
+
+
+void CMemSpyEngineObjectContainer::ProcessIsDeadL( const TProcessId& aId, const RProcess& aProcess )
+ {
+ const TInt index = ProcessIndexById( aId );
+ if ( index >= 0 )
+ {
+ CMemSpyProcess* process = iProcesses[ index ];
+ process->SetDeadL( aProcess );
+
+ // Signal UI
+ AsyncNotifyUiOfContainerChanges();
+ }
+ }
+
+
+void CMemSpyEngineObjectContainer::ThreadIsBornL( const TThreadId& /*aId*/, const RThread& aThread )
+ {
+ if ( aThread.Handle() != KNullHandle )
+ {
+ // The thread and process objects that will be created (or found, if they already exist).
+ CMemSpyProcess* process = NULL;
+ CMemSpyThread* thread = NULL;
+
+ // Create the objects if needed
+ TryToCreateProcessAndThreadL( aThread, process, thread );
+ }
+ }
+
+
+void CMemSpyEngineObjectContainer::ProcessIsBornL( const TProcessId& aId, const RProcess& /*aProcess*/ )
+ {
+#ifdef _DEBUG
+ RDebug::Printf( "[MemSpy] CMemSpyEngineObjectContainer::ProcessIsBornL() - START - pid: 0x%04x", (TUint) aId );
+#endif
+ (void) aId;
+
+ // This gets handled by the new thread creation. When the first thread in the process
+ // is created, we'll also prepare a new process object.
+
+#ifdef _DEBUG
+ RDebug::Printf( "[MemSpy] CMemSpyEngineObjectContainer::ProcessIsBornL() - END - pid: 0x%04x", (TUint) aId );
+#endif
+ }
+
+
+void CMemSpyEngineObjectContainer::AsyncNotifyUiOfContainerChanges()
+ {
+ iIdleNotifyContainerChanged->Cancel();
+ iIdleNotifyContainerChanged->Start( TCallBack( NotifyUiOfContainerChanges, this ) );
+ }
+
+
+TBool CMemSpyEngineObjectContainer::NotifyUiOfContainerChanges( TAny* aSelf )
+ {
+ CMemSpyEngineObjectContainer* self = reinterpret_cast< CMemSpyEngineObjectContainer* >( aSelf );
+ TRAP_IGNORE( self->iEngine.NotifyContainerChangeL() );
+ return EFalse;
+ }
+
+
+