commands/leak/leak.cpp
author Tom Sutcliffe <thomas.sutcliffe@accenture.com>
Sun, 17 Oct 2010 18:43:12 +0100
changeset 69 849a0b46c767
parent 31 d0e1c40de386
permissions -rw-r--r--
Fixed lots of issues with installing a low-caps version of fshell from SIS file. * Fixed issue in CCommandFactory whereby some APIs like GetCommandInfoL could trigger allocations on the wrong heap or signals to the wrong thread. The symptoms were often seen as a crash in the which_00 thread when running ciftest. * Lots of build fixes for when FSHELL_PROTECTED_UIDS isn't defined and when all capabilities aren't available. * Added new platform.mmh macro FSHELL_OPEN_SIGNED. * Open signing of fshell SIS files is now supported for production S60 handsets. Build fshell with the FSHELL_OPEN_SIGNED macro defined (and without defining FSHELL_CAP_ALL or FSHELL_PROTECTED_UIDS) in your platform.mmh and submit \epoc32\fshell\fshell.unsigned.sis to https://www.symbiansigned.com/app/page/public/openSignedOnline.do . The following commands are not available when using Open Signing due to Platform Security restrictions: fdb; kerninfo; chunkinfo; svrinfo; objinfo; sudo; fsck; localdrive; ramdefrag; readmem; reboot; setcritical; setpriority. Others such as chkdeps, e32header, ps, and fshell itself will run but in a restricted capacity (for example, fshell will no longer allow you to modify files in the \sys\bin directory). * Removed commands objinfo, svrinfo, chunkinfo, readmem, fsck completely when memory access isn't present - previously they would still appear in the help but would give an error if you tried to run them.

// leak.cpp
// 
// Copyright (c) 2007 - 2010 Accenture. All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the "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:
// Accenture - Initial contribution
//

#include "leak.h"
#include <fshell/common.mmh>
#ifdef FSHELL_QR3_SUPPORT_LOGGINGALLOCATOR
#include <fshell/loggingallocator.h>
#endif

const TInt KMinChunkSize = 4 * 1024;
const TInt KMaxChunkSize = 512 * 1024 * 1024;

CCommandBase* CCmdLeak::NewLC()
	{
	CCmdLeak* self = new(ELeave) CCmdLeak();
	CleanupStack::PushL(self);
	self->BaseConstructL();
	return self;
	}

CCmdLeak::~CCmdLeak()
	{
#ifdef FSHELL_QR3_SUPPORT_LOGGINGALLOCATOR
	if (iLoggingAllocator)
		{
		// Hmm how do I clean up a logging allocator created with RLoggingAllocator::New()?
		}
#endif
	iChunk.Close();
	if (iChunkHeap)
		{
		iChunkHeap->Reset();
		iChunkHeap->Close();
		}
	}

CCmdLeak::CCmdLeak()
	{
	}

const TDesC& CCmdLeak::Name() const
	{
	_LIT(KName, "leak");
	return KName;
	}

void CCmdLeak::DoRunL()
	{
	if ((iAmount < 0) || (iIncrementAmount < 0))
		{
		User::Leave(KErrArgument);
		}

	if (iArguments.IsPresent(0))
		{
		if (iIncrementAmount == 0)
			{
			iIncrementAmount = iAmount;
			}
		}
	else
		{
		iAmount = KMaxTInt;
		if (iIncrementAmount == 0)
			{
			iIncrementAmount = KMinChunkSize;
			}
		}

	if (iUseLoggingAllocator) iUseHeap = ETrue; // Using the logging allocator implies the --heap option

	if (iUseHeap)
		{
		iChunkHeap = UserHeap::ChunkHeap(NULL, KMinChunkSize, 256*1024*1024);
		if (!iChunkHeap) LeaveIfErr(KErrNoMemory, _L("Couldn't create chunk heap"));
		iAllocatorToUse = iChunkHeap;

#ifdef FSHELL_QR3_SUPPORT_LOGGINGALLOCATOR
		if (iUseLoggingAllocator)
			{
			LeaveIfErr(RLoggingAllocator::New(0, iChunkHeap, iLoggingAllocator), _L("Couldn't create logging allocator"));
			iAllocatorToUse = iLoggingAllocator;
			}
#endif
		}
	else
		{
		if (iIncrementAmount & 4095) LeaveIfErr(KErrArgument, _L("increment-amount must be a multiple of 4096"));
		TInt err = iChunk.CreateLocal(KMinChunkSize, KMaxChunkSize);
		LeaveIfErr(err, _L("Failed to create local chunk"));
		}

	RIoConsoleWriteHandle stdout = Stdout();
	stdout.SetCursorHeight(0);
	TInt err = KErrNone;
	do
		{
		err = LeakStep(Min(iIncrementAmount, iAmount - iCurrentLeak));
		if (iVerbose)
			{
			Write(_L("\r"));
			stdout.ClearToEndOfLine();
			Printf(_L("Allocated %d: %d"), iCurrentLeak, err);
			}
		if (err && iRetry && iIncrementAmount > 4)
			{
			// Keep going with a smaller increment
			err = KErrNone;
			iIncrementAmount /= 2;
			continue;
			}

		if (iRate > 0)
			{
			User::After(iRate * 1000);
			}
		}
		while ((err == KErrNone) && (iCurrentLeak < iAmount));

	if (err == KErrNoMemory)
		{
		Printf(_L("Out of memory. "));
		}
	else if (err)
		{
		Printf(_L("Error: %d. "), err);
		}

	Printf(_L("\r\nLeaked %d bytes. Press any key to exit (and free the memory).\r\n"), iCurrentLeak);

	RIoConsoleReadHandle stdin = Stdin();
	stdin.ReadKey();
	}

void CCmdLeak::OptionsL(RCommandOptionList& aOptions)
	{
	_LIT(KOptVerbose, "verbose");
	aOptions.AppendBoolL(iVerbose, KOptVerbose);

	_LIT(KOptIncrementAmount, "increment-amount");
	aOptions.AppendIntL(iIncrementAmount, KOptIncrementAmount);

	_LIT(KOptRate, "rate");
	aOptions.AppendUintL(iRate, KOptRate);

	_LIT(KOptUseHeap, "heap");
	aOptions.AppendBoolL(iUseHeap, KOptUseHeap);

	_LIT(KOptRetry, "retry");
	aOptions.AppendBoolL(iRetry, KOptRetry);

#ifdef FSHELL_QR3_SUPPORT_LOGGINGALLOCATOR
	_LIT(KOptUseLoggingAllocator, "logging-allocator");
	aOptions.AppendBoolL(iUseLoggingAllocator, KOptUseLoggingAllocator);
#endif
	}

void CCmdLeak::ArgumentsL(RCommandArgumentList& aArguments)
	{
	_LIT(KArgAmount, "amount");
	aArguments.AppendIntL(iAmount, KArgAmount);
	}


#ifdef EXE_BUILD
EXE_BOILER_PLATE(CCmdLeak)
#endif

TInt CCmdLeak::LeakStep(TInt aAmount)
	{
	TInt err = KErrNone;
	if (iAllocatorToUse)
		{
		TAny* cell = iAllocatorToUse->Alloc(aAmount);
		if (!cell) err = KErrNoMemory;
		}
	else
		{
		if (aAmount < 4096) err = KErrNoMemory; // implies we're retrying - unlike the others that keep retrying down to 4 bytes, we have to stop at page granularity
		else err = iChunk.Adjust(iCurrentLeak + aAmount);
		}

	if (!err) iCurrentLeak += aAmount;
	return err;
	}