diff -r 000000000000 -r a03f92240627 memspy/Engine/Source/ThreadAndProcess/MemSpyEngineObjectThread.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/memspy/Engine/Source/ThreadAndProcess/MemSpyEngineObjectThread.cpp Tue Feb 02 01:57:15 2010 +0200 @@ -0,0 +1,527 @@ +/* +* 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 + +// System includes +#include + +// Driver includes +#include + +// User includes +#include +#include +#include +#include + +// Constants +_LIT( KMemSpyUnknownExitCategory, "Unknown ExitCat" ); +_LIT( KMemSpyUnknownThreadName, "Unknown Thread" ); +_LIT( KMemSpyThreadDoubleColon, "::" ); + + +CMemSpyThread::CMemSpyThread( TThreadId aId, CMemSpyProcess& aProcess ) +: CMemSpyEngineObject( aProcess ), iId( aId ), iProcess( &aProcess ) + { + } + + +CMemSpyThread::~CMemSpyThread() + { + if ( iInfoContainer ) + { + iInfoContainer->Close(); + } + delete iName; + } + + +void CMemSpyThread::ConstructL() + { + RefreshL(); + } + + +CMemSpyThread* CMemSpyThread::NewL( TThreadId aId, CMemSpyProcess& aProcess ) + { + CMemSpyThread* self = CMemSpyThread::NewLC( aId, aProcess ); + CleanupStack::Pop( self ); + return self; + } + + +CMemSpyThread* CMemSpyThread::NewLC( TThreadId aId, CMemSpyProcess& aProcess ) + { + CMemSpyThread* self = new(ELeave) CMemSpyThread( aId, aProcess ); + CleanupStack::PushL( self ); + self->ConstructL(); + return self; + } + + +EXPORT_C void CMemSpyThread::Open() + { + if ( !OpenOrCloseInProgress() ) + { + SetOpenOrCloseInProgress( ETrue ); + CMemSpyEngineObject::Open(); + SetOpenOrCloseInProgress( EFalse ); + } + } + + +EXPORT_C void CMemSpyThread::Close() + { + if ( !OpenOrCloseInProgress() ) + { + SetOpenOrCloseInProgress( ETrue ); + CMemSpyEngineObject::Close(); + SetOpenOrCloseInProgress( EFalse ); + } + } + + +void CMemSpyThread::AppendPriority( TDes& aDes, TThreadPriority aPriority ) + { + switch( aPriority ) + { + case EPriorityNull: + aDes += _L("[Null]"); + break; + case EPriorityMuchLess: + aDes += _L("[Much Less]"); + break; + case EPriorityLess: + aDes += _L("[Less]"); + break; + case EPriorityNormal: + aDes += _L("[Normal]"); + break; + case EPriorityMore: + aDes += _L("[More]"); + break; + case EPriorityMuchMore: + aDes += _L("[Much More]"); + break; + case EPriorityRealTime: + aDes += _L("[Real Time]"); + break; + + // Absolute values + case EPriorityAbsoluteVeryLow: + aDes += _L("[Abs Very Low]"); + break; + case EPriorityAbsoluteLowNormal: + aDes += _L("[Abs Low Norm]"); + break; + case EPriorityAbsoluteLow: + aDes += _L("[Abs Low]"); + break; + case EPriorityAbsoluteBackground: + aDes += _L("[Abs Bgnd]"); + break; + case EPriorityAbsoluteBackgroundNormal: + aDes += _L("[Abs Bgnd Norm]"); + break; + case EPriorityAbsoluteForeground: + aDes += _L("[Abs Fgnd]"); + break; + case EPriorityAbsoluteForegroundNormal: + aDes += _L("[Abs Fgnd Norm]"); + break; + case EPriorityAbsoluteHigh: + aDes += _L("[Abs High]"); + break; + case EPriorityAbsoluteHighNormal: + aDes += _L("[Abs High Norm]"); + break; + case EPriorityAbsoluteRealTime1: + case EPriorityAbsoluteRealTime2: + case EPriorityAbsoluteRealTime3: + case EPriorityAbsoluteRealTime4: + case EPriorityAbsoluteRealTime5: + case EPriorityAbsoluteRealTime6: + case EPriorityAbsoluteRealTime7: + case EPriorityAbsoluteRealTime8: + aDes.AppendFormat( _L("[Abs RT %d]"), ( aPriority - EPriorityAbsoluteRealTime1 ) + 1 ); + break; + default: + aDes += _L("[Unknown Pri.]"); + break; + } + } + + +void CMemSpyThread::AppendExitType( TDes& aDes, TExitType aType ) + { + _LIT( KExitTypeKilled, "Killed" ); + _LIT( KExitTypeTerminated, "Terminated" ); + _LIT( KExitTypePanicked, "Panicked" ); + _LIT( KExitTypePending, "Pending" ); + + // Panic and Terminate are exceptional exit conditions. + // Kill, is ironically, not an exceptional condition. + switch( aType ) + { + case EExitKill: + aDes += KExitTypeKilled; + break; + case EExitTerminate: + aDes += KExitTypeTerminated; + break; + case EExitPanic: + aDes += KExitTypePanicked; + break; + default: + case EExitPending: + aDes += KExitTypePending; + break; + } + } + + +void CMemSpyThread::AppendExitInfo( TDes& aDes, TExitType aType, TInt aExitReason, const TDesC& aExitCategory ) + { + aDes.Append( '[' ); + const TInt length = aDes.Length(); + AppendExitType( aDes, aType ); + aDes.SetLength( length + 1 ); // Remove all but the first letter + aDes.Append( ']' ); + + if ( aType == EExitKill || aType == EExitPending ) + { + // Kill implies "clean" exit. Pending implies not yet dead. + } + else + { + TMemSpyTruncateOverflow overflow; + + // Terminate or Panic implies abnormal exit condition, so + // show full exit info. + _LIT( KAbnormalFormatSpec, " %S-%d" ); + aDes.AppendFormat( KAbnormalFormatSpec, &overflow, &aExitCategory, aExitReason ); + } + } + + +CMemSpyEngine& CMemSpyThread::Engine() const + { + return Process().Engine(); + } + + +void CMemSpyThread::OpenLC( RThread& aThread ) + { + const TInt error = Open( aThread ); + User::LeaveIfError( error ); + CleanupClosePushL( aThread ); + } + + +TInt CMemSpyThread::Open( RThread& aThread ) + { + CMemSpyEngine& engine = iProcess->Engine(); + RMemSpyDriverClient& driver = engine.Driver(); + const TInt error = driver.OpenThread( iId, aThread ); + return error; + } + + +EXPORT_C TPtrC CMemSpyThread::Name() const + { + // Just return the pure name, minus the leading tab + TPtrC pRet( iName->Mid(2) ); + + // Find the last tab position + TInt pos = pRet.Locate(TChar('\t')); + if ( pos > 0 ) + { + pRet.Set( pRet.Left( pos ) ); + } + // + return pRet; + } + + +EXPORT_C TFullName CMemSpyThread::FullName() const + { + TFullName name( iProcess->Name() ); + name += KMemSpyThreadDoubleColon; + name += Name(); + // + return name; + } + + +EXPORT_C TBool CMemSpyThread::IsSystemPermanent() const + { + const TBool ret = ( iFlags & KThreadFlagSystemPermanent ); + return ret; + } + + +EXPORT_C TBool CMemSpyThread::IsSystemCritical() const + { + const TBool ret = ( iFlags & KThreadFlagSystemCritical ); + return ret; + } + + +EXPORT_C CMemSpyThreadInfoContainer& CMemSpyThread::InfoContainerL() + { + if ( iInfoContainer == NULL ) + { + const TBool KConstructAsynchronously = ETrue; + iInfoContainer = CMemSpyThreadInfoContainer::NewL( *this, KConstructAsynchronously ); + } + // + return *iInfoContainer; + } + + +EXPORT_C CMemSpyThreadInfoContainer& CMemSpyThread::InfoContainerForceSyncronousConstructionL() + { + if ( iInfoContainer == NULL ) + { + const TBool KConstructSynchronously = EFalse; + iInfoContainer = CMemSpyThreadInfoContainer::NewL( *this, KConstructSynchronously ); + } + // + return *iInfoContainer; + } + + +EXPORT_C void CMemSpyThread::KillL() + { + CMemSpyEngine& engine = iProcess->Engine(); + RMemSpyDriverClient& driver = engine.Driver(); + // + User::LeaveIfError( driver.ThreadEnd( Id(), EExitKill ) ); + } + + +EXPORT_C void CMemSpyThread::TerminateL() + { + CMemSpyEngine& engine = iProcess->Engine(); + RMemSpyDriverClient& driver = engine.Driver(); + // + User::LeaveIfError( driver.ThreadEnd( Id(), EExitTerminate ) ); + } + + +EXPORT_C void CMemSpyThread::PanicL() + { + CMemSpyEngine& engine = iProcess->Engine(); + RMemSpyDriverClient& driver = engine.Driver(); + // + User::LeaveIfError( driver.ThreadEnd( Id(), EExitPanic ) ); + } + + +EXPORT_C void CMemSpyThread::SetPriorityL( TThreadPriority aPriority ) + { +#ifdef _DEBUG + RDebug::Printf( "CMemSpyThread::SetPriorityL() - START - aPriority: %d, orig pri: %d", aPriority, iPriority ); +#endif + CMemSpyEngine& engine = iProcess->Engine(); + RMemSpyDriverClient& driver = engine.Driver(); + // + const TInt err = driver.SetPriority( Id(), aPriority ); +#ifdef _DEBUG + TInt newPri = -1; + RThread thread; + if ( driver.OpenThread( iId, thread ) == KErrNone ) + { + newPri = thread.Priority(); + thread.Close(); + } + RDebug::Printf( "CMemSpyThread::SetPriorityL() - err: %d, newPri: %d", err, newPri ); +#endif + + User::LeaveIfError( err ); + RefreshL(); +#ifdef _DEBUG + RDebug::Printf( "CMemSpyThread::SetPriorityL() - END" ); +#endif + } + + +void CMemSpyThread::SetDeadL() + { + RefreshL(); + } + + +void CMemSpyThread::SetDeadL( const RThread& aThread ) + { + RefreshL( aThread ); + } + + +void CMemSpyThread::FullName( TDes& aName ) const + { + iProcess->FullName( aName ); + aName.Append( KMemSpyThreadDoubleColon ); + aName.Append( Name() ); + } + + +EXPORT_C TBool CMemSpyThread::IsDead() const + { + const TBool isDead = ( iExitType != EExitPending ); + return isDead; + } + + +void CMemSpyThread::RefreshL() + { + CMemSpyEngine& engine = iProcess->Engine(); + RMemSpyDriverClient& driver = engine.Driver(); + + // Try to open thread. We use the device driver since + // it doesn't check (i.e. it bypasses) some of the conditions which the + // default RThread::Open() implementation enforces... + // + // Deliberately ignore error. The other overload of RefreshL will + // cope with the failure. + RThread thread; + driver.OpenThread( iId, thread ); + CleanupClosePushL( thread ); + + // Call refresh with thread to perform actual heavy lifting... + RefreshL( thread ); + + // Clean up. This thread handle might actually not even be open, but that's okay... + CleanupStack::PopAndDestroy( &thread ); + } + + +void CMemSpyThread::RefreshL( const RThread& aThread ) + { + const TBool handleValid = aThread.Handle() != KNullHandle; + if ( handleValid ) + { + // Annoyingly, we request the entire thread info structure just to get the thread flags... + iFlags = 0; + const User::TCritical critType = User::Critical( aThread ); + if ( critType == User::ESystemPermanent ) + { + iFlags |= KThreadFlagSystemPermanent; + } + else if ( critType == User::ESystemCritical ) + { + iFlags |= KThreadFlagSystemCritical; + } + +#ifdef _DEBUG + TMemSpyDriverThreadInfo threadInfo; + User::LeaveIfError( iProcess->Engine().Driver().GetThreadInfo( iId, threadInfo ) ); + RDebug::Print( _L("CMemSpyThread::RefreshL() - old user pri: %d, curr user pri: %d, curr kernel pri: %d, iFlags: %d, name: %S"), iPriority, aThread.Priority(), threadInfo.iThreadPriority, iFlags, &threadInfo.iFullName ); +#endif + } + + // Get exit info + iExitType = handleValid ? aThread.ExitType() : EExitKill; + iPriority = handleValid ? aThread.Priority() : EPriorityNormal; + + // If the thread is dead then we may not be able to get some attributes + // (it depends on whether the thread handle is valid anymore). + iExitReason = 0; + iExitCategory.Zero(); + + if ( IsDead() ) + { + if ( handleValid ) + { + iExitReason = aThread.ExitReason(); + iExitCategory = aThread.ExitCategory(); + } + else + { + iExitCategory = KMemSpyUnknownExitCategory; + } + } + else + { + } + + // Get raw thread name + HBufC* rawThreadName = GetThreadNameLC( aThread ); + + // Full name is enough for the thread name as well as the extra info + // we show + TFullName name; + + // Build S60 listbox formatted name + _LIT( KMemSpyThreadNameFormatSpecBasicName, " \t%S\t\t" ); + name.Format( KMemSpyThreadNameFormatSpecBasicName, rawThreadName ); + CleanupStack::PopAndDestroy( rawThreadName ); + + // If the thread is dead show exit info + if ( IsDead() ) + { + AppendExitInfo( name, iExitType, iExitReason, iExitCategory ); + } + else + { + // Otherwise, show priority + AppendPriority( name, iPriority ); + } + + // Save new fully formatted name + HBufC* newName = name.AllocL(); + delete iName; + iName = newName; + } + + +HBufC* CMemSpyThread::GetThreadNameLC( const RThread& aThreadOrNull ) const + { + TName threadName; + // + const TBool handleValid = aThreadOrNull.Handle() != KNullHandle; + // + if ( handleValid ) + { + // Easy case - we have a valid thread handle. + threadName.Append( aThreadOrNull.Name() ); + } + else + { + // Since we don't have the possibility to enquire after the thread's name + // we'll assume that it used to be alive and therefore at some point we did + // manage to grep it's name... + if ( iName ) + { + const TPtrC pOriginalName( Name() ); + threadName.Append( pOriginalName ); + } + else + { + // Don't have a thread handle, don't have any possibility to get the + // name from a prior cached version. Must use "unknown" + threadName.Append( KMemSpyUnknownThreadName ); + } + } + // + HBufC* ret = threadName.AllocLC(); + return ret; + } + + +