libraries/qr3/inc/LoggingAllocator.h
author Tom Sutcliffe <thomas.sutcliffe@accenture.com>
Thu, 26 Aug 2010 00:49:35 +0100
changeset 45 534b01198c2d
parent 0 7f656887cf89
permissions -rw-r--r--
Added ENotifyKeypresses and ECaptureCtrlC flags to CCommandBase. Commands can now get keypresses and handle ctrl-C via callbacks instead of having to implement custom active objects. As part of this extended the CCommandBase extension interface to MCommandExtensionsV2 for the new virtual functions KeyPressed(TUint aKeyCode, TUint aModifiers) and CtrlCPressed(). sudo now cleans up correctly by using ECaptureCtrlC.

// LoggingAllocator.h
// 
// Copyright (c) 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
//
#ifndef LOGGING_ALLOCATOR_H
#define LOGGING_ALLOCATOR_H

#include <e32cmn.h>
#include <fshell/clogger.h>
#include <fshell/heaputils.h>
using LtkUtils::RAllocatorHelper;

NONSHARABLE_CLASS(RLoggingAllocator) : public RAllocator
	{
public:
	IMPORT_C static TInt Install();
	IMPORT_C static TInt Install(TUint aFlags);
	IMPORT_C static TInt Uninstall();

	// These don't require you to actually link against RLoggingAllocator
	inline static TInt Install_WeakLink(TUint aFlags=0);
	inline static TInt Uninstall_WeakLink();

	// Doesn't require the allocator to be installed, just dumps a stacktrace frame for the given cell
	static IMPORT_C void StaticTraceAlloc(RAllocator* aAllocator, TAny* aCellPtr, TInt aRequestedSize);
	static IMPORT_C void StaticTraceFree(RAllocator* aAllocator, TAny* aCellPtr);

	// Create a new logging allocator without changing the current User::Allocator
	IMPORT_C static TInt New(TUint aFlags, RAllocator* aOrigAllocator, RLoggingAllocator*& aResult);

	enum TFlags
		{
		EScribbleFrees = 1,
		EDeferFree = 2,
		EDeferFreeAndCheckScribbles = EDeferFree | EScribbleFrees,
		EOldFormatLogging = 4, // Use Symbian-defined BTrace::EAlloc and BTrace::ETest1 rather than the new range atrace defines extending THeap
		};
	
	static const TInt KTempDisableLogging = 0x10286F5E;

	static TAny* DisableLogging()
		{
		TAny* result = NULL;
		User::Allocator().DebugFunction(KTempDisableLogging, &result);
		return result;
		}

	static void RestoreLogging(TAny* aAllocator)
		{
		if (aAllocator)
			{
			User::SwitchAllocator((RAllocator*)aAllocator);
			}
		}

protected:
	TAny* Alloc(TInt aSize);
	void Free(TAny* aPtr);
	TAny* ReAlloc(TAny* aPtr, TInt aSize, TInt aMode=0);
	TInt AllocLen(const TAny* aCell) const;
	TInt Compress();
	void Reset();
	TInt AllocSize(TInt& aTotalAllocSize) const;
	TInt Available(TInt& aBiggestBlock) const;
	TInt DebugFunction(TInt aFunc, TAny* a1=NULL, TAny* a2=NULL);

private:
	RLoggingAllocator(TUint aFlags);
	static TBool HeavenWalk(LtkUtils::RAllocatorHelper& aHelper, TAny* aPtr, RAllocatorHelper::TCellType aType, TLinAddr aCell, TInt aLen);

	static TBool TraceExistingAllocs(TAny* aContext, RAllocatorHelper::TCellType aType, TLinAddr aCell, TInt aLen);
	inline void TraceAlloc(RAllocator* aAllocator, TAny* aCellPtr, TInt aRequestedSize);
	inline void TraceFree(RAllocator* aAllocator, TAny* aCellPtr, TBool aCellIsAlreadyFreed=EFalse);
	inline void TraceRealloc(TAny *aNewPtr, TAny* aOldPtr, TInt aNewRequestedSize);
	void DoTraceAllocEvent(RAllocator* aAllocator, TAny* aCellPtr, TInt aEvent, TInt aRequestedSize, TAny* aOldPtr=NULL); // RequestedSize only relevant for aEvent==EHeapAlloc or EHeapReAlloc, aOldPtr only for realloc
	void CheckDeferredFrees();
	void Destroy();
	virtual ~RLoggingAllocator(); // Made this virtual to shut up GCCE (even GCC 4 complains about this)

public:
	RAllocator* iA; // The original allocator

private:
	TInt iBreakOnAllocCount; // Useful when running in a debugger
#ifndef __KERNEL_MODE__
	RLibrary iLib; // Needed to keep the plugin DLL loaded past the time when ecom is cleaned up
#endif
	TUint iFlags;
	RFastLock iLock; // For locking around iFlags and iDeferredFrees
	struct SDeferredFreeCell { void* iPtr; TInt iLen; };
	RArray<SDeferredFreeCell> iDeferredFrees;
	TUint iPid;
	RAllocatorHelper iHelper;
	};

inline TInt RLoggingAllocator::Install_WeakLink(TUint aFlags)
	{
	const TInt KInstallOrdinal = 5; // Happily this is the same on bwins and eabi (and probably bmarm if I get round to rebuilding it)
	RLibrary lib;
	TInt err = lib.Load(_L("loggingallocator"));
	if (err) return err;

	typedef TInt (*InstallFn)(TUint);
	InstallFn InstallLoggingAllocator = (InstallFn)lib.Lookup(KInstallOrdinal);
	if (!InstallLoggingAllocator) err = KErrBadLibraryEntryPoint;

	if (!err) err = InstallLoggingAllocator(aFlags);
	lib.Close(); // If the allocator installed itself, it makes sure to keep itself loaded via an RLibrary of its own
	return err;
	}

inline TInt RLoggingAllocator::Uninstall_WeakLink()
	{
	const TInt KUninstallOrdinal = 2; // Happily this is the same on bwins and eabi (and probably bmarm if I get round to rebuilding it)
	RLibrary lib;
	TInt err = lib.Load(_L("loggingallocator"));
	if (err) return err;

	typedef TInt (*UninstallFn)();
	UninstallFn UninstallLoggingAllocator = (UninstallFn)lib.Lookup(KUninstallOrdinal);
	if (!UninstallLoggingAllocator) err = KErrBadLibraryEntryPoint;

	if (!err) err = UninstallLoggingAllocator();
	lib.Close(); // If the allocator installed itself, it makes sure to keep itself loaded via an RLibrary of its own
	return err;
	}

#endif