memspy/Engine/Source/ThreadAndProcess/MemSpyEngineObjectThreadInfoObjects.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Wed, 13 Oct 2010 16:17:58 +0300
branchRCL_3
changeset 59 8ad140f3dd41
parent 49 7fdc9a71d314
permissions -rw-r--r--
Revision: 201039 Kit: 201041

/*
* 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/memspyengineobjectthreadinfoobjects.h>

// System includes
#include <f32file.h>
#include <hal.h>
#include <kernel/arm/arm_types.h>
#include <memspy/driver/memspydriverclient.h>
#include <memspy/engine/memspyengine.h>
#include <memspy/engine/memspyengineutils.h>
#include <memspy/engine/memspyengineoutputlist.h>
#include <memspy/engine/memspyenginehelpercodesegment.h>
#include <memspy/engine/memspyenginehelperactiveobject.h>
#include <memspy/engine/memspyenginehelperchunk.h>
#include <memspy/engine/memspyenginehelperheap.h>
#include <memspy/engine/memspyenginehelperprocess.h>
#include <memspy/engine/memspyengineobjectprocess.h>
#include <memspy/engine/memspyengineobjectthread.h>
#include <memspy/engine/memspyengineobjectthreadinfocontainer.h>
#include <memspy/engine/memspyengineoutputsink.h>

// User includes
#include "MemSpyEngineOutputListItem.h"

// Constants
const TInt KMemSpyNumericFormatBufferSize = 20;

// Literal constants
_LIT( KMemSpyNumericHexFormat, "0x%08x" );
_LIT( KMemSpyNumericDecFormat, "%d" );
_LIT( KMemSpyNumericLongFormat, "%Ld" );
_LIT( KMemSpyCaptionYes, "Yes" );
_LIT( KMemSpyCaptionNo, "No" );
_LIT( KMemSpyCaptionOn, "On" );
_LIT( KMemSpyCaptionOff, "Off" );
_LIT( KMemSpyUnavailable, "Unavailable" );
_LIT( KMemSpyDead, "Dead" );
_LIT( KMemSpyNoItems, "(No items)" );



CMemSpyThreadInfoItemBase::CMemSpyThreadInfoItemBase( CMemSpyThreadInfoContainer& aContainer, TMemSpyThreadInfoItemType aType, TBool aAsyncConstruction )
:   CMemSpyEngineObject( aContainer ), iContainer( aContainer ), iCallBack( CActive::EPriorityLow ), iType( aType )
    {
    if  ( aAsyncConstruction )
        {
        TCallBack callBackMethod( CallConstructL, this );
        iCallBack.Set( callBackMethod );
        iCallBack.CallBack();
        }
    }


CMemSpyThreadInfoItemBase::~CMemSpyThreadInfoItemBase()
    {
    TRAP_IGNORE( iContainer.NotifyObserverL( MMemSpyThreadInfoContainerObserver::EInfoItemDestroyed, iType ) );
    //
    iItems.ResetAndDestroy();
    iItems.Close();
    }


TInt CMemSpyThreadInfoItemBase::CallConstructL( TAny* aSelf )
    {
    CMemSpyThreadInfoItemBase* self = reinterpret_cast< CMemSpyThreadInfoItemBase* >( aSelf );
    self->iReady = EFalse;
    
    // Don't try to refresh dead thread
    TInt err = KErrNone;
    if ( !self->Container().Thread().IsDead() )
        {
        TRAP(err, self->ConstructL());
        if  ( err != KErrNone )
            {
    #ifdef _DEBUG
            RDebug::Printf( "CMemSpyThreadInfoItemBase::CallConstructL() - construction err: %d, iType: %d", err, self->iType );
    #endif
            self->AddItemL( KMemSpyUnavailable, KNullDesC );
            self->iIsEmpty = ETrue;
            }
        else if ( self->MdcaCount() == 0 )
            {
            self->AddItemL( KMemSpyNoItems, KNullDesC );
            self->iIsEmpty = ETrue;
            }        
        }
    else
        {
        self->AddItemL( KMemSpyDead, KNullDesC );
        self->iIsEmpty = ETrue;
        }
    //
    self->iReady = ETrue;
    return KErrNone;
    }


EXPORT_C TInt CMemSpyThreadInfoItemBase::MdcaCount() const
    {
    return iItems.Count();
    }


EXPORT_C TPtrC CMemSpyThreadInfoItemBase::MdcaPoint( TInt aIndex ) const
    {
    CItem* item = iItems[ aIndex ];
    return TPtrC( item->Combined() );
    }


EXPORT_C CMemSpyEngine& CMemSpyThreadInfoItemBase::Engine() const
    {
    return iContainer.Engine();
    }


EXPORT_C void CMemSpyThreadInfoItemBase::PrintL()
    {
    const TInt count = iItems.Count();
    if  ( count > 0 && !iIsEmpty )
        {
        CMemSpyEngine& engine = Engine();
        CMemSpyEngineOutputSink& sink = engine.Sink();

        HBufC* name = MemSpyEngineUtils::CleanupTextLC( Name() );
        sink.OutputSectionHeadingL( *name, TChar('-') );
        CleanupStack::PopAndDestroy( name );
        sink.OutputPrefixSetLC( _L("  ") ); // Slight insertion

        // First pass to get max lengths
        TInt maxLengthCaption = 0;
        TInt maxLengthValue = 0;

        for( TInt j=0; j<count; j++ )
            {
            const CItem* item = iItems[ j ];
            maxLengthCaption = Max( maxLengthCaption, item->Caption().Length() );
            maxLengthValue = Max( maxLengthValue, item->Value().Length() );
            }

        // Second pass - real this time - to print the values
        HBufC* line = HBufC::NewLC( ( maxLengthCaption + maxLengthValue ) + 20 );
        TPtr pLine( line->Des() );
        //
        for( TInt i=0; i<count; i++ )
            {
            const CItem* item = iItems[ i ];

            // Remove initial tabs in caption
            HBufC* caption = MemSpyEngineUtils::CleanupTextLC( item->Caption() );
        
            // Create value item & replace any further tabs
            HBufC* value = MemSpyEngineUtils::CleanupTextLC( item->Value() );

            // Now format the final line, with padding.
            pLine.Justify( *caption, maxLengthCaption + 3, ELeft, TChar(' ') );
            pLine.Append( *value );
            CleanupStack::PopAndDestroy( 2, caption );

            // Sink output
            sink.OutputLineL( pLine );
            }
        //
        CleanupStack::PopAndDestroy( line );
        sink.OutputBlankLineL();
        CleanupStack::PopAndDestroy(); // clear prefix
        }
    }



void CMemSpyThreadInfoItemBase::AddItemL( const TDesC& aCaption, const TDesC& aValue )
    {
    CItem* item = CItem::NewLC( aCaption, aValue );
    iItems.AppendL( item );
    CleanupStack::Pop( item );
    }


void CMemSpyThreadInfoItemBase::AddItemHexL( const TDesC& aCaption, TUint aValue )
    {
    TBuf<KMemSpyNumericFormatBufferSize> val;
    val.Format( KMemSpyNumericHexFormat, aValue );
    AddItemL( aCaption, val );
    }


void CMemSpyThreadInfoItemBase::AddItemDecimalL( const TDesC& aCaption, TInt aValue )
    {
    TBuf<KMemSpyNumericFormatBufferSize> val;
    val.Format( KMemSpyNumericDecFormat, aValue );
    AddItemL( aCaption, val );
    }


void CMemSpyThreadInfoItemBase::AddItemLongL( const TDesC& aCaption, const TInt64& aValue )
    {
    TBuf<KMemSpyNumericFormatBufferSize> val;
    val.Format( KMemSpyNumericLongFormat, aValue );
    AddItemL( aCaption, val );
    }


void CMemSpyThreadInfoItemBase::AddItemYesNoL( const TDesC& aCaption, TBool aYes )
    {
    CItem* item = CItem::NewYesNoLC( aCaption, aYes );
    iItems.AppendL( item );
    CleanupStack::Pop( item );
    }


void CMemSpyThreadInfoItemBase::AddItemOnOffL( const TDesC& aCaption, TBool aOn )
    {
    CItem* item = CItem::NewOnOffLC( aCaption, aOn );
    iItems.AppendL( item );
    CleanupStack::Pop( item );
    }


void CMemSpyThreadInfoItemBase::AddItemPercentageL( const TDesC& aCaption, TInt aOneHundredPercentValue, TInt aValue )
    {
    const TMemSpyPercentText val( MemSpyEngineUtils::FormatPercentage( TReal( aOneHundredPercentValue ), TReal( aValue ) ) );
    AddItemL( aCaption, val );
    }


EXPORT_C void CMemSpyThreadInfoItemBase::RebuildL()
    {
    Reset();
    CallConstructL( this );
    }


EXPORT_C TBool CMemSpyThreadInfoItemBase::IsReady() const
    {
    return iReady;
    }


EXPORT_C TMemSpyThreadInfoItemType CMemSpyThreadInfoItemBase::Type() const
    {
    return iType;
    }


void CMemSpyThreadInfoItemBase::Reset()
    {
    iItems.ResetAndDestroy();
    }


void CMemSpyThreadInfoItemBase::StripProcessAndThreadNames( TDes& aText )
    {
    StripProcessName( aText );
    StripThreadName( aText );
    }


void CMemSpyThreadInfoItemBase::StripProcessName( TDes& aText )
    {
    CMemSpyProcess& process = Container().Thread().Process();
    const TPtrC processName( process.Name() );
    TFullName temp;
    //
    _LIT( KProcessNameUidFormat1, "%S.exe[%08x]" );
    temp.Format( KProcessNameUidFormat1, &processName, process.SID() );
    const TBool stripped = MemSpyEngineUtils::StripText( aText, temp );
    //
    if  ( stripped == EFalse )
        {
        _LIT( KProcessNameUidFormat2, "%S[%08x]" );
        temp.Format( KProcessNameUidFormat2, &processName, process.SID() );
        MemSpyEngineUtils::StripText( aText, temp );
        }
    }


void CMemSpyThreadInfoItemBase::StripThreadName( TDes& aText )
    {
    CMemSpyThread& thread = Container().Thread();
    const TPtrC threadName( thread.Name() );
    const TBool stripped = MemSpyEngineUtils::StripText( aText, threadName );
    (void) stripped;
    }


CMemSpyThreadInfoItemBase::CItem& CMemSpyThreadInfoItemBase::Item( TInt aIndex )
    {
    CItem* item = iItems[ aIndex ];
    return *item;
    }


const CMemSpyThreadInfoItemBase::CItem& CMemSpyThreadInfoItemBase::Item( TInt aIndex ) const
    {
    const CItem* item = iItems[ aIndex ];
    return *item;
    }




















CMemSpyThreadInfoItemBase::CItem::CItem()
    {
    }


CMemSpyThreadInfoItemBase::CItem::~CItem()
    {
    delete iCaption;
    delete iValue;
    delete iCombined;
    }


void CMemSpyThreadInfoItemBase::CItem::ConstructL( const TDesC& aCaption, const TDesC& aValue )
    {
    iCaption = aCaption.AllocL();
    iValue = aValue.AllocL();
    //
    UpdateCombinedL();
    }


CMemSpyThreadInfoItemBase::CItem* CMemSpyThreadInfoItemBase::CItem::NewLC( const CItem& aCopyMe )
    {
    CItem* self = new(ELeave) CItem();
    CleanupStack::PushL( self );
    self->ConstructL( aCopyMe.Caption(), aCopyMe.Value() );
    return self;
    }


CMemSpyThreadInfoItemBase::CItem* CMemSpyThreadInfoItemBase::CItem::NewLC( const TDesC& aCaption )
    {
    CItem* self = new(ELeave) CItem();
    CleanupStack::PushL( self );
    self->ConstructL( aCaption, KNullDesC );
    return self;
    }


CMemSpyThreadInfoItemBase::CItem* CMemSpyThreadInfoItemBase::CItem::NewLC( const TDesC& aCaption, const TDesC& aValue )
    {
    CItem* self = new(ELeave) CItem();
    CleanupStack::PushL( self );
    self->ConstructL( aCaption, aValue );
    return self;
    }


CMemSpyThreadInfoItemBase::CItem* CMemSpyThreadInfoItemBase::CItem::NewHexLC( const TDesC& aCaption, TUint aValue )
    {
    CItem* ret = CItem::NewLC( aCaption );
    ret->SetHexL( aValue );
    return ret;
    }


CMemSpyThreadInfoItemBase::CItem* CMemSpyThreadInfoItemBase::CItem::NewDecimalLC( const TDesC& aCaption, TInt aValue )
    {
    CItem* ret = CItem::NewLC( aCaption );
    ret->SetDecimalL( aValue );
    return ret;
    }


CMemSpyThreadInfoItemBase::CItem* CMemSpyThreadInfoItemBase::CItem::NewLongLC( const TDesC& aCaption, const TInt64& aValue )
    {
    CItem* ret = CItem::NewLC( aCaption );
    ret->SetLongL( aValue );
    return ret;
    }


CMemSpyThreadInfoItemBase::CItem* CMemSpyThreadInfoItemBase::CItem::NewYesNoLC( const TDesC& aCaption, TBool aYes )
    {
    CItem* ret = CItem::NewLC( aCaption );
    ret->SetYesNoL( aYes );
    return ret;
    }


CMemSpyThreadInfoItemBase::CItem* CMemSpyThreadInfoItemBase::CItem::NewOnOffLC( const TDesC& aCaption, TBool aOn )
    {
    CItem* ret = CItem::NewLC( aCaption );
    ret->SetOnOffL( aOn );
    return ret;
    }


CMemSpyThreadInfoItemBase::CItem* CMemSpyThreadInfoItemBase::CItem::NewPercentageLC( const TDesC& aCaption, TInt aOneHundredPercentValue, TInt aValue )
    {
    CItem* ret = CItem::NewLC( aCaption );
    ret->SetPercentageL( aOneHundredPercentValue, aValue );
    return ret;
    }


void CMemSpyThreadInfoItemBase::CItem::SetValueL( const TDesC& aValue )
    {
    if  ( iValue == NULL )
        {
        iValue = aValue.AllocL();
        }
    else
        {
        if  ( iValue->Des().MaxLength() < aValue.Length() )
            {
            iValue = iValue->ReAllocL( aValue.Length() );
            }
            
        // Now its safe to assign new content
        *iValue = aValue;
        }
        
    UpdateCombinedL();
    }


void CMemSpyThreadInfoItemBase::CItem::SetHexL( TUint aValue )
    {
    TBuf<KMemSpyNumericFormatBufferSize> val;
    val.Format( KMemSpyNumericHexFormat, aValue );
    SetValueL( val );
    }


void CMemSpyThreadInfoItemBase::CItem::SetDecimalL( TInt aValue )
    {
    TBuf<KMemSpyNumericFormatBufferSize> val;
    val.Format( KMemSpyNumericDecFormat, aValue );
    SetValueL( val );
    }


void CMemSpyThreadInfoItemBase::CItem::SetLongL( const TInt64& aValue )
    {
    TBuf<KMemSpyNumericFormatBufferSize> val;
    val.Format( KMemSpyNumericLongFormat, aValue );
    SetValueL( val );
    }


void CMemSpyThreadInfoItemBase::CItem::SetYesNoL( TBool aYes )
    {
    if  ( aYes )
        {
        SetValueL( KMemSpyCaptionYes );
        }
    else
        {
        SetValueL( KMemSpyCaptionNo );
        }
    }


void CMemSpyThreadInfoItemBase::CItem::SetOnOffL( TBool aOn )
    {
    if  ( aOn )
        {
        SetValueL( KMemSpyCaptionOn );
        }
    else
        {
        SetValueL( KMemSpyCaptionOff );
        }
    }


void CMemSpyThreadInfoItemBase::CItem::SetPercentageL( TInt aOneHundredPercentValue, TInt aValue )
    {
    const TMemSpyPercentText val( MemSpyEngineUtils::FormatPercentage( TReal( aOneHundredPercentValue ), TReal( aValue ) ) );
    SetValueL( val );
    }


void CMemSpyThreadInfoItemBase::CItem::UpdateCombinedL()
    {
    const TInt requiredLength = Caption().Length() + Value().Length() + 10;
    //
    if  ( iCombined == NULL )
        {
        iCombined = HBufC::NewL( requiredLength );
        }
    else if ( iCombined->Des().MaxLength() < requiredLength )
        {
        iCombined = iCombined->ReAllocL( requiredLength );
        }
        
    TPtr pCombined( iCombined->Des() );
    pCombined.Zero();
    pCombined.Append( _L("\t") );
    pCombined.Append( Caption() );
    pCombined.Append( _L("\t\t") );
    pCombined.Append( Value() );
    }







































CMemSpyThreadInfoGeneral::CMemSpyThreadInfoGeneral( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
:   CMemSpyThreadInfoItemBase( aContainer, EMemSpyThreadInfoItemTypeGeneralInfo, aAsyncConstruction )
    {
    }


void CMemSpyThreadInfoGeneral::ConstructL()
    {
    TBuf<50> temp;
    RThread thread;
    Container().Thread().OpenLC( thread );
    const CMemSpyProcess& process = Container().Thread().Process();

    _LIT( KItem1, "Thread Id" );
    AddItemLongL( KItem1, thread.Id() );

    _LIT( KItem1a, "Process Id" );
    AddItemLongL( KItem1a, (TUint) process.Id() );
  
    _LIT( KItem1b, "SID" );
    AddItemHexL( KItem1b, process.SID() );
  
    _LIT( KItem1c, "VID" );
    AddItemHexL( KItem1c, process.VID() );

    _LIT( KItem2, "Thread Priority" );
    CMemSpyThread::AppendPriority( temp, thread.Priority() );
    AddItemL( KItem2, temp );
    temp.Zero();
   
    _LIT( KItem3, "Process Priority" );
    CMemSpyProcess::AppendPriority( temp, thread.ProcessPriority() );
    AddItemL( KItem3, temp );
    temp.Zero();
   
    _LIT( KItem4, "Request Count" );
    AddItemDecimalL( KItem4, thread.RequestCount() );
   
    TInt processHandleCount = 0;
    TInt threadHandleCount = 0;
    thread.HandleCount( processHandleCount, threadHandleCount );

    _LIT( KItem5a, "Process Handles" );
    AddItemDecimalL( KItem5a, processHandleCount );

    _LIT( KItem5b, "Thread Handles" );
    AddItemDecimalL( KItem5b, threadHandleCount );

    // Thread handle info
    THandleInfo handleInfo;
    thread.HandleInfo( &handleInfo );

    _LIT( KItem5c, "Num. Proc. (Using)" );
    AddItemDecimalL( KItem5c, handleInfo.iNumProcesses );

    _LIT( KItem5d, "Num. Thread (Using)" );
    AddItemDecimalL( KItem5d, handleInfo.iNumThreads );

    _LIT( KItem5e, "Attributes" );
    AddItemDecimalL( KItem5e, thread.Attributes() );
    
    // CPU time (request special kernel build)
    TTimeIntervalMicroSeconds cpuTime;
    if  ( thread.GetCpuTime( cpuTime ) == KErrNone )
        {
        _LIT( KItem5f, "CPU Time (us)" );
        const TInt64 time = cpuTime.Int64();
        AddItemLongL( KItem5f, time );
        }

    // Exit info
    _LIT( KItem6, "Exit Type" );
    CMemSpyThread::AppendExitType( temp, thread.ExitType() );
    AddItemL( KItem6, temp );
    temp.Zero();

    if  ( thread.ExitType() != EExitPending )
        {
        _LIT( KItem7, "Exit Reason" );
        AddItemDecimalL( KItem7, thread.ExitReason() );

        _LIT( KItem8, "Exit Category" );
        const TExitCategoryName cat( thread.ExitCategory() );
        AddItemL( KItem8, cat );
        }

    // Registers
    MakeRegisterListingL( thread );
    
    CleanupStack::PopAndDestroy( &thread );

    Container().NotifyObserverL( MMemSpyThreadInfoContainerObserver::EInfoItemChanged, Type() );
    }


CMemSpyThreadInfoGeneral* CMemSpyThreadInfoGeneral::NewLC( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
    {
    CMemSpyThreadInfoGeneral* self = new(ELeave) CMemSpyThreadInfoGeneral( aContainer, aAsyncConstruction );
    CleanupStack::PushL( self );
    if  ( !aAsyncConstruction )
        {
        self->ConstructL();
        }
    return self;
    }


EXPORT_C TPtrC CMemSpyThreadInfoGeneral::Name() const
    {
    _LIT(KName, "\tGeneral");
    return TPtrC( KName );
    }


void CMemSpyThreadInfoGeneral::MakeRegisterListingL( RThread& aThread )
    {
#ifndef __WINS__
    _LIT(KRegFormatGeneral, "R%02d");
    _LIT(KRegFormatSP, "SP");
    _LIT(KRegFormatLR, "LR");
    _LIT(KRegFormatPC, "PC");
    _LIT(KRegFormatFlags, "Flags");
    _LIT(KRegFormatDACR, "DACR"); // Data access control register
    //
    TArmRegSet regList;
    TPckg<TArmRegSet> pRegList( regList );
    //
    aThread.Context( pRegList );
	TArmReg* pReg = reinterpret_cast<TArmReg*>( &regList );
    //
    for( TInt i=0; i<KArmRegisterCount; i++ )
        {
        const TArmReg regValue = pReg[ i ];
        //
        if  ( i <= EArmR12 )
            {
            TBuf<128> buf;
            buf.Format( KRegFormatGeneral, i );
            AddItemHexL( buf, regValue );
            }
        else
            {
            TPtrC pCaption( KRegFormatGeneral );
            //
            if  ( i == EArmSp )
                {
                pCaption.Set( KRegFormatSP );
                }
            else if ( i == EArmLr )
                {
                pCaption.Set( KRegFormatLR );
                }
            else if ( i == EArmPc )
                {
                pCaption.Set( KRegFormatPC );
                }
            else if ( i == EArmFlags )
                {
                pCaption.Set( KRegFormatFlags );
                }
            else if ( i == EArmDacr )
                {
                pCaption.Set( KRegFormatDACR );
                }
            //
            AddItemHexL( pCaption, regValue );
            }
        }
#else
    (void) aThread;
#endif
    }














CMemSpyThreadInfoHeap::CMemSpyThreadInfoHeap( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
:   CMemSpyThreadInfoItemBase( aContainer, EMemSpyThreadInfoItemTypeHeap, aAsyncConstruction )
    {
    }


void CMemSpyThreadInfoHeap::ConstructL()
    {
    CMemSpyEngineHelperHeap& heapHelper = Engine().HelperHeap();

    // Get heap info first of all
    TMemSpyHeapInfo info;
    heapHelper.GetHeapInfoUserL( Container().Thread().Process().Id(), Container().Thread().Id(), info );
    CMemSpyEngineOutputList* list = heapHelper.NewHeapSummaryShortLC( info );

    // Now add each item to our view
    const TInt count = list->Count();
    for( TInt i=0; i<count; i++ )
        {
        const CMemSpyEngineOutputListItem& item = list->Item( i );
        //
        AddItemL( item.Caption(), item.Value() );
        }

    // Tidy up
    CleanupStack::PopAndDestroy( list );
    Container().NotifyObserverL( MMemSpyThreadInfoContainerObserver::EInfoItemChanged, Type() );
    }


CMemSpyThreadInfoHeap* CMemSpyThreadInfoHeap::NewLC( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
    {
    CMemSpyThreadInfoHeap* self = new(ELeave) CMemSpyThreadInfoHeap( aContainer, aAsyncConstruction );
    CleanupStack::PushL( self );
    if  ( !aAsyncConstruction )
        {
        self->ConstructL();
        }
    return self;
    }


EXPORT_C TPtrC CMemSpyThreadInfoHeap::Name() const
    {
    _LIT(KName, "\tHeap");
    return TPtrC( KName );
    }
















CMemSpyThreadInfoActiveObjects::CMemSpyThreadInfoActiveObjects( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
:   CMemSpyThreadInfoItemBase( aContainer, EMemSpyThreadInfoItemTypeActiveObject, aAsyncConstruction )
    {
    }


CMemSpyThreadInfoActiveObjects::~CMemSpyThreadInfoActiveObjects()
    {
    delete iItems;
    }


void CMemSpyThreadInfoActiveObjects::ConstructL()
    {
    CMemSpyEngine& engine = Container().Thread().Process().Engine();
    engine.ProcessSuspendLC( Container().Thread().Process().Id() );
    //
    CMemSpyEngineActiveObjectArray* activeObjects = engine.HelperActiveObject().ActiveObjectListL( Container().Thread() );
    delete iItems;
    iItems = activeObjects;
    //
    CleanupStack::PopAndDestroy(); // ProcessSuspendLC

    Container().NotifyObserverL( MMemSpyThreadInfoContainerObserver::EInfoItemChanged, Type() );
    }


CMemSpyThreadInfoActiveObjects* CMemSpyThreadInfoActiveObjects::NewLC( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
    {
    CMemSpyThreadInfoActiveObjects* self = new(ELeave) CMemSpyThreadInfoActiveObjects( aContainer, aAsyncConstruction );
    CleanupStack::PushL( self );
    if  ( !aAsyncConstruction )
        {
        self->ConstructL();
        }
    return self;
    }


EXPORT_C TPtrC CMemSpyThreadInfoActiveObjects::Name() const
    {
    _LIT(KName, "\tActive Objects");
    return TPtrC( KName );
    }


EXPORT_C TInt CMemSpyThreadInfoActiveObjects::MdcaCount() const
    {
    TInt count = 0;
    //
    if  ( iItems )
        {
        count = iItems->MdcaCount();
        }
    //
    return count;
    }


EXPORT_C TPtrC CMemSpyThreadInfoActiveObjects::MdcaPoint(TInt aIndex) const
    {
    TPtrC ret( KNullDesC );
    //
    if  ( iItems )
        {
        ret.Set( iItems->MdcaPoint( aIndex ) );
        }
    //
    return ret;
    }












CMemSpyThreadInfoOpenFiles::CMemSpyThreadInfoOpenFiles( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
:   CMemSpyThreadInfoItemBase( aContainer, EMemSpyThreadInfoItemTypeOpenFiles, aAsyncConstruction )
    {
    }


void CMemSpyThreadInfoOpenFiles::ConstructL()
    {
    _LIT(KSpace, " ");
    //
    const TThreadId myThreadId = Container().Thread().Id();
    CMemSpyEngine& engine = Container().Thread().Process().Engine();
    RFs& fsSession = engine.FsSession();
    //
    TMemSpySizeText valueBuf;
    TBuf<128> timeBuf;
    TOpenFileScan scanner( fsSession );
    //
    CFileList* list = NULL;
    scanner.NextL( list );

    while( list != NULL )
        {
        if  ( scanner.ThreadId() == myThreadId )
            {
            CleanupStack::PushL( list );
    
            const TInt entryCount = list->Count();
            for(TInt i=0; i<entryCount; i++)
                {
                const TEntry& entry = (*list)[ i ];

                // Get time and size format strings
                valueBuf = MemSpyEngineUtils::FormatSizeText( entry.iSize );
                MemSpyEngineUtils::FormatTimeL( timeBuf, entry.iModified );
                timeBuf.Insert( 0, KSpace );
                timeBuf.Insert( 0, valueBuf );

                // Get just file name
                TParsePtrC parser( entry.iName );
                const TPtrC pJustName( parser.NameAndExt() );

                // Create item 
                AddItemL( pJustName, timeBuf );
                }

            CleanupStack::Pop( list );
            }

        delete list;
        list = NULL;
        scanner.NextL( list );
        }

    Container().NotifyObserverL( MMemSpyThreadInfoContainerObserver::EInfoItemChanged, Type() );
    }


CMemSpyThreadInfoOpenFiles* CMemSpyThreadInfoOpenFiles::NewLC( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
    {
    CMemSpyThreadInfoOpenFiles* self = new(ELeave) CMemSpyThreadInfoOpenFiles( aContainer, aAsyncConstruction );
    CleanupStack::PushL( self );
    if  ( !aAsyncConstruction )
        {
        self->ConstructL();
        }
    return self;
    }


EXPORT_C TPtrC CMemSpyThreadInfoOpenFiles::Name() const
    {
    _LIT(KName, "\tOpen Files");
    return TPtrC( KName );
    }
















CMemSpyThreadInfoStack::CMemSpyThreadInfoStack( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
:   CMemSpyThreadInfoItemBase( aContainer, EMemSpyThreadInfoItemTypeStack, aAsyncConstruction )
    {
    }


void CMemSpyThreadInfoStack::ConstructL()
    {
    CMemSpyEngine& engine = Container().Thread().Process().Engine();
    engine.ProcessSuspendLC( Container().Thread().Process().Id() );
    //
    TMemSpyDriverStackInfo info;
    const TInt error = engine.Driver().GetStackInfo( Container().Thread().Id(), info );
    User::LeaveIfError( error );
    
    _LIT( KItem1, "Size" );
    AddItemDecimalL( KItem1, info.iUserStackSize );

#ifndef __WINS__
    const TInt userStackUsage = (TInt) ( info.iUserStackBase + info.iUserStackSize ) - info.iUserStackPointer;
    const TInt userStackHighWaterMarkUsage = (TInt) ( info.iUserStackBase + info.iUserStackSize ) - info.iUserStackHighWatermark;

    _LIT( KItem2, "Stack used" );
    AddItemDecimalL( KItem2, userStackUsage );
    
    _LIT( KItem3, "(percentage)" );
    AddItemPercentageL( KItem3, info.iUserStackSize, userStackUsage );

    _LIT( KItem4, "High watermark" );
    AddItemDecimalL( KItem4, userStackHighWaterMarkUsage );
    
    _LIT( KItem5, "(percentage)" );
    AddItemPercentageL( KItem5, info.iUserStackSize, userStackHighWaterMarkUsage );
#endif

    _LIT( KItem6, "Base address" );
    AddItemHexL( KItem6, info.iUserStackBase );

#ifndef __WINS__
    _LIT( KItem7, "Current pointer" );
    AddItemHexL( KItem7, info.iUserStackPointer );
#endif
    //
    CleanupStack::PopAndDestroy(); // ProcessSuspendLC

    Container().NotifyObserverL( MMemSpyThreadInfoContainerObserver::EInfoItemChanged, Type() );
    }


CMemSpyThreadInfoStack* CMemSpyThreadInfoStack::NewLC( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
    {
    CMemSpyThreadInfoStack* self = new(ELeave) CMemSpyThreadInfoStack( aContainer, aAsyncConstruction );
    CleanupStack::PushL( self );
    if  ( !aAsyncConstruction )
        {
        self->ConstructL();
        }
    return self;
    }


EXPORT_C TPtrC CMemSpyThreadInfoStack::Name() const
    {
    _LIT(KName, "\tStack");
    return TPtrC( KName );
    }






























CMemSpyThreadInfoChunk::CMemSpyThreadInfoChunk( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
:   CMemSpyThreadInfoItemBase( aContainer, EMemSpyThreadInfoItemTypeChunk, aAsyncConstruction )
    {
    }


CMemSpyThreadInfoChunk::~CMemSpyThreadInfoChunk()
    {
    delete iList;
    }


void CMemSpyThreadInfoChunk::ConstructL()
    {
    CMemSpyEngine& engine = Container().Thread().Process().Engine();
    engine.ProcessSuspendLC( Container().Thread().Process().Id() );
    //
    CMemSpyEngineChunkList* list = engine.HelperChunk().ListForThreadL( Container().Thread().Id() );
    delete iList;
    iList = list;
    //
    CleanupStack::PopAndDestroy(); // ProcessSuspendLC

    Container().NotifyObserverL( MMemSpyThreadInfoContainerObserver::EInfoItemChanged, Type() );
    }


CMemSpyThreadInfoChunk* CMemSpyThreadInfoChunk::NewLC( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
    {
    CMemSpyThreadInfoChunk* self = new(ELeave) CMemSpyThreadInfoChunk( aContainer, aAsyncConstruction );
    CleanupStack::PushL( self );
    if  ( !aAsyncConstruction )
        {
        self->ConstructL();
        }
    return self;
    }


EXPORT_C TPtrC CMemSpyThreadInfoChunk::Name() const
    {
    _LIT(KName, "\tChunks");
    return TPtrC( KName );
    }


EXPORT_C TInt CMemSpyThreadInfoChunk::MdcaCount() const
    {
    TInt count = 0;
    //
    if  ( iList )
        {
        count = iList->MdcaCount();
        }
    //
    return count;
    }


EXPORT_C TPtrC CMemSpyThreadInfoChunk::MdcaPoint(TInt aIndex) const
    {
    TPtrC ret( KNullDesC );
    //
    if  ( iList )
        {
        ret.Set( iList->MdcaPoint( aIndex ) );
        }
    //
    return ret;
    }


















CMemSpyThreadInfoCodeSeg::CMemSpyThreadInfoCodeSeg( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
:   CMemSpyThreadInfoItemBase( aContainer, EMemSpyThreadInfoItemTypeCodeSeg, aAsyncConstruction )
    {
    }


CMemSpyThreadInfoCodeSeg::~CMemSpyThreadInfoCodeSeg()
    {
    delete iList;
    }


void CMemSpyThreadInfoCodeSeg::ConstructL()
    {
    CMemSpyEngine& engine = Container().Thread().Process().Engine();
    engine.ProcessSuspendLC( Container().Thread().Process().Id() );
    //
    CMemSpyEngineCodeSegList* list = engine.HelperCodeSegment().CodeSegmentListL( Container().Thread().Process().Id() );
    delete iList;
    iList = list;
    //
    CleanupStack::PopAndDestroy(); // ProcessSuspendLC

    Container().NotifyObserverL( MMemSpyThreadInfoContainerObserver::EInfoItemChanged, Type() );
    }


CMemSpyThreadInfoCodeSeg* CMemSpyThreadInfoCodeSeg::NewLC( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
    {
    CMemSpyThreadInfoCodeSeg* self = new(ELeave) CMemSpyThreadInfoCodeSeg( aContainer, aAsyncConstruction );
    CleanupStack::PushL( self );
    if  ( !aAsyncConstruction )
        {
        self->ConstructL();
        }
    return self;
    }


EXPORT_C TPtrC CMemSpyThreadInfoCodeSeg::Name() const
    {
    _LIT(KName, "\tCode Segments");
    return TPtrC( KName );
    }


EXPORT_C TInt CMemSpyThreadInfoCodeSeg::MdcaCount() const
    {
    TInt count = 0;
    //
    if  ( iList )
        {
        count = iList->MdcaCount();
        }
    //
    return count;
    }


EXPORT_C TPtrC CMemSpyThreadInfoCodeSeg::MdcaPoint(TInt aIndex) const
    {
    TPtrC ret( KNullDesC );
    //
    if  ( iList )
        {
        ret.Set( iList->MdcaPoint( aIndex ) );
        }
    //
    return ret;
    }

























CMemSpyThreadInfoHandleObjectBase::CMemSpyThreadInfoHandleObjectBase( CMemSpyThreadInfoContainer& aContainer, TMemSpyThreadInfoItemType aItemType, TMemSpyDriverContainerType aContainerType, TBool aAsyncConstruction )
:   CMemSpyThreadInfoItemBase( aContainer, aItemType, aAsyncConstruction ), iContainerType( aContainerType )
    {
    }


CMemSpyThreadInfoHandleObjectBase::~CMemSpyThreadInfoHandleObjectBase()
    {
#ifdef _DEBUG
    RDebug::Printf( "CMemSpyThreadInfoHandleObjectBase::~CMemSpyThreadInfoHandleObjectBase() - this: 0x%08x", this );
#endif
    iInfoItems.Close();
    }


void CMemSpyThreadInfoHandleObjectBase::ConstructL()
    {
#ifdef _DEBUG
    RDebug::Printf( "CMemSpyThreadInfoHandleObjectBase::ConstructL() - START" );
#endif
    iInfoItems.Reset();
    //
    CMemSpyProcess& process = Container().Thread().Process();
    CMemSpyEngine& engine = process.Engine();
    engine.ProcessSuspendLC( process.Id() );
    //
    RArray<THandleWrapper> handles;
    CleanupClosePushL( handles );
    GetHandlesL( handles );
#ifdef _DEBUG
    RDebug::Printf( "CMemSpyThreadInfoHandleObjectBase::ConstructL() - got %d handle entries...", handles.Count() );
#endif
    //
    TFullName name;
    TMemSpyDriverHandleInfoGeneric info;
    //
    const TInt count = handles.Count();
    for (TInt i=0; i<count; i++)
    	{
    	const THandleWrapper& handleWrapper = handles[ i ];
        //
    	const TInt r = engine.Driver().GetGenericHandleInfo( Container().Thread().Id(), handleWrapper.iType, handleWrapper.iHandle, info );
        //
#ifdef _DEBUG
        RDebug::Printf( "CMemSpyThreadInfoHandleObjectBase::ConstructL() - handle[%3d] 0x%08x, type: %d, refCount: %d, r: %d", i, handleWrapper.iHandle, handleWrapper.iType, handleWrapper.iRefCount, r );
#endif
        //
        if  (r == KErrNone)
    		{
            name.Copy( info.iName );
#ifdef _DEBUG
            RDebug::Print( _L( "CMemSpyThreadInfoHandleObjectBase::ConstructL() - HANDLE [%3d] %S"), handleWrapper.iRefCount, &name );
#endif
            StripProcessAndThreadNames( name );
            //
            iInfoItems.AppendL( info );
            HandleContainerItemL( info, handleWrapper.iRefCount, name );
            }
     	}

    CleanupStack::PopAndDestroy( &handles );
    CleanupStack::PopAndDestroy(); // ProcessSuspendLC

    HandleAllItemsLocatedL();

    Container().NotifyObserverL( MMemSpyThreadInfoContainerObserver::EInfoItemChanged, Type() );
    }


TBool CMemSpyThreadInfoHandleObjectBase::THandleWrapper::Match( const THandleWrapper& aLeft, const THandleWrapper& aRight )
    {
    return ( aLeft.iHandle == aRight.iHandle );
    }


EXPORT_C TInt CMemSpyThreadInfoHandleObjectBase::DetailsIndexByEntry( const TMemSpyDriverHandleInfoGeneric& aEntry ) const
    {
#ifdef _DEBUG
    RDebug::Printf( "CMemSpyThreadInfoHandleObjectBase::DetailsIndexByEntry() - START - this: 0x%08x, aEntry.iHandle: 0x%08x", this, aEntry.iHandle );
#endif
    //
    const TInt ret = DetailsIndexByHandle( aEntry.iHandle );
    //
#ifdef _DEBUG
    RDebug::Printf( "CMemSpyThreadInfoHandleObjectBase::DetailsIndexByEntry() - END - ret: %d", ret );
#endif
    return ret;
    }


EXPORT_C TInt CMemSpyThreadInfoHandleObjectBase::DetailsIndexByHandle( TAny* aHandle ) const
    {
#ifdef _DEBUG
    RDebug::Printf( "CMemSpyThreadInfoHandleObjectBase::DetailsIndexByHandle() - START - this: 0x%08x, aHandle: 0x%08x", this, aHandle );
#endif
    TInt ret = KErrNotFound;
    //
    const TInt count = DetailsCount();
    for(TInt i=0; i<count; i++)
        {
        const TMemSpyDriverHandleInfoGeneric& item = DetailsAt( i );
        if  ( item.iHandle == aHandle )
            {
            ret = i;
            break;
            }
        }
    //
#ifdef _DEBUG
    RDebug::Printf( "CMemSpyThreadInfoHandleObjectBase::DetailsIndexByHandle() - END - ret: %d", ret );
#endif
    return ret;
    }














CMemSpyThreadInfoHandleByContainer::CMemSpyThreadInfoHandleByContainer( CMemSpyThreadInfoContainer& aContainer, TMemSpyThreadInfoItemType aItemType, TMemSpyDriverContainerType aContainerType, TBool aAsyncConstruction )
:   CMemSpyThreadInfoHandleObjectBase( aContainer, aItemType, aContainerType, aAsyncConstruction )
    {
    }


void CMemSpyThreadInfoHandleByContainer::GetHandlesL( RArray<THandleWrapper>& aArray )
    {
#ifdef _DEBUG
    RDebug::Printf( "CMemSpyThreadInfoHandleByContainer::GetHandlesL() - START - container: %d", ContainerType() );
#endif

    aArray.Reset();

    // Our handles will be stored here... duplicates are filtered out
    TInt r = KErrNone;
	TInt c = KMemSpyDefaultMaxHandleCount;
	TAny* handles[ KMemSpyDefaultMaxHandleCount ];

    CMemSpyProcess& process = Container().Thread().Process();
    CMemSpyEngine& engine = process.Engine();
    TIdentityRelation<CMemSpyThreadInfoHandleObjectBase::THandleWrapper> finder( THandleWrapper::Match );

    // First get the handles for the process
    if  ( r == KErrNone )
        {
        c = KMemSpyDefaultMaxHandleCount;
        r = engine.Driver().GetProcessHandlesByType( process.Id(), ContainerType(), handles, c );
        if  ( r == KErrNone && c > 0 )
    	    {
            c = Min( c, KMemSpyDefaultMaxHandleCount );
    	    for( TInt i=0; i<c; i++ )
    		    {
    		    TAny* handle = handles[ i ];

                // Create temporary entry that we'll use as the key in our array...
                CMemSpyThreadInfoHandleObjectBase::THandleWrapper entry( handle, ContainerType() );
                
                // Find existing duplicate entry (if there is one...)
                const TInt errorOrIndex = aArray.Find( entry, finder );
#ifdef _DEBUG
                RDebug::Printf( "CMemSpyThreadInfoHandleByContainer::GetHandlesL() - PROC[%03d/%03d] - handle: 0x%08x, foundIndex: %d", i+1, c, handle, errorOrIndex );
#endif

    		    if  ( errorOrIndex == KErrNotFound )
        		    {
        		    // Not a duplicate handle, so keep it
        		    aArray.AppendL( entry );
#ifdef _DEBUG
                    RDebug::Printf( "      new entry: 0x%08x", handle );
#endif
        		    }
                else if ( errorOrIndex >= 0 )
                    {
                    // Increment reference count for duplicates...
                    CMemSpyThreadInfoHandleObjectBase::THandleWrapper& existingEntry = aArray[ errorOrIndex ];
                    ++existingEntry.iRefCount;
#ifdef _DEBUG
                    RDebug::Printf( "      dupe entry - count is now: %d", existingEntry.iRefCount );
#endif
                    }
     		    }
            }
        }

    // Next get the handles for the thread
    if  ( r == KErrNone )
        {
        c = KMemSpyDefaultMaxHandleCount;
        r = engine.Driver().GetThreadHandlesByType( Container().Thread().Id(), ContainerType(), handles, c );
        if  ( r == KErrNone && c > 0 )
    	    {
            c = Min( c, KMemSpyDefaultMaxHandleCount );
    	    for( TInt i=0; i<c; i++ )
    		    {
    		    TAny* handle = handles[ i ];

                // Create temporary entry that we'll use as the key in our array...
                CMemSpyThreadInfoHandleObjectBase::THandleWrapper entry( handle, ContainerType() );
                
                // Find existing duplicate entry (if there is one...)
                const TInt errorOrIndex = aArray.Find( entry, finder );
#ifdef _DEBUG
                RDebug::Printf(  "CMemSpyThreadInfoHandleByContainer::GetHandlesL() - THRD[%03d/%03d] - handle: 0x%08x, foundIndex: %d", i+1, c, handle, errorOrIndex );
#endif
    		    
    		    if  ( errorOrIndex == KErrNotFound )
        		    {
        		    // Not a duplicate handle, so keep it
        		    aArray.AppendL( entry );
#ifdef _DEBUG
                    RDebug::Printf( "      new entry: 0x%08x", handle );
#endif
        		    }
                else if ( errorOrIndex >= 0 )
                    {
                    // Increment reference count for duplicates...
                    CMemSpyThreadInfoHandleObjectBase::THandleWrapper& existingEntry = aArray[ errorOrIndex ];
                    ++existingEntry.iRefCount;
#ifdef _DEBUG
                    RDebug::Printf( "      dupe entry - count is now: %d", existingEntry.iRefCount );
#endif
                    }
     		    }
            }
        }

#ifdef _DEBUG
    RDebug::Printf(  "CMemSpyThreadInfoHandleByContainer::GetHandlesL() - final handle listing: " );

    const TInt finalCount = aArray.Count();
    for( TInt i=0; i<finalCount; i++ )
        {
        const THandleWrapper& handle = aArray[ i ];
        RDebug::Printf(  "entry[%03d/%03d] - handle: 0x%08x, type: %d, refCount: %d", i+1, finalCount, handle.iHandle, handle.iType, handle.iRefCount );
        }

    RDebug::Printf( "CMemSpyThreadInfoHandleByContainer::GetHandlesL() - END - container: %d, finalCount: %d", ContainerType(), finalCount );
#endif
    }

















































CMemSpyThreadInfoServer::CMemSpyThreadInfoServer( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
:   CMemSpyThreadInfoHandleByContainer( aContainer, EMemSpyThreadInfoItemTypeServer, EMemSpyDriverContainerTypeServer, aAsyncConstruction )
    {
    }


CMemSpyThreadInfoServer* CMemSpyThreadInfoServer::NewLC( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
    {
    CMemSpyThreadInfoServer* self = new(ELeave) CMemSpyThreadInfoServer( aContainer, aAsyncConstruction );
    CleanupStack::PushL( self );
    if  ( !aAsyncConstruction )
        {
        self->ConstructL();
        }
    return self;
    }


EXPORT_C TPtrC CMemSpyThreadInfoServer::Name() const
    {
    _LIT(KName, "\tServers Running in Thread");
    return TPtrC( KName );
    }


void CMemSpyThreadInfoServer::HandleContainerItemL( TMemSpyDriverHandleInfoGeneric& /*aItem*/, TInt /*aRefCount*/, TDes& aFullName )
    {
    AddItemL( aFullName, KNullDesC );
    }


EXPORT_C TPtrC CMemSpyThreadInfoServer::SessionType( TIpcSessionType aType )
    {
    _LIT( KUnsharable, "Unsharable" );
    _LIT( KSharable, "Sharable" );
    _LIT( KGlobalSharable, "Global Sharable" );
    //
    TPtrC pType(KNullDesC);
    switch( aType )
        {
    case EIpcSession_Unsharable:
        pType.Set( KUnsharable );
        break;
    case EIpcSession_Sharable:
        pType.Set( KSharable );
        break;
    case EIpcSession_GlobalSharable:
        pType.Set( KGlobalSharable );
        break;
    default:
        pType.Set( KMemSpyUnavailable );
        break;
        }
    //
    return pType;
    }
























CMemSpyThreadInfoSession::CMemSpyThreadInfoSession( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
:   CMemSpyThreadInfoHandleByContainer( aContainer, EMemSpyThreadInfoItemTypeSession, EMemSpyDriverContainerTypeSession, aAsyncConstruction )
    {
    }


CMemSpyThreadInfoSession::~CMemSpyThreadInfoSession()
    {
    iServerNames.ResetAndDestroy();
    iServerNames.Close();
    }


CMemSpyThreadInfoSession* CMemSpyThreadInfoSession::NewLC( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
    {
    CMemSpyThreadInfoSession* self = new(ELeave) CMemSpyThreadInfoSession( aContainer, aAsyncConstruction );
    CleanupStack::PushL( self );
    if  ( !aAsyncConstruction )
        {
        self->ConstructL();
        }
    return self;
    }


EXPORT_C TPtrC CMemSpyThreadInfoSession::Name() const
    {
    _LIT(KName, "\tClient <-> Server\nConnections");
    return TPtrC( KName );
    }


void CMemSpyThreadInfoSession::Reset()
    {
    CMemSpyThreadInfoHandleByContainer::Reset();
    iServerNames.ResetAndDestroy();
    }


EXPORT_C TInt CMemSpyThreadInfoSession::ConnectionCount( const TDesC& aName ) const
    {
    TInt ret = 0;

#ifdef _DEBUG
    RDebug::Print( _L("CMemSpyThreadInfoSession::ConnectionCount() - START - aName: %S"), &aName );
#endif

    // See if we have an entry with that name...
    TIdentityRelation<CSessionInfoEntry> comparer( CompareEntries );
    HBufC* name = aName.AllocLC();
    CSessionInfoEntry* entry = new(ELeave) CSessionInfoEntry( name );
    CleanupStack::Pop( name );
    CleanupStack::PushL( entry );
    const TInt foundIndex = iServerNames.Find( entry, comparer );
    CleanupStack::PopAndDestroy( entry );
    
    // If we did, get the count
    if  ( foundIndex >=0 && foundIndex < iServerNames.Count() )
        {
        ret = iServerNames[ foundIndex ]->iCount;
        }
    //
#ifdef _DEBUG
    RDebug::Printf( "CMemSpyThreadInfoSession::ConnectionCount() - END - ret: %d", ret );
#endif
    //
    return ret;
    }


void CMemSpyThreadInfoSession::HandleContainerItemL( TMemSpyDriverHandleInfoGeneric& aItem, TInt /*aRefCount*/, TDes& aFullName )
    {
    // Check whether we have the item already?
    TIdentityRelation<CSessionInfoEntry> comparer( CompareEntries );

    // Prepare object, just in case we don't find it...
    HBufC* name = aFullName.AllocLC();

#ifdef _DEBUG
    TBuf<KMaxName> origName; origName.Copy( aItem.iName );
    RDebug::Print( _L("CMemSpyThreadInfoSession::HandleContainerItemL() - START - handle: 0x%08x, type: %d, origName: %S, modName: %S"), aItem.iHandle, aItem.iType, &origName, name );
#else
    (void) aItem;
#endif

    CSessionInfoEntry* entry = new(ELeave) CSessionInfoEntry( name );
    CleanupStack::Pop( name );
    CleanupStack::PushL( entry );

    // Search
    const TInt foundIndex = iServerNames.Find( entry, comparer );
    if  ( foundIndex == KErrNotFound )
        {
        // Make new entry
        iServerNames.AppendL( entry );
        CleanupStack::Pop( entry );
        }
    else if ( foundIndex >= 0 )
        {
        // Existing entry, increment count
        CleanupStack::PopAndDestroy( entry );
        entry = iServerNames[ foundIndex ];
        ++entry->iCount;
        }
    else
        {
        CleanupStack::PopAndDestroy( entry );
        }
 
#ifdef _DEBUG
    RDebug::Printf( "CMemSpyThreadInfoSession::HandleContainerItemL() - END - foundIndex: %d", foundIndex );
#endif
    }


void CMemSpyThreadInfoSession::HandleAllItemsLocatedL()
    {
    _LIT(KSecondLineFormatStringCount1, "1 connection");
    _LIT(KSecondLineFormatStringCountMoreThanOne, "%d connections");
    TBuf<50> buf;

    // All items have been found, now create listbox entries
    const TInt count = iServerNames.Count();
    for( TInt i=0; i<count; i++ )
        {
        CSessionInfoEntry* entry = iServerNames[ i ];

        if  ( entry->iCount == 1 )
            {
            buf.Copy( KSecondLineFormatStringCount1 );
            }
        else
            {
            buf.Format( KSecondLineFormatStringCountMoreThanOne, entry->iCount );
            }

        AddItemL( *entry->iName, buf );
        }
    }


TBool CMemSpyThreadInfoSession::CompareEntries( const CSessionInfoEntry& aLeft, const CSessionInfoEntry& aRight )
    {
    return ( aLeft.iName->CompareF( *aRight.iName ) == 0 );
    }


























CMemSpyThreadInfoSemaphore::CMemSpyThreadInfoSemaphore( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
:   CMemSpyThreadInfoHandleByContainer( aContainer, EMemSpyThreadInfoItemTypeSemaphore, EMemSpyDriverContainerTypeSemaphore, aAsyncConstruction )
    {
    }


CMemSpyThreadInfoSemaphore* CMemSpyThreadInfoSemaphore::NewLC( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
    {
    CMemSpyThreadInfoSemaphore* self = new(ELeave) CMemSpyThreadInfoSemaphore( aContainer, aAsyncConstruction );
    CleanupStack::PushL( self );
    if  ( !aAsyncConstruction )
        {
        self->ConstructL();
        }
    return self;
    }


EXPORT_C TPtrC CMemSpyThreadInfoSemaphore::Name() const
    {
    _LIT(KName, "\tSemaphores");
    return TPtrC( KName );
    }


void CMemSpyThreadInfoSemaphore::HandleContainerItemL( TMemSpyDriverHandleInfoGeneric& aItem, TInt /*aRefCount*/, TDes& aFullName )
    {
    _LIT( KFormatSpec, "Count: %d" );
    TBuf<50> buf;
    buf.AppendFormat( KFormatSpec, aItem.iCount );

    AddItemL( aFullName, buf );
    }
























CMemSpyThreadInfoMutex::CMemSpyThreadInfoMutex( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
:   CMemSpyThreadInfoHandleByContainer( aContainer, EMemSpyThreadInfoItemTypeMutex, EMemSpyDriverContainerTypeMutex, aAsyncConstruction )
    {
    }


CMemSpyThreadInfoMutex* CMemSpyThreadInfoMutex::NewLC( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
    {
    CMemSpyThreadInfoMutex* self = new(ELeave) CMemSpyThreadInfoMutex( aContainer, aAsyncConstruction );
    CleanupStack::PushL( self );
    if  ( !aAsyncConstruction )
        {
        self->ConstructL();
        }
    return self;
    }


EXPORT_C TPtrC CMemSpyThreadInfoMutex::Name() const
    {
    _LIT(KName, "\tMutexes");
    return TPtrC( KName );
    }


void CMemSpyThreadInfoMutex::HandleContainerItemL( TMemSpyDriverHandleInfoGeneric& aItem, TInt /*aRefCount*/, TDes& aFullName )
    {
    _LIT( KFormatSpec, "Count: %d" );
    TBuf<50> buf;
    buf.AppendFormat( KFormatSpec, aItem.iCount );

    AddItemL( aFullName, buf );
    }
























CMemSpyThreadInfoTimer::CMemSpyThreadInfoTimer( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
:   CMemSpyThreadInfoHandleByContainer( aContainer, EMemSpyThreadInfoItemTypeTimer, EMemSpyDriverContainerTypeTimer, aAsyncConstruction )
    {
    }


CMemSpyThreadInfoTimer* CMemSpyThreadInfoTimer::NewLC( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
    {
    CMemSpyThreadInfoTimer* self = new(ELeave) CMemSpyThreadInfoTimer( aContainer, aAsyncConstruction );
    CleanupStack::PushL( self );
    if  ( !aAsyncConstruction )
        {
        self->ConstructL();
        }
    return self;
    }


EXPORT_C TPtrC CMemSpyThreadInfoTimer::Name() const
    {
    _LIT(KName, "\tTimers");
    return TPtrC( KName );
    }


void CMemSpyThreadInfoTimer::HandleContainerItemL( TMemSpyDriverHandleInfoGeneric& aItem, TInt /*aRefCount*/, TDes& /*aFullName*/ )
    {
    // Get useful strings
    TBuf<20> state;
    GetTimerState( aItem.iTimerState, state );
    TBuf<20> type;
    GetTimerType( aItem.iTimerType, type );

    AddItemL( type, state );
    }


void CMemSpyThreadInfoTimer::GetTimerState( TMemSpyDriverTimerState aState, TDes& aBuf )
    {
    switch( aState )
        {
    default:
    case EMemSpyDriverTimerStateUnknown: 
        {
        _LIT(KStateUnknown, "Unknown");
        aBuf.Copy( KStateUnknown );
        }
        break;
    case EMemSpyDriverTimerStateIdle:
        {
        _LIT(KStateIdle, "Idle");
        aBuf.Copy( KStateIdle );
        }
        break;
    case EMemSpyDriverTimerStateWaiting: 
        {
        _LIT(KStateWaiting, "Waiting");
        aBuf.Copy( KStateWaiting );
        }
        break;
    case EMemSpyDriverTimerStateWaitHighRes: 
        {
        _LIT(KStateWaitHighRes, "Waiting, High Res.");
        aBuf.Copy( KStateWaitHighRes );
        }
        break;
        }
    }


void CMemSpyThreadInfoTimer::GetTimerType( TMemSpyDriverTimerType aType, TDes& aBuf )
    {
    switch( aType )
        {
    case EMemSpyDriverTimerTypeRelative:
        {
        _LIT( KType, "Relative" );
        aBuf.Copy( KType );
        }
        break;
    case EMemSpyDriverTimerTypeAbsolute:
        {
        _LIT( KType, "Absolute" );
        aBuf.Copy( KType );
        }
        break;
    case EMemSpyDriverTimerTypeHighRes:
        {
        _LIT( KType, "High Res." );
        aBuf.Copy( KType );
        }
        break;
    case EMemSpyDriverTimerTypeInactivity:
        {
        _LIT( KType, "Inactivity" );
        aBuf.Copy( KType );
        }
        break;
    default:
        {
        _LIT( KType, "Unknown" );
        aBuf.Copy( KType );
        }
        break;
        }
    }



















CMemSpyThreadInfoLDD::CMemSpyThreadInfoLDD( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
:   CMemSpyThreadInfoHandleByContainer( aContainer, EMemSpyThreadInfoItemTypeLDD, EMemSpyDriverContainerTypeLogicalDevice, aAsyncConstruction )
    {
    }


CMemSpyThreadInfoLDD* CMemSpyThreadInfoLDD::NewLC( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
    {
    CMemSpyThreadInfoLDD* self = new(ELeave) CMemSpyThreadInfoLDD( aContainer, aAsyncConstruction );
    CleanupStack::PushL( self );
    if  ( !aAsyncConstruction )
        {
        self->ConstructL();
        }
    return self;
    }


EXPORT_C TPtrC CMemSpyThreadInfoLDD::Name() const
    {
    _LIT(KName, "\tLogical Device Drivers");
    return TPtrC( KName );
    }


void CMemSpyThreadInfoLDD::HandleContainerItemL( TMemSpyDriverHandleInfoGeneric& aItem, TInt /*aRefCount*/, TDes& aFullName )
    {
    _LIT( KFormatSpec, "Open channels: %d" );
    TBuf<50> buf;
    buf.AppendFormat( KFormatSpec, aItem.iOpenChannels );

    AddItemL( aFullName, buf );
    }

























CMemSpyThreadInfoPDD::CMemSpyThreadInfoPDD( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
:   CMemSpyThreadInfoHandleByContainer( aContainer, EMemSpyThreadInfoItemTypePDD, EMemSpyDriverContainerTypePhysicalDevice, aAsyncConstruction )
    {
    }


CMemSpyThreadInfoPDD* CMemSpyThreadInfoPDD::NewLC( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
    {
    CMemSpyThreadInfoPDD* self = new(ELeave) CMemSpyThreadInfoPDD( aContainer, aAsyncConstruction );
    CleanupStack::PushL( self );
    if  ( !aAsyncConstruction )
        {
        self->ConstructL();
        }
    return self;
    }


EXPORT_C TPtrC CMemSpyThreadInfoPDD::Name() const
    {
    _LIT(KName, "\tPhysical Device Drivers");
    return TPtrC( KName );
    }


void CMemSpyThreadInfoPDD::HandleContainerItemL( TMemSpyDriverHandleInfoGeneric& /*aItem*/, TInt /*aRefCount*/, TDes& aFullName )
    {
    AddItemL( aFullName, KNullDesC );
    }






















CMemSpyThreadInfoLogicalChannel::CMemSpyThreadInfoLogicalChannel( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
:   CMemSpyThreadInfoHandleByContainer( aContainer, EMemSpyThreadInfoItemTypeLogicalChannel, EMemSpyDriverContainerTypeLogicalChannel, aAsyncConstruction )
    {
    }


CMemSpyThreadInfoLogicalChannel* CMemSpyThreadInfoLogicalChannel::NewLC( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
    {
    CMemSpyThreadInfoLogicalChannel* self = new(ELeave) CMemSpyThreadInfoLogicalChannel( aContainer, aAsyncConstruction );
    CleanupStack::PushL( self );
    if  ( !aAsyncConstruction )
        {
        self->ConstructL();
        }
    return self;
    }


EXPORT_C TPtrC CMemSpyThreadInfoLogicalChannel::Name() const
    {
    _LIT(KName, "\tLogical DD Channels");
    return TPtrC( KName );
    }


void CMemSpyThreadInfoLogicalChannel::HandleContainerItemL( TMemSpyDriverHandleInfoGeneric& /*aItem*/, TInt /*aRefCount*/, TDes& aFullName )
    {
    AddItemL( aFullName, KNullDesC );
    }





















CMemSpyThreadInfoChangeNotifier::CMemSpyThreadInfoChangeNotifier( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
:   CMemSpyThreadInfoHandleByContainer( aContainer, EMemSpyThreadInfoItemTypeChangeNotifier, EMemSpyDriverContainerTypeChangeNotifier, aAsyncConstruction )
    {
    }


CMemSpyThreadInfoChangeNotifier* CMemSpyThreadInfoChangeNotifier::NewLC( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
    {
    CMemSpyThreadInfoChangeNotifier* self = new(ELeave) CMemSpyThreadInfoChangeNotifier( aContainer, aAsyncConstruction );
    CleanupStack::PushL( self );
    if  ( !aAsyncConstruction )
        {
        self->ConstructL();
        }
    return self;
    }


EXPORT_C TPtrC CMemSpyThreadInfoChangeNotifier::Name() const
    {
    _LIT(KName, "\tChange Notifiers");
    return TPtrC( KName );
    }


void CMemSpyThreadInfoChangeNotifier::HandleContainerItemL( TMemSpyDriverHandleInfoGeneric& /*aItem*/, TInt /*aRefCount*/, TDes& aFullName )
    {
    AddItemL( aFullName, KNullDesC );
    }





















CMemSpyThreadInfoUndertaker::CMemSpyThreadInfoUndertaker( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
:   CMemSpyThreadInfoHandleByContainer( aContainer, EMemSpyThreadInfoItemTypeUndertaker, EMemSpyDriverContainerTypeUndertaker, aAsyncConstruction )
    {
    }


CMemSpyThreadInfoUndertaker* CMemSpyThreadInfoUndertaker::NewLC( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
    {
    CMemSpyThreadInfoUndertaker* self = new(ELeave) CMemSpyThreadInfoUndertaker( aContainer, aAsyncConstruction );
    CleanupStack::PushL( self );
    if  ( !aAsyncConstruction )
        {
        self->ConstructL();
        }
    return self;
    }


EXPORT_C TPtrC CMemSpyThreadInfoUndertaker::Name() const
    {
    _LIT(KName, "\tUndertakers");
    return TPtrC( KName );
    }


void CMemSpyThreadInfoUndertaker::HandleContainerItemL( TMemSpyDriverHandleInfoGeneric& /*aItem*/, TInt /*aRefCount*/, TDes& aFullName )
    {
    AddItemL( aFullName, KNullDesC );
    }

















CMemSpyThreadInfoOwnedThreadHandles::CMemSpyThreadInfoOwnedThreadHandles( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
:   CMemSpyThreadInfoHandleByContainer( aContainer, EMemSpyThreadInfoItemTypeOwnedThreadHandles, EMemSpyDriverContainerTypeThread, aAsyncConstruction )
    {
    }


CMemSpyThreadInfoOwnedThreadHandles* CMemSpyThreadInfoOwnedThreadHandles::NewLC( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
    {
    CMemSpyThreadInfoOwnedThreadHandles* self = new(ELeave) CMemSpyThreadInfoOwnedThreadHandles( aContainer, aAsyncConstruction );
    CleanupStack::PushL( self );
    if  ( !aAsyncConstruction )
        {
        self->ConstructL();
        }
    return self;
    }


EXPORT_C TPtrC CMemSpyThreadInfoOwnedThreadHandles::Name() const
    {
    _LIT(KName, "\tHandles to other\nThreads");
    return TPtrC( KName );
    }


void CMemSpyThreadInfoOwnedThreadHandles::HandleContainerItemL( TMemSpyDriverHandleInfoGeneric& aItem, TInt aRefCount, TDes& aFullName )
    {
    const TInt bracketPosStart = aFullName.LocateF( TChar('[') );
    const TInt doubleColonPos = aFullName.FindF( _L("::" ) );
    //
    if  ( bracketPosStart >= 0 && doubleColonPos > bracketPosStart && doubleColonPos < aFullName.Length() - 2 )
        {
        // Process
        TPtrC pProcessName( aFullName.Left( bracketPosStart ) );
        HBufC* caption = HBufC::NewLC( KMaxName + 10 );
        TPtr pCaption( caption->Des() );
        pCaption.AppendFormat( _L("[%2d] %S"), aRefCount, &pProcessName );
        
        // Thread id & thread name
        TPtrC pThreadName( aFullName.Mid( doubleColonPos + 2 ) );
        HBufC* value = HBufC::NewLC( KMaxName + 10 );
        TPtr pValue( value->Des() );
        pValue.AppendFormat( _L("[%3d] %S"), aItem.iId, &pThreadName );

        // Add it & tidy up
        AddItemL( pCaption, pValue );
        CleanupStack::PopAndDestroy( 2, caption );
        }
    else
        {
        AddItemL( aFullName, KNullDesC );
        }
    }









CMemSpyThreadInfoOwnedProcessHandles::CMemSpyThreadInfoOwnedProcessHandles( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
:   CMemSpyThreadInfoHandleByContainer( aContainer, EMemSpyThreadInfoItemTypeOwnedProcessHandles, EMemSpyDriverContainerTypeProcess, aAsyncConstruction )
    {
    }


CMemSpyThreadInfoOwnedProcessHandles* CMemSpyThreadInfoOwnedProcessHandles::NewLC( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
    {
    CMemSpyThreadInfoOwnedProcessHandles* self = new(ELeave) CMemSpyThreadInfoOwnedProcessHandles( aContainer, aAsyncConstruction );
    CleanupStack::PushL( self );
    if  ( !aAsyncConstruction )
        {
        self->ConstructL();
        }
    return self;
    }


EXPORT_C TPtrC CMemSpyThreadInfoOwnedProcessHandles::Name() const
    {
    _LIT(KName, "\tHandles to other\nProcesses");
    return TPtrC( KName );
    }


void CMemSpyThreadInfoOwnedProcessHandles::HandleContainerItemL( TMemSpyDriverHandleInfoGeneric& aItem, TInt aRefCount, TDes& aFullName )
    {
    const TInt bracketPosStart = aFullName.LocateF( TChar('[') );
    const TInt doubleColonPos = aFullName.FindF( _L("::" ) );
    //
    if  ( bracketPosStart >= 0 && doubleColonPos > bracketPosStart && doubleColonPos < aFullName.Length() - 2 )
        {
        // Process
        TPtrC pProcessName( aFullName.Left( bracketPosStart ) );
        HBufC* caption = HBufC::NewLC( KMaxName + 10 );
        TPtr pCaption( caption->Des() );
        pCaption.AppendFormat( _L("[%2d] %S"), aRefCount, &pProcessName );
        
        // Thread id & thread name
        TPtrC pThreadName( aFullName.Mid( doubleColonPos + 2 ) );
        HBufC* value = HBufC::NewLC( KMaxName + 10 );
        TPtr pValue( value->Des() );
        pValue.AppendFormat( _L("[%3d] %S"), aItem.iId, &pThreadName );

        // Add it & tidy up
        AddItemL( pCaption, pValue );
        CleanupStack::PopAndDestroy( 2, caption );
        }
    else
        {
        AddItemL( aFullName, KNullDesC );
        }
    }








































CMemSpyThreadInfoReferencedBy::CMemSpyThreadInfoReferencedBy( CMemSpyThreadInfoContainer& aContainer, TMemSpyThreadInfoItemType aItemType, TMemSpyDriverContainerType aContainerType, TBool aAsyncConstruction )
:   CMemSpyThreadInfoHandleObjectBase( aContainer, aItemType, aContainerType, aAsyncConstruction )
    {
    }


void CMemSpyThreadInfoReferencedBy::GetHandlesL( RArray<THandleWrapper>& aArray )
    {
    aArray.Reset();
    //
    TInt r = KErrNone;
    //
    CMemSpyProcess& process = Container().Thread().Process();
    CMemSpyEngine& engine = process.Engine();
    TIdentityRelation<CMemSpyThreadInfoHandleObjectBase::THandleWrapper> finder( THandleWrapper::Match );

    // We need to either search through:
    //
    // a) all thread & process handles looking for *this thread*, or
    // b) all thread & process handles looking for *this process*
    //
    // We abuse the "container type" as a means of deciding whether it is
    // the thread or the process we are looking for.
    //
    RMemSpyDriverClient& driver = engine.Driver();
    if  ( ContainerType() == EMemSpyDriverContainerTypeProcess )
        {
        const TUint id = Container().Thread().Process().Id();
        r = driver.GetReferencesToMyProcess( id );
        }
    else if ( ContainerType() == EMemSpyDriverContainerTypeThread )
        {
        const TUint id = Container().Thread().Id();
        r = driver.GetReferencesToMyThread( id );
        }
    else
        {
        ASSERT( EFalse );
        }
    User::LeaveIfError( r );

    RMemSpyMemStreamReader stream = driver.StreamOpenL();
    CleanupClosePushL( stream );
    
    // Extract thread matches
    const TInt threadCount = stream.ReadInt32L();
    for( TInt i=0; i<threadCount; i++ )
        {
        TAny* handle = (TAny*) stream.ReadUint32L();

        // Create temporary entry that we'll use as the key in our array...
        CMemSpyThreadInfoHandleObjectBase::THandleWrapper entry( handle, EMemSpyDriverContainerTypeThread );
        
        // Find existing duplicate entry (if there is one...)
        const TInt errorOrIndex = aArray.Find( entry, finder );
	    
	    if  ( errorOrIndex == KErrNotFound )
		    {
		    // Not a duplicate handle, so keep it
		    aArray.AppendL( entry );
		    }
        else if ( errorOrIndex >= 0 )
            {
            // Increment reference count for duplicates...
            CMemSpyThreadInfoHandleObjectBase::THandleWrapper& existingEntry = aArray[ errorOrIndex ];
            ++existingEntry.iRefCount;
            }
        }
    
    // Extract process matches
    const TInt processCount = stream.ReadInt32L();
    for( TInt i=0; i<processCount; i++ )
        {
        TAny* handle = (TAny*) stream.ReadUint32L();

        // Create temporary entry that we'll use as the key in our array...
        CMemSpyThreadInfoHandleObjectBase::THandleWrapper entry( handle, EMemSpyDriverContainerTypeProcess );
        
        // Find existing duplicate entry (if there is one...)
        const TInt errorOrIndex = aArray.Find( entry, finder );
	    
	    if  ( errorOrIndex == KErrNotFound )
		    {
		    // Not a duplicate handle, so keep it
		    aArray.AppendL( entry );
		    }
        else if ( errorOrIndex >= 0 )
            {
            // Increment reference count for duplicates...
            CMemSpyThreadInfoHandleObjectBase::THandleWrapper& existingEntry = aArray[ errorOrIndex ];
            ++existingEntry.iRefCount;
            }
        }
        
    // Tidy up
    CleanupStack::PopAndDestroy( &stream );
    }




















CMemSpyThreadInfoOtherThreads::CMemSpyThreadInfoOtherThreads( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
:   CMemSpyThreadInfoReferencedBy( aContainer, EMemSpyThreadInfoItemTypeOtherThreads, EMemSpyDriverContainerTypeThread, aAsyncConstruction )
    {
    }


CMemSpyThreadInfoOtherThreads* CMemSpyThreadInfoOtherThreads::NewLC( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
    {
    CMemSpyThreadInfoOtherThreads* self = new(ELeave) CMemSpyThreadInfoOtherThreads( aContainer, aAsyncConstruction );
    CleanupStack::PushL( self );
    if  ( !aAsyncConstruction )
        {
        self->ConstructL();
        }
    return self;
    }


EXPORT_C TPtrC CMemSpyThreadInfoOtherThreads::Name() const
    {
    _LIT(KName, "\tReferences this Thread");
    return TPtrC( KName );
    }


void CMemSpyThreadInfoOtherThreads::HandleContainerItemL( TMemSpyDriverHandleInfoGeneric& /*aItem*/, TInt /*aRefCount*/, TDes& aFullName )
    {
    AddItemL( aFullName, KNullDesC );
    }




















CMemSpyThreadInfoOtherProcesses::CMemSpyThreadInfoOtherProcesses( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
:   CMemSpyThreadInfoReferencedBy( aContainer, EMemSpyThreadInfoItemTypeOtherProcesses, EMemSpyDriverContainerTypeProcess, aAsyncConstruction )
    {
    }


CMemSpyThreadInfoOtherProcesses* CMemSpyThreadInfoOtherProcesses::NewLC( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
    {
    CMemSpyThreadInfoOtherProcesses* self = new(ELeave) CMemSpyThreadInfoOtherProcesses( aContainer, aAsyncConstruction );
    CleanupStack::PushL( self );
    if  ( !aAsyncConstruction )
        {
        self->ConstructL();
        }
    return self;
    }


EXPORT_C TPtrC CMemSpyThreadInfoOtherProcesses::Name() const
    {
    _LIT(KName, "\tReferences this Process");
    return TPtrC( KName );
    }


void CMemSpyThreadInfoOtherProcesses::HandleContainerItemL( TMemSpyDriverHandleInfoGeneric& /*aItem*/, TInt /*aRefCount*/, TDes& aFullName )
    {
    AddItemL( aFullName, KNullDesC );
    }

















CMemSpyThreadInfoMemoryTracking::CMemSpyThreadInfoMemoryTracking( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
:   CMemSpyThreadInfoItemBase( aContainer, EMemSpyThreadInfoItemTypeMemoryTracking, aAsyncConstruction ), iTotalIncludesSharedMemory( ETrue )
    {
    }


CMemSpyThreadInfoMemoryTracking::~CMemSpyThreadInfoMemoryTracking()
    {
#ifdef _DEBUG
    RDebug::Printf( "CMemSpyThreadInfoMemoryTracking::~CMemSpyThreadInfoMemoryTracking() - START - this: 0x%08x, iTracker: 0x%08x", this, iTracker );
#endif
    //
    TrackingObserverRemove( *this );
    //
    delete iInfoHWM;
    delete iInfoPeak;
    delete iInfoCurrent;
    //
#ifdef _DEBUG
    RDebug::Printf( "CMemSpyThreadInfoMemoryTracking::~CMemSpyThreadInfoMemoryTracking() - END - this: 0x%08x, iTracker: 0x%08x", this, iTracker );
#endif
    }


void CMemSpyThreadInfoMemoryTracking::ConstructL()
    {
#ifdef _DEBUG
    RDebug::Printf( "CMemSpyThreadInfoMemoryTracking::ConstructL() - START - this: 0x%08x, iTracker: 0x%08x", this, iTracker );
#endif
    CMemSpyEngine& engine = Container().Thread().Process().Engine();
    //
    const TProcessId pid = Container().Thread().Process().Id();
    iTracker = engine.HelperProcess().TrackerOrNull( pid );

#ifdef _DEBUG
    RDebug::Printf( "CMemSpyThreadInfoMemoryTracking::ConstructL() - requesting observer add... - this: 0x%08x, iTracker: 0x%08x", this, iTracker );
#endif
    TrackingObserverAddL( *this );
    //
#ifdef _DEBUG
    RDebug::Printf( "CMemSpyThreadInfoMemoryTracking::ConstructL() - preparing info item... - this: 0x%08x, iTracker: 0x%08x", this, iTracker );
#endif
    if  ( iTracker )
        {
        delete iInfoCurrent;
        iInfoCurrent = NULL;
        iInfoCurrent = CMemSpyThreadInfoMemoryTrackingStatisticsCurrent::NewLC( Container(), EFalse );
        CleanupStack::Pop( iInfoCurrent );
        //
        delete iInfoHWM;
        iInfoHWM = NULL;
        iInfoHWM = CMemSpyThreadInfoMemoryTrackingStatisticsHWM::NewLC( Container(), EFalse );
        CleanupStack::Pop( iInfoHWM );
        //
        delete iInfoPeak;
        iInfoPeak = NULL;
        iInfoPeak = CMemSpyThreadInfoMemoryTrackingStatisticsPeak::NewLC( Container(), EFalse );
        CleanupStack::Pop( iInfoPeak );
        }
    
#ifdef _DEBUG
    RDebug::Printf( "CMemSpyThreadInfoMemoryTracking::ConstructL() - prepared info items - this: 0x%08x, iTracker: 0x%08x", this, iTracker );
#endif

    // Prepare items
    _LIT( KItem0, "Tracking" );
    AddItemOnOffL( KItem0, ( iTracker ) ? iTracker->AmTracking() : EFalse );

    TInt64 valCurrent( 0 );
    if  ( iTracker )
        {
        if  ( TotalIncludesSharedMemory() )
            {
            valCurrent = iTracker->InfoCurrent().TotalIncShared();
            }
        else
            {
            valCurrent = iTracker->InfoCurrent().TotalExcShared();
            }
        }
    _LIT( KItem1, "Total [Current]" );
    AddItemLongL( KItem1, valCurrent );

    TInt64 valHWM( 0 );
    if  ( iTracker )
        {
        if  ( TotalIncludesSharedMemory() )
            {
            valHWM = iTracker->InfoHWMIncShared().TotalIncShared();
            }
        else
            {
            valHWM = iTracker->InfoHWMExcShared().TotalExcShared();
            }
        }
    _LIT( KItem2, "Total [HWM]" );
    AddItemLongL( KItem2, valHWM );

    TInt64 valPeak( 0 );
    if  ( iTracker )
        {
        if  ( TotalIncludesSharedMemory() )
            {
            valPeak = iTracker->InfoPeaks().TotalIncShared();
            }
        else
            {
            valPeak = iTracker->InfoPeaks().TotalExcShared();
            }
        }
    _LIT( KItem3, "Total [Peaks]" );
    AddItemLongL( KItem3, valPeak );

    //
    Container().NotifyObserverL( MMemSpyThreadInfoContainerObserver::EInfoItemChanged, Type() );
#ifdef _DEBUG
    RDebug::Printf( "CMemSpyThreadInfoMemoryTracking::ConstructL() - END - this: 0x%08x", this );
#endif
    }


CMemSpyThreadInfoMemoryTracking* CMemSpyThreadInfoMemoryTracking::NewLC( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
    {
    CMemSpyThreadInfoMemoryTracking* self = new(ELeave) CMemSpyThreadInfoMemoryTracking( aContainer, aAsyncConstruction );
    CleanupStack::PushL( self );
    if  ( !aAsyncConstruction )
        {
        self->ConstructL();
        }
    return self;
    }


EXPORT_C TPtrC CMemSpyThreadInfoMemoryTracking::Name() const
    {
    _LIT(KName, "\tMemory Tracking");
    return TPtrC( KName );
    }


EXPORT_C TBool CMemSpyThreadInfoMemoryTracking::TrackingActive() const
    {
    return ( iTracker != NULL ? iTracker->AmTracking() : EFalse );
    }


EXPORT_C TBool CMemSpyThreadInfoMemoryTracking::TotalIncludesSharedMemory() const
    {
    return iTotalIncludesSharedMemory;
    }


EXPORT_C void CMemSpyThreadInfoMemoryTracking::TrackingSetTotalIncludesSharedMemoryL( TBool aIncludesSharedMemory )
    {
    iTotalIncludesSharedMemory = aIncludesSharedMemory;

    if  ( iTracker )
        {
        iInfoCurrent->SetTotalIncludesSharedMemoryL( aIncludesSharedMemory );
        iInfoHWM->SetTotalIncludesSharedMemoryL( aIncludesSharedMemory );
        iInfoPeak->SetTotalIncludesSharedMemoryL( aIncludesSharedMemory );
        
        // Update totals
        TRAP_IGNORE( UpdateCaptionsL( iTracker->InfoCurrent(), iTracker->InfoHWMIncShared(), iTracker->InfoHWMExcShared() ) );
        }
    }


EXPORT_C void CMemSpyThreadInfoMemoryTracking::TrackingStartL()
    {
    if  ( iTracker == NULL )
        {
        CMemSpyProcess& process = Container().Thread().Process();
        CMemSpyEngine& engine = process.Engine();
        iTracker = &engine.HelperProcess().TrackerL( process );

        // Make sure we are also listening to the tracker!
        TrackingObserverAddL( *this );
        //
        CMemSpyThreadInfoMemoryTrackingStatisticsCurrent* infoCurrent = CMemSpyThreadInfoMemoryTrackingStatisticsCurrent::NewLC( Container(), EFalse );
        CMemSpyThreadInfoMemoryTrackingStatisticsHWM* infoHWM = CMemSpyThreadInfoMemoryTrackingStatisticsHWM::NewLC( Container(), EFalse );
        CMemSpyThreadInfoMemoryTrackingStatisticsPeak* infoPeak = CMemSpyThreadInfoMemoryTrackingStatisticsPeak::NewLC( Container(), EFalse );
        //
        iInfoCurrent = infoCurrent;
        iInfoHWM = infoHWM;
        iInfoPeak = infoPeak;
        //
        CleanupStack::Pop( iInfoPeak );
        CleanupStack::Pop( infoHWM );
        CleanupStack::Pop( infoCurrent );
        //
        TrackingSetTotalIncludesSharedMemoryL( iTotalIncludesSharedMemory );
        }

    iTracker->StartL();

    UpdateCaptionsL();
    }


EXPORT_C void CMemSpyThreadInfoMemoryTracking::TrackingStopL()
    {
    if  ( iTracker != NULL )
        {
        iTracker->Stop();
        }

    UpdateCaptionsL();
    }


EXPORT_C void CMemSpyThreadInfoMemoryTracking::TrackingResetHWML()
    {
    if  ( iTracker != NULL )
        {
        iTracker->ResetHWML();
        }
    }


EXPORT_C void CMemSpyThreadInfoMemoryTracking::TrackingObserverAddL( MMemSpyEngineProcessMemoryTrackerObserver& aObserver )
    {
#ifdef _DEBUG
    RDebug::Printf( "CMemSpyThreadInfoMemoryTracking::TrackingObserverAddL() - START - iTracker: 0x%08x, this: 0x%08x", iTracker, this );
#endif

    if  ( iTracker != NULL )
        {
        iTracker->AddObserverL( aObserver );
        }

#ifdef _DEBUG
    RDebug::Printf( "CMemSpyThreadInfoMemoryTracking::TrackingObserverAddL() - END - iTracker: 0x%08x, this: 0x%08x", iTracker, this );
#endif
    }


EXPORT_C void CMemSpyThreadInfoMemoryTracking::TrackingObserverRemove( MMemSpyEngineProcessMemoryTrackerObserver& aObserver )
    {
#ifdef _DEBUG
    RDebug::Printf( "CMemSpyThreadInfoMemoryTracking::TrackingObserverRemove() - START - iTracker: 0x%08x, this: 0x%08x", iTracker, this );
#endif

    if  ( iTracker != NULL )
        {
        iTracker->RemoveObserver( aObserver );
        }

#ifdef _DEBUG
    RDebug::Printf( "CMemSpyThreadInfoMemoryTracking::TrackingObserverRemove() - END - iTracker: 0x%08x, this: 0x%08x", iTracker, this );
#endif
    }


EXPORT_C MDesCArray& CMemSpyThreadInfoMemoryTracking::InfoCurrent()
    {
    return *iInfoCurrent;
    }


EXPORT_C MDesCArray& CMemSpyThreadInfoMemoryTracking::InfoHWM()
    {
    return *iInfoHWM;
    }


EXPORT_C MDesCArray& CMemSpyThreadInfoMemoryTracking::InfoPeak()
    {
    return *iInfoPeak;
    }


void CMemSpyThreadInfoMemoryTracking::HandleMemoryTrackingStartedL()
    {
    __ASSERT_ALWAYS( iTracker, MemSpyEngineUtils::Panic( EMemSpyEnginePanicTrackerNull1 ) );
    CMemSpyThreadInfoItemBase::CItem& trackingItem = Item( 0 );
    trackingItem.SetOnOffL( iTracker->AmTracking() );
    //
    Container().NotifyObserverL( MMemSpyThreadInfoContainerObserver::EInfoItemChanged, Type() );
    }


void CMemSpyThreadInfoMemoryTracking::HandleMemoryTrackingStoppedL()
    {
    __ASSERT_ALWAYS( iTracker, MemSpyEngineUtils::Panic( EMemSpyEnginePanicTrackerNull2 ) );
    CMemSpyThreadInfoItemBase::CItem& trackingItem = Item( 0 );
    trackingItem.SetOnOffL( iTracker->AmTracking() );
    //
    Container().NotifyObserverL( MMemSpyThreadInfoContainerObserver::EInfoItemChanged, Type() );
    }


void CMemSpyThreadInfoMemoryTracking::HandleMemoryChangedL( const TProcessId& /*aPid*/, const TMemSpyDriverProcessInspectionInfo& aInfoCurrent, const TMemSpyDriverProcessInspectionInfo& aHWMInfoIncShared, const TMemSpyDriverProcessInspectionInfo& aHWMInfoExcShared )
    {
#ifdef _DEBUG
    RDebug::Printf( "CMemSpyThreadInfoMemoryTracking::HandleMemoryChangedL() - START - this: 0x%08x", this );
#endif 

    __ASSERT_ALWAYS( iTracker, MemSpyEngineUtils::Panic( EMemSpyEnginePanicTrackerNull3 ) );
    UpdateCaptionsL( aInfoCurrent, aHWMInfoIncShared, aHWMInfoExcShared );

#ifdef _DEBUG
    RDebug::Printf( "CMemSpyThreadInfoMemoryTracking::HandleMemoryChangedL() - END - this: 0x%08x", this );
#endif 
    }


void CMemSpyThreadInfoMemoryTracking::UpdateCaptionsL()
    {
    if  ( iTracker )
        {
        UpdateCaptionsL( iTracker->InfoCurrent(), iTracker->InfoHWMIncShared(), iTracker->InfoHWMExcShared() );
        }
    }


void CMemSpyThreadInfoMemoryTracking::UpdateCaptionsL( const TMemSpyDriverProcessInspectionInfo& aInfoCurrent, const TMemSpyDriverProcessInspectionInfo& aHWMInfoIncShared, const TMemSpyDriverProcessInspectionInfo& aHWMInfoExcShared )
    {
    if  ( iTracker )
        {
        // Update caption
        Item( 0 ).SetOnOffL( TrackingActive() );
  
        if  ( TotalIncludesSharedMemory() )
            {
            Item( 1 ).SetLongL( aInfoCurrent.TotalIncShared() );
            Item( 2 ).SetLongL( aHWMInfoIncShared.TotalIncShared() );
            Item( 3 ).SetLongL( iTracker->InfoPeaks().TotalIncShared() );
            }
        else
            {
            Item( 1 ).SetLongL( aInfoCurrent.TotalExcShared() );
            Item( 2 ).SetLongL( aHWMInfoExcShared.TotalExcShared() );
            Item( 3 ).SetLongL( iTracker->InfoPeaks().TotalExcShared() );
            }

        Container().NotifyObserverL( MMemSpyThreadInfoContainerObserver::EInfoItemChanged, Type() );
        }
    }
































CMemSpyThreadInfoMemoryTrackingStatisticsCurrent::CMemSpyThreadInfoMemoryTrackingStatisticsCurrent( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
:   CMemSpyThreadInfoItemBase( aContainer, EMemSpyThreadInfoItemTypeMemoryTrackingCurrent, aAsyncConstruction ), iTotalIncludesSharedMemory( ETrue )
    {
    }


CMemSpyThreadInfoMemoryTrackingStatisticsCurrent::~CMemSpyThreadInfoMemoryTrackingStatisticsCurrent()
    {
    if  ( iTracker )
        {
        iTracker->RemoveObserver( *this );
        }
    }


void CMemSpyThreadInfoMemoryTrackingStatisticsCurrent::ConstructL()
    {
    CMemSpyEngine& engine = Container().Thread().Process().Engine();
    //
    if  ( iTracker )
        {
        iTracker->RemoveObserver( *this );
        }
    iTracker = &Container().Engine().HelperProcess().TrackerL( Container().Thread().Process() );
    if  ( iTracker )
        {
        iTracker->AddObserverL( *this );
        //
        _LIT( KItem1, "Stack Memory" );
        AddItemDecimalL( KItem1, iTracker->InfoCurrent().iMemoryStack );
        //
        _LIT( KItem2, "Heap Memory" );
        AddItemDecimalL( KItem2, iTracker->InfoCurrent().iMemoryHeap );
        //
        _LIT( KItem3, "Local Chunk Memory" );
        AddItemDecimalL( KItem3, iTracker->InfoCurrent().iMemoryChunkLocal );
        //
        _LIT( KItem4, "Shared Chunk Memory" );
        AddItemDecimalL( KItem4, iTracker->InfoCurrent().iMemoryChunkShared );
        //
        _LIT( KItem5, "Global Data Memory" );
        AddItemDecimalL( KItem5, iTracker->InfoCurrent().iMemoryGlobalData );
        //
        _LIT( KItem6, "Total" );
        if  ( iTotalIncludesSharedMemory )
            {
            AddItemLongL( KItem6, iTracker->InfoCurrent().TotalIncShared() );
            }
        else
            {
            AddItemLongL( KItem6, iTracker->InfoCurrent().TotalExcShared() );
            }
        }
    }


CMemSpyThreadInfoMemoryTrackingStatisticsCurrent* CMemSpyThreadInfoMemoryTrackingStatisticsCurrent::NewLC( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
    {
    CMemSpyThreadInfoMemoryTrackingStatisticsCurrent* self = new(ELeave) CMemSpyThreadInfoMemoryTrackingStatisticsCurrent( aContainer, aAsyncConstruction );
    CleanupStack::PushL( self );
    if  ( !aAsyncConstruction )
        {
        self->ConstructL();
        }
    return self;
    }


TPtrC CMemSpyThreadInfoMemoryTrackingStatisticsCurrent::Name() const
    {
    _LIT(KName, "\tCurrent Statistics");
    return TPtrC( KName );
    }


void CMemSpyThreadInfoMemoryTrackingStatisticsCurrent::SetTotalIncludesSharedMemoryL( TBool aIncludesSharedMemory )
    {
    iTotalIncludesSharedMemory = aIncludesSharedMemory;
    
    // Update totals
    HandleMemoryChangedL( iTracker->ProcessId(), iTracker->InfoCurrent(), iTracker->InfoHWMIncShared(), iTracker->InfoHWMExcShared() );
    }


void CMemSpyThreadInfoMemoryTrackingStatisticsCurrent::HandleMemoryTrackingStartedL()
    {
    }


void CMemSpyThreadInfoMemoryTrackingStatisticsCurrent::HandleMemoryTrackingStoppedL()
    {
    }


void CMemSpyThreadInfoMemoryTrackingStatisticsCurrent::HandleMemoryChangedL( const TProcessId& /*aPid*/, const TMemSpyDriverProcessInspectionInfo& aInfoCurrent, const TMemSpyDriverProcessInspectionInfo& /*aHWMInfoIncShared*/, const TMemSpyDriverProcessInspectionInfo& /*aHWMInfoExcShared*/ )
    {
    Item( 0 ).SetDecimalL( aInfoCurrent.iMemoryStack );
    Item( 1 ).SetDecimalL( aInfoCurrent.iMemoryHeap );
    Item( 2 ).SetDecimalL( aInfoCurrent.iMemoryChunkLocal );
    Item( 3 ).SetDecimalL( aInfoCurrent.iMemoryChunkShared );
    Item( 4 ).SetDecimalL( aInfoCurrent.iMemoryGlobalData );
    //
    if  ( iTotalIncludesSharedMemory )
        {
        Item( 5 ).SetLongL( aInfoCurrent.TotalIncShared() );
        }
    else
        {
        Item( 5 ).SetLongL( aInfoCurrent.TotalExcShared() );
        }
    }



















CMemSpyThreadInfoMemoryTrackingStatisticsPeak::CMemSpyThreadInfoMemoryTrackingStatisticsPeak( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
:   CMemSpyThreadInfoItemBase( aContainer, EMemSpyThreadInfoItemTypeMemoryTrackingPeak, aAsyncConstruction ), iTotalIncludesSharedMemory( ETrue )
    {
    }


CMemSpyThreadInfoMemoryTrackingStatisticsPeak::~CMemSpyThreadInfoMemoryTrackingStatisticsPeak()
    {
    if  ( iTracker )
        {
        iTracker->RemoveObserver( *this );
        }
    }


void CMemSpyThreadInfoMemoryTrackingStatisticsPeak::ConstructL()
    {
    CMemSpyEngine& engine = Container().Thread().Process().Engine();
    //
    if  ( iTracker )
        {
        iTracker->RemoveObserver( *this );
        }
    iTracker = &Container().Engine().HelperProcess().TrackerL( Container().Thread().Process() );
    if  ( iTracker )
        {
        iTracker->AddObserverL( *this );
        //
        _LIT( KItem1, "Stack Memory" );
        AddItemDecimalL( KItem1, iTracker->InfoPeaks().iMemoryStack );
        //
        _LIT( KItem2, "Heap Memory" );
        AddItemDecimalL( KItem2, iTracker->InfoPeaks().iMemoryHeap );
        //
        _LIT( KItem3, "Local Chunk Memory" );
        AddItemDecimalL( KItem3, iTracker->InfoPeaks().iMemoryChunkLocal );
        //
        _LIT( KItem4, "Shared Chunk Memory" );
        AddItemDecimalL( KItem4, iTracker->InfoPeaks().iMemoryChunkShared );
        //
        _LIT( KItem5, "Global Data Memory" );
        AddItemDecimalL( KItem5, iTracker->InfoPeaks().iMemoryGlobalData );
        //
        _LIT( KItem6, "Total" );
        if  ( iTotalIncludesSharedMemory )
            {
            AddItemLongL( KItem6, iTracker->InfoPeaks().TotalIncShared() );
            }
        else
            {
            AddItemLongL( KItem6, iTracker->InfoPeaks().TotalExcShared() );
            }
        }
    }


CMemSpyThreadInfoMemoryTrackingStatisticsPeak* CMemSpyThreadInfoMemoryTrackingStatisticsPeak::NewLC( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
    {
    CMemSpyThreadInfoMemoryTrackingStatisticsPeak* self = new(ELeave) CMemSpyThreadInfoMemoryTrackingStatisticsPeak( aContainer, aAsyncConstruction );
    CleanupStack::PushL( self );
    if  ( !aAsyncConstruction )
        {
        self->ConstructL();
        }
    return self;
    }


TPtrC CMemSpyThreadInfoMemoryTrackingStatisticsPeak::Name() const
    {
    _LIT(KName, "\tPeak Statistics");
    return TPtrC( KName );
    }


void CMemSpyThreadInfoMemoryTrackingStatisticsPeak::SetTotalIncludesSharedMemoryL( TBool aIncludesSharedMemory )
    {
    iTotalIncludesSharedMemory = aIncludesSharedMemory;
    
    // Update totals
    HandleMemoryChangedL( iTracker->ProcessId(), iTracker->InfoCurrent(), iTracker->InfoHWMIncShared(), iTracker->InfoHWMExcShared() );
    }


void CMemSpyThreadInfoMemoryTrackingStatisticsPeak::HandleMemoryTrackingStartedL()
    {
    }


void CMemSpyThreadInfoMemoryTrackingStatisticsPeak::HandleMemoryTrackingStoppedL()
    {
    }


void CMemSpyThreadInfoMemoryTrackingStatisticsPeak::HandleMemoryChangedL( const TProcessId& /*aPid*/, const TMemSpyDriverProcessInspectionInfo& /*aInfoCurrent*/, const TMemSpyDriverProcessInspectionInfo& /*aHWMInfoIncShared*/, const TMemSpyDriverProcessInspectionInfo& /*aHWMInfoExcShared*/ )
    {
    Item( 0 ).SetDecimalL( iTracker->InfoPeaks().iMemoryStack );
    Item( 1 ).SetDecimalL( iTracker->InfoPeaks().iMemoryHeap );
    Item( 2 ).SetDecimalL( iTracker->InfoPeaks().iMemoryChunkLocal );
    Item( 3 ).SetDecimalL( iTracker->InfoPeaks().iMemoryChunkShared );
    Item( 4 ).SetDecimalL( iTracker->InfoPeaks().iMemoryGlobalData );
    //
    if ( iTotalIncludesSharedMemory )
        {
        Item( 5 ).SetLongL( iTracker->InfoPeaks().TotalIncShared() );
        }
    else
        {
        Item( 5 ).SetLongL( iTracker->InfoPeaks().TotalExcShared() );
        }
    }
















CMemSpyThreadInfoMemoryTrackingStatisticsHWM::CMemSpyThreadInfoMemoryTrackingStatisticsHWM( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
:   CMemSpyThreadInfoItemBase( aContainer, EMemSpyThreadInfoItemTypeMemoryTrackingHWM, aAsyncConstruction ), iTotalIncludesSharedMemory( ETrue )
    {
    }


CMemSpyThreadInfoMemoryTrackingStatisticsHWM::~CMemSpyThreadInfoMemoryTrackingStatisticsHWM()
    {
    if  ( iTracker )
        {
        iTracker->RemoveObserver( *this );
        }
    }


void CMemSpyThreadInfoMemoryTrackingStatisticsHWM::ConstructL()
    {
    CMemSpyEngine& engine = Container().Thread().Process().Engine();
    //
    if  ( iTracker )
        {
        iTracker->RemoveObserver( *this );
        }
    iTracker = &Container().Engine().HelperProcess().TrackerL( Container().Thread().Process() );
    if  ( iTracker )
        {
        iTracker->AddObserverL( *this );
        //
        _LIT( KItem1, "Stack Memory" );
        _LIT( KItem2, "Heap Memory" );
        _LIT( KItem3, "Local Chunk Memory" );
        _LIT( KItem4, "Shared Chunk Memory" );
        _LIT( KItem5, "Global Data Memory" );
        _LIT( KItem6, "Total" );
        //
        if  ( iTotalIncludesSharedMemory )
            {
            AddItemDecimalL( KItem1, iTracker->InfoHWMIncShared().iMemoryStack );
            AddItemDecimalL( KItem2, iTracker->InfoHWMIncShared().iMemoryHeap );
            AddItemDecimalL( KItem3, iTracker->InfoHWMIncShared().iMemoryChunkLocal );
            AddItemDecimalL( KItem4, iTracker->InfoHWMIncShared().iMemoryChunkShared );
            AddItemDecimalL( KItem5, iTracker->InfoHWMIncShared().iMemoryGlobalData );
            AddItemLongL(    KItem6, iTracker->InfoHWMIncShared().TotalIncShared() );
            }
        else
            {
            AddItemDecimalL( KItem1, iTracker->InfoHWMExcShared().iMemoryStack );
            AddItemDecimalL( KItem2, iTracker->InfoHWMExcShared().iMemoryHeap );
            AddItemDecimalL( KItem3, iTracker->InfoHWMExcShared().iMemoryChunkLocal );
            AddItemDecimalL( KItem4, iTracker->InfoHWMExcShared().iMemoryChunkShared );
            AddItemDecimalL( KItem5, iTracker->InfoHWMExcShared().iMemoryGlobalData );
            AddItemLongL(    KItem6, iTracker->InfoHWMExcShared().TotalExcShared() );
            }
        }
    }


CMemSpyThreadInfoMemoryTrackingStatisticsHWM* CMemSpyThreadInfoMemoryTrackingStatisticsHWM::NewLC( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
    {
    CMemSpyThreadInfoMemoryTrackingStatisticsHWM* self = new(ELeave) CMemSpyThreadInfoMemoryTrackingStatisticsHWM( aContainer, aAsyncConstruction );
    CleanupStack::PushL( self );
    if  ( !aAsyncConstruction )
        {
        self->ConstructL();
        }
    return self;
    }


void CMemSpyThreadInfoMemoryTrackingStatisticsHWM::SetTotalIncludesSharedMemoryL( TBool aIncludesSharedMemory )
    {
    iTotalIncludesSharedMemory = aIncludesSharedMemory;
    
    // Update totals
    HandleMemoryChangedL( iTracker->ProcessId(), iTracker->InfoCurrent(), iTracker->InfoHWMIncShared(), iTracker->InfoHWMExcShared() );
    }


TPtrC CMemSpyThreadInfoMemoryTrackingStatisticsHWM::Name() const
    {
    _LIT(KName, "\tHigh-Water-Mark Statistics");
    return TPtrC( KName );
    }


void CMemSpyThreadInfoMemoryTrackingStatisticsHWM::HandleMemoryTrackingStartedL()
    {
    }


void CMemSpyThreadInfoMemoryTrackingStatisticsHWM::HandleMemoryTrackingStoppedL()
    {
    }


void CMemSpyThreadInfoMemoryTrackingStatisticsHWM::HandleMemoryChangedL( const TProcessId& /*aPid*/, const TMemSpyDriverProcessInspectionInfo& /*aInfoCurrent*/, const TMemSpyDriverProcessInspectionInfo& aHWMInfoIncShared, const TMemSpyDriverProcessInspectionInfo& aHWMInfoExcShared )
    {
    if  ( iTotalIncludesSharedMemory )
        {
        Item( 0 ).SetDecimalL( aHWMInfoIncShared.iMemoryStack );
        Item( 1 ).SetDecimalL( aHWMInfoIncShared.iMemoryHeap );
        Item( 2 ).SetDecimalL( aHWMInfoIncShared.iMemoryChunkLocal );
        Item( 3 ).SetDecimalL( aHWMInfoIncShared.iMemoryChunkShared );
        Item( 4 ).SetDecimalL( aHWMInfoIncShared.iMemoryGlobalData );
        Item( 5 ).SetLongL(    aHWMInfoIncShared.TotalIncShared() );
        }
    else
        {
        Item( 0 ).SetDecimalL( aHWMInfoExcShared.iMemoryStack );
        Item( 1 ).SetDecimalL( aHWMInfoExcShared.iMemoryHeap );
        Item( 2 ).SetDecimalL( aHWMInfoExcShared.iMemoryChunkLocal );
        Item( 3 ).SetDecimalL( aHWMInfoExcShared.iMemoryChunkShared );
        Item( 4 ).SetDecimalL( aHWMInfoExcShared.iMemoryGlobalData );
        Item( 5 ).SetLongL(    aHWMInfoExcShared.TotalExcShared() );
        }
    }