memspy/Engine/Source/ThreadAndProcess/MemSpyEngineObjectContainer.cpp
changeset 0 a03f92240627
child 20 ca8a1b6995f6
--- /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;
+    }
+
+
+