diff -r 185201be11b0 -r 516af714ebb4 perfsrv/memspy/Driver/Kernel/Source/MemSpyDriverSuspensionManager.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/perfsrv/memspy/Driver/Kernel/Source/MemSpyDriverSuspensionManager.cpp Fri Sep 17 08:38:31 2010 +0300 @@ -0,0 +1,508 @@ +/* +* 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 "MemSpyDriverSuspensionManager.h" + +// System includes +#include + +// Shared includes +#include "MemSpyDriverUtils.h" +#include "MemSpyDriverDevice.h" +#include "MemSpyDriverOSAdaption.h" + +// Constants +const TInt KSuspendResumeCount = 1; + + + +DMemSpySuspensionManager::DMemSpySuspensionManager( DMemSpyDriverDevice& aDevice ) +: iDevice( aDevice ) + { + } + + +DMemSpySuspensionManager::~DMemSpySuspensionManager() + { + TRACE( Kern::Printf("DMemSpySuspensionManager::~DMemSpySuspensionManager() - START")); + + if ( iAlreadySuspended ) + { + TRACE( Kern::Printf("DMemSpySuspensionManager::~DMemSpySuspensionManager() - resuming threads in process with id: %d", iSuspendedProcessId )); + DoResumeAllThreadsInProcess( iSuspendedProcessId ); + } + if ( iTempObj != NULL ) + { + Kern::SafeClose( iTempObj, NULL ); + } + + TRACE( Kern::Printf("DMemSpySuspensionManager::~DMemSpySuspensionManager() - END")); + } + + +TInt DMemSpySuspensionManager::Construct() + { + return KErrNone; + } + + + + + + + + + + + +TBool DMemSpySuspensionManager::IsSuspended( TUint aPid ) const + { + TBool ret = iAlreadySuspended; + // + if ( ret ) + { + ret = ( aPid == iSuspendedProcessId ); + } + // + TRACE( Kern::Printf("DMemSpySuspensionManager::IsSuspended() - iAlreadySuspended: %d, iSuspendedProcessId: %d, aPid: %d, ret: %d", iAlreadySuspended, iSuspendedProcessId, aPid, ret ) ); + return ret; + } + + +TBool DMemSpySuspensionManager::IsSuspended( DThread& aThread ) const + { + TBool ret = EFalse; + // + const TUint tid = iDevice.OSAdaption().DThread().GetId( aThread ); + DProcess* process = iDevice.OSAdaption().DThread().GetOwningProcess( aThread ); + TRACE( Kern::Printf("DMemSpySuspensionManager::IsSuspended() - START - iSuspendedProcessId: %d, aThread: (%d) %O, process: 0x%08x", iSuspendedProcessId, tid, &aThread, process ) ); + // + if ( process ) + { + ret = IsSuspended( *process ); + } + // + TRACE( Kern::Printf("DMemSpySuspensionManager::IsSuspended() - END - ret: %d", ret ) ); + return ret; + } + + +TBool DMemSpySuspensionManager::IsSuspended( DProcess& aProcess ) const + { + const TUint pid = iDevice.OSAdaption().DProcess().GetId( aProcess ); + TRACE( Kern::Printf("DMemSpySuspensionManager::IsSuspended() - START - iSuspendedProcessId: %d, aProcess: (%d / %d) %O", iSuspendedProcessId, pid, aProcess.iId, &aProcess ) ); + // + const TBool ret = IsSuspended( pid ); + // + TRACE( Kern::Printf("DMemSpySuspensionManager::IsSuspended() - END - ret: %d", ret ) ); + return ret; + } + + + + + + + + + + + + + + + + +TInt DMemSpySuspensionManager::SuspendAllThreadsInProcess( TUint aPid, DThread& aClientThread ) + { + // Suspend all threads in the process + TRACE( Kern::Printf("DMemSpySuspensionManager::SuspendAllThreadsInProcess() - START - id: %8d, iSuspendedProcessId: %8d, iAlreadySuspended: %d", aPid, iSuspendedProcessId, iAlreadySuspended )); + if ( iAlreadySuspended && aPid != iSuspendedProcessId ) + { + Kern::Printf("DMemSpySuspensionManager::SuspendAllThreadsInProcess() - END - trying to suspend multiple processes!"); + MemSpyDriverUtils::PanicThread( aClientThread, EPanicAttemptingToSuspendMultipleProcesses ); + return KErrNone; + } + else if ( IsProcessTheClientThread( aPid, aClientThread ) ) + { + Kern::Printf("DMemSpySuspensionManager::SuspendAllThreadsInProcess() - END - trying to suspend client thread! - request ignored"); + return KErrLocked; + } + + TInt r = KErrNone; + TRACE( Kern::Printf("DMemSpySuspensionManager::SuspendAllThreadsInProcess - iAlreadySuspended: %d", iAlreadySuspended)); + if ( !iAlreadySuspended ) + { + r = DoSuspendAllThreadsInProcess( aPid, &aClientThread ); + if (r != KErrNone) + { + TRACE( Kern::Printf("DMemSpySuspensionManager::SuspendAllThreadsInProcess() - END - process not found") ); + return r; + } + + // To ensure we clean up in case of user-side problem... + iSuspendedProcessId = aPid; + iAlreadySuspended = ETrue; + iSuspendCount = 1; + } + else + { + // Just increment the count + ++iSuspendCount; + } + + TRACE( Kern::Printf("DMemSpySuspensionManager::SuspendAllThreadsInProcess() - END - iSuspendCount: %d, iSuspendedProcessId: %d", iSuspendCount, iSuspendedProcessId )); + return iSuspendCount; + } + + +TInt DMemSpySuspensionManager::ResumeAllThreadsInProcess( TUint aPid, DThread& aClientThread ) + { + TRACE( Kern::Printf("DMemSpySuspensionManager::ResumeAllThreadsInProcess() - START - id: %8d, iSuspendedProcessId: %8d, iAlreadySuspended: %d", aPid, iSuspendedProcessId, iAlreadySuspended)); + if ( !iAlreadySuspended ) + { + // Nothing suspended - don't panic + TRACE( Kern::Printf("DMemSpySuspensionManager::ResumeAllThreadsInProcess() - END - nothing suspended, ignoring client request")); + return KErrNone; + } + else if ( iAlreadySuspended && aPid != iSuspendedProcessId ) + { + Kern::Printf("DMemSpySuspensionManager::ResumeAllThreadsInProcess() - END - trying to resume incorrect process!"); + MemSpyDriverUtils::PanicThread( aClientThread, EPanicAttemptingToResumeNonSuspendedProcess ); + return KErrNone; + } + else if ( IsProcessTheClientThread( aPid, aClientThread ) ) + { + Kern::Printf("DMemSpySuspensionManager::ResumeAllThreadsInProcess() - END - trying to resume client thread! - request ignored"); + return KErrLocked; + } + + TRACE( Kern::Printf("DMemSpySuspensionManager::ResumeAllThreadsInProcess")); + + TInt r = KErrNone; + if ( --iSuspendCount <= 0 ) + { + r = DoResumeAllThreadsInProcess( aPid, &aClientThread ); + if (r != KErrNone) + { + Kern::Printf("DMemSpySuspensionManager::ResumeAllThreadsInProcess() - END - process not found"); + return r; + } + + // No longer need to clean up + iAlreadySuspended = EFalse; + iSuspendedProcessId = 0; + iSuspendCount = 0; + } + else + { + // No action needed - we've already decremented the counter + } + + TRACE( Kern::Printf("DMemSpySuspensionManager::ResumeAllThreadsInProcess() - END - iSuspendCount: %d", iSuspendCount)); + return iSuspendCount; + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + +TInt DMemSpySuspensionManager::DoSuspendAllThreadsInProcess( TUint aPid, DThread* /*aClientThread*/ ) + { + TRACE( Kern::Printf("DMemSpySuspensionManager::DoSuspendAllThreadsInProcess() - START - aPid: %d", aPid)); + TInt r = OpenTempObject( aPid, EProcess ); + if (r == KErrNone) + { + DProcess* process = (DProcess*) iTempObj; + TFullName processName; + process->FullName( processName ); + processName.Append('*'); + + DObjectCon* container = Kern::Containers()[EThread]; + NKern::ThreadEnterCS(); + container->Wait(); + // + TFullName result; +#ifdef MCL_FIND_HANDLES + TFindHandle findHandle; +#else + TInt findHandle = 0; +#endif + r = container->FindByFullName( findHandle, processName, result ); + while( r == KErrNone ) + { + DThread* thread = (DThread*) container->At( findHandle ); + if ( thread ) + { + const TUint tid = iDevice.OSAdaption().DThread().GetId( *thread ); + TRACE( Kern::Printf("DMemSpySuspensionManager::DoSuspendAllThreadsInProcess - suspending thread: (%d), %O", tid, thread )); + // + Kern::ThreadSuspend( *thread, KSuspendResumeCount ); + } + // + r = container->FindByFullName( findHandle, processName, result ); + } + // + container->Signal(); + NKern::ThreadLeaveCS(); + + CloseTempObject(); + r = KErrNone; + } + + TRACE( Kern::Printf("DMemSpySuspensionManager::DoSuspendAllThreadsInProcess() - END - ret: %d", r)); + return r; + } + + +TInt DMemSpySuspensionManager::DoResumeAllThreadsInProcess( TUint aPid, DThread* aClientThread ) + { + TRACE( Kern::Printf("DMemSpySuspensionManager::DoResumeAllThreadsInProcess() - START - aPid: %d", aPid)); + TInt r = OpenTempObject( aPid, EProcess ); + if (r == KErrNone) + { + // Check that this process is suspended + DProcess* process = (DProcess*) iTempObj; + const TUint pid = iDevice.OSAdaption().DProcess().GetId( *process ); + if ( !aClientThread || ( aClientThread && CheckProcessSuspended( pid, *aClientThread ) ) ) + { + // Resume all threads in the process + TFullName processName; + process->FullName( processName ); + processName.Append('*'); + + DObjectCon* container = Kern::Containers()[EThread]; + NKern::ThreadEnterCS(); + container->Wait(); + // + TFullName result; + #ifdef MCL_FIND_HANDLES + TFindHandle findHandle; + #else + TInt findHandle = 0; + #endif + r = container->FindByFullName( findHandle, processName, result ); + while( r == KErrNone ) + { + DThread* thread = (DThread*) container->At( findHandle ); + TRACE( Kern::Printf("DMemSpySuspensionManager::DoResumeAllThreadsInProcess - resuming thread: %lS", &result)); + // + Kern::ThreadResume(*thread); + r = container->FindByFullName( findHandle, processName, result ); + } + // + container->Signal(); + NKern::ThreadLeaveCS(); + + r = KErrNone; + } + else + { + TRACE( Kern::Printf("DMemSpySuspensionManager::DoResumeAllThreadsInProcess - parent process not suspended => KErrAccessDenied")); + r = KErrAccessDenied; + } + + CloseTempObject(); + } + + TRACE( Kern::Printf("DMemSpySuspensionManager::DoResumeAllThreadsInProcess() - END - ret: %d", r)); + return r; + } + + + + + + + + + + + + + + + + + +TBool DMemSpySuspensionManager::IsProcessTheClientThread( TUint aPid, DThread& aClientThread ) const + { + TBool ret = EFalse; + DProcess& clientProcess = *iDevice.OSAdaption().DThread().GetOwningProcess( aClientThread ); + const TUint pid = iDevice.OSAdaption().DProcess().GetId( clientProcess ); + if ( pid == aPid ) + { + ret = ETrue; + } + // + return ret; + } + + +TBool DMemSpySuspensionManager::CheckProcessSuspended( TUint aExpectedPid, DThread& aClientThread ) const + { + TBool suspended = ETrue; + // + if ( !iAlreadySuspended ) + { + MemSpyDriverUtils::PanicThread( aClientThread, EPanicThreadsInProcessNotSuspended ); + } + else if ( aExpectedPid != iSuspendedProcessId ) + { + MemSpyDriverUtils::PanicThread( aClientThread, EPanicWrongProcessSuspended ); + } + // + return suspended; + } + + + + + + + + + + + + + + + + + + + +TInt DMemSpySuspensionManager::OpenTempObject(TUint aId, TObjectType aType) + { + __ASSERT_DEBUG( aType == EProcess || aType == EThread, MemSpyDriverUtils::Fault( __LINE__ ) ); + __ASSERT_DEBUG( !iTempObj, MemSpyDriverUtils::Fault( __LINE__ ) ); + + TRACE( Kern::Printf("DMemSpySuspensionManager::OpenTempObject() - START - aId: %d, aType: %d", aId, aType )); + DObjectCon* pC = Kern::Containers()[aType]; + NKern::ThreadEnterCS(); + pC->Wait(); + iTempObj = (aType == EProcess) ? (DObject*)Kern::ProcessFromId(aId) : (DObject*)Kern::ThreadFromId(aId); + TRACE( Kern::Printf("DMemSpySuspensionManager::OpenTempObject() - kernel obj from id returned: 0x%08x %O", iTempObj, iTempObj )); + // + TBool openedOkay = EFalse; + TInt r = KErrNone; + // + if ( iTempObj ) + { + r = iTempObj->Open(); + TRACE( Kern::Printf("DMemSpySuspensionManager::OpenTempObject() - open returned: %d", r )); + // + if ( r == KErrNone ) + { + openedOkay = ETrue; + if ( aType == EProcess ) + { + // Check the process is still alive + DProcess* process = (DProcess*) iTempObj; + const TExitType exitType = iDevice.OSAdaption().DProcess().GetExitType( *process ); + if ( exitType != EExitPending ) + { + r = KErrDied; + TRACE( Kern::Printf("DMemSpySuspensionManager::OpenTempObject() - PROCESS IS DEAD!" )); + } + } + else if (aType == EThread ) + { + // Check the thread is still alive + DThread* thread = (DThread*) iTempObj; + const TExitType exitType = iDevice.OSAdaption().DThread().GetExitType( *thread ); + if ( exitType != EExitPending ) + { + r = KErrDied; + TRACE( Kern::Printf("DMemSpySuspensionManager::OpenTempObject() - THREAD IS DEAD!" )); + } + } + } + + } + else if ( ! iTempObj ) + { + r = KErrNotFound; + TRACE( Kern::Printf("DMemSpySuspensionManager::OpenTempObject() - ENTITY NOT FOUND!" )); + } + // + pC->Signal(); + TRACE( Kern::Printf("DMemSpySuspensionManager::OpenTempObject() - signalled container..." )); + NKern::ThreadLeaveCS(); + TRACE( Kern::Printf("DMemSpySuspensionManager::OpenTempObject() - left CS..." )); + // + if ( r != KErrNone && iTempObj ) + { + TRACE( Kern::Printf("DMemSpySuspensionManager::OpenTempObject() - ERROR CASE - closing temp object (r: %d, openedOkay: %d)...", r, openedOkay )); + // + if ( openedOkay ) + { + CloseTempObject(); + } + else + { + NKern::SafeSwap( NULL, (TAny*&) iTempObj ); + } + // + TRACE( Kern::Printf("DMemSpySuspensionManager::OpenTempObject() - ERROR CASE - closed temp object" )); + } + // + TRACE( Kern::Printf("DMemSpySuspensionManager::OpenTempObject() - END - r: %d", r )); + return r; + } + + +void DMemSpySuspensionManager::CloseTempObject() + { + TRACE( Kern::Printf("DMemSpySuspensionManager::CloseTempObject() - START - iTempObj: 0x%08x %O", iTempObj, iTempObj )); + + __ASSERT_DEBUG( iTempObj, MemSpyDriverUtils::Fault( __LINE__ ) ); + if ( iTempObj ) + { + NKern::ThreadEnterCS(); + Kern::SafeClose( iTempObj, NULL ); + NKern::ThreadLeaveCS(); + } + + TRACE( Kern::Printf("DMemSpySuspensionManager::CloseTempObject() - END" )); + } + +