debugsrv/runmodedebug/tsrc/rm_debug/debug_targets/d_rmdebugthread2.cpp
author hgs
Fri, 08 Oct 2010 14:56:39 +0300
changeset 56 aa2539c91954
permissions -rw-r--r--
201041

// Copyright (c) 2006-2010 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:
// Implements a debug thread for testing.
// 
//

#include <e32base.h>
#include <e32base_private.h>
#include <e32cons.h>
#include <e32debug.h>
#include "d_rmdebugthread2.h"

#include "d_rmdebug_step_test.h"
#include "d_rmdebug_bkpt_test.h"
#include "d_demand_paging.h"

TBuf8<SYMBIAN_RMDBG_MEMORYSIZE> gMemoryAccessBytes;
IMPORT_C extern void RMDebug_BranchTst1();
IMPORT_C extern TInt RMDebugDemandPagingTest();

TInt TestData;
TTestFunction FunctionChooser;

const TInt 	KNumberOfTraceCalls = 50;

EXPORT_C TInt TestFunction()
	{
	// Set TestData to an arbitrary value that can be checked by a tester
	TestData = 0xffeeddcc;
	RMDebug_BranchTst1();
	
	// Code here may not be executed because tests can change the PC value
	// at any time, typically once the test passes
	return 0;
	}

/**
  Wrapper around RMDebugDemandPagingTest, need to pause for a short time to
  allow time in t_rmdebug.cpp to issue a User::WaitForRequest to catch the break point
  */
EXPORT_C void TestPagedCode()
	{
	User::After(100000);

	// call the function in paged code
	RMDebugDemandPagingTest();
	}

EXPORT_C void TestMultipleTraceCalls()
	{
	//arbitrary function to set a BP on
	RMDebug_BranchTst1();

	// The tester will change FunctionChooser once it gets what it needs out of the test
	for(TInt cnt = KNumberOfTraceCalls; cnt>0 && (FunctionChooser==EMultipleTraceCalls); cnt--)
		{
		RDebug::Printf("T");
		RDebug::Printf("R");
		RDebug::Printf("A");
		RDebug::Printf("C");
		RDebug::Printf("E");
		}
	
	//another arbitrary function to set a BP on
	RMDebug_StepTest_Non_PC_Modifying();
	}

CDebugServThread::~CDebugServThread()
    {
    }

CDebugServThread::CDebugServThread()
//
// Empty constructor
//
	{
	}


/**
 * Check that the RProperty argument does not change within the given amount of time.
 * If the property does change, the error KErrInUse is returned.
 * 
 */
EXPORT_C TInt TestRunCountSame( RProperty & aProperty, RTimer & aTimer, TTimeIntervalMicroSeconds32 aTimeOut )
    {
    TRequestStatus propertyStatus;
    TRequestStatus timerStatus;
    TInt propertyValueBefore = 0;
    TInt propertyValueAfter = 0;

    aProperty.Subscribe( propertyStatus );
    aProperty.Get( propertyValueBefore );
    aTimer.After( timerStatus, aTimeOut );

    User::WaitForRequest( propertyStatus, timerStatus );
    if (propertyStatus != KRequestPending)
        {
        RDebug::Printf(" CDebugServThread::TestRunCountSame: Property has been set. Returning KErrInUse");
        aTimer.Cancel();
        // Wait for the KErrCancel
        User::WaitForRequest( timerStatus );
        return KErrInUse;
        }

    aProperty.Cancel();
    //This will wait for the KErrCancel to be issued by the property.
    User::WaitForRequest( propertyStatus );
    
    aProperty.Get( propertyValueAfter );
    if( propertyValueAfter != propertyValueBefore )
        {
        RDebug::Printf(" CDebugServThread::TestRunCountSame: Change in property value. Returning KErrInUse");
        return KErrInUse;
        }
        
    return KErrNone;
    }


/**
 * Check that the RProperty argument changes within the given amount of time.
 * If the property does not change, the error KErrTimedOut is returned.
 * If the values before and after are the same, the error KErrNotReady is returned
 */
EXPORT_C TInt WaitForRunCountChange( RProperty & aProperty, RTimer & aTimer, TTimeIntervalMicroSeconds32 aTimeOut )
    {
    TRequestStatus propertyStatus;
    TRequestStatus timerStatus;
    TInt propertyValueBefore = 0;
    TInt propertyValueAfter = 0;
    
    aProperty.Get( propertyValueBefore );
    aProperty.Subscribe( propertyStatus );

    aTimer.After( timerStatus, aTimeOut );

    User::WaitForRequest( propertyStatus, timerStatus );
    if (timerStatus != KRequestPending)
        {
        RDebug::Printf(" CDebugServThread::WaitForRunCountChange: timeout. Returning KErrTimedOut");
        aProperty.Cancel();
        // Wait for the KErrCancel
        User::WaitForRequest( propertyStatus );
        return KErrTimedOut;
        }
    
    aTimer.Cancel();
    //This will wait for the KErrCancel to be issued by the timer.
    User::WaitForRequest( timerStatus );
    
    aProperty.Get( propertyValueAfter );
    if( propertyValueAfter == propertyValueBefore )
        {
        RDebug::Printf(" CDebugServThread::WaitForRunCountChange: No change in property value. Returning KErrNotReady");
        return KErrNotReady;
        }
        
    return KErrNone;
    }

GLDEF_C TInt CDebugServThread::ThreadFunction(TAny*)
//
// Generic thread function for testing
//
	{
	// set FunctionChooser to run the default function
	FunctionChooser = EDefaultFunction;

	CTrapCleanup* cleanup=CTrapCleanup::New();
	if (cleanup == NULL)
		{
		User::Leave(KErrNoMemory);
		}
    
	TInt err = RProperty::Define( RProcess().SecureId(), ERMDBGRunCountProperty, RProperty::EInt );
    if( (err != KErrAlreadyExists) && (err != KErrNone) )
        {
        RDebug::Printf("CDebugServThread::ThreadFunction - unable to create 'ERunCount' property. err:%d", err);
        }
    
	RThread::Rendezvous(KErrNone);

	TestData = 1;

	/* Beware of adding printf or other debug-generating events in this loop because
	* they interfere with the tests
	*/
	while(TestData != 0xFFFFFFFF)
		{
        //iRunCountPublish.Set( TestData );
        RProperty::Set( RProcess().SecureId(), ERMDBGRunCountProperty, TestData );
        
		switch(FunctionChooser)
			{
			case EDemandPagingFunction:
				TestPagedCode();
				break;
			case EDefaultFunction:
				// the default function is the stepping test functions
			case EStepFunction:
				{
				RMDebug_BranchTst1();

				// Single stepping test support code

				// ARM tests
				RMDebug_StepTest_Non_PC_Modifying();

				RMDebug_StepTest_Branch();

				RMDebug_StepTest_Branch_And_Link();

				RMDebug_StepTest_MOV_PC();

				RMDebug_StepTest_LDR_PC();
 
// thumb/interworking tests not supported on armv4
#ifdef __MARM_ARMV5__

				// Thumb tests
				RMDebug_StepTest_Thumb_Non_PC_Modifying();

				RMDebug_StepTest_Thumb_Branch();

				RMDebug_StepTest_Thumb_Branch_And_Link();

				RMDebug_StepTest_Thumb_Back_Branch_And_Link();

				// ARM <-> Thumb interworking tests
				RMDebug_StepTest_Interwork();

				RMDebug_StepTest_Thumb_AddPC();

#endif	// __MARM_ARMV5__
				
				// Single-stepping performance
				RMDebug_StepTest_Count();

				// multiple step test
				RMDebug_StepTest_ARM_Step_Multiple();

				// Breakpoints in loop test
				RMDebug_Bkpt_Test_Entry();

				TestData++;
				
				RDebug::Printf("** TestData=%d", TestData) ;

				// Wait 50mSecs. // (suspends this thread)
				User::After(50000);

				break;
				}
			case EMultipleTraceCalls:
				TestMultipleTraceCalls();
				break;
			default:
				//do nothing
				break;
			}
		}

	RProperty::Delete( RProcess().SecureId(), ERMDBGRunCountProperty );
	        
	delete cleanup;

	return (KErrNone);
	}

EXPORT_C TInt StartDebugThread(RThread& aDebugThread, const TDesC& aDebugThreadName)
//
// Starts a test thread
//
{
	TInt res=KErrNone;

	// Create the thread
	res = aDebugThread.Create(	aDebugThreadName,
								CDebugServThread::ThreadFunction,
								KDefaultStackSize,
								KDebugThreadDefaultHeapSize,
								KDebugThreadDefaultHeapSize,
								NULL
								);

	// Check that the creation worked
	if (res == KErrNone)
		{
		TRequestStatus rendezvousStatus;

		aDebugThread.SetPriority(EPriorityNormal);
		// Make a request for a rendezvous
		aDebugThread.Rendezvous(rendezvousStatus);
		// Set the thread as ready for execution
		aDebugThread.Resume();
		// Wait for the resumption
		User::WaitForRequest(rendezvousStatus);
		}                                 
	else
		{
		// Close the handle.
		aDebugThread.Close();
		}
	        
	return res;
	}