kerneltest/e32test/debug/d_traceredirect.cpp
changeset 0 a41df078684a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32test/debug/d_traceredirect.cpp	Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,252 @@
+// Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "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:
+// e32test\debug\d_traceredirect.cpp
+// Trace redirection LDD
+// This device driver captures RDebug::Prints from user side code using the
+// debug event handler.
+// The text can be retrieved with the RTraceRedirect::NextTrace() function 
+// TODO: Modify this LDD to use asynchronous retrieval.
+// 
+//
+
+#include <kernel/kernel.h>
+#include <kernel/kern_priv.h>
+#include "d_traceredirect.h"
+
+_LIT(KLddName,"D_TRACEREDIRECT");
+
+const TInt KMajorVersionNumber = 0;
+const TInt KMinorVersionNumber = 1;
+const TInt KBuildVersionNumber = 1;
+
+const TInt KMaxTraceEventLength=100;
+const TInt KTraceBufferSize=256;
+const TInt KTraceBufferSizeMask=0xff;
+
+
+class TTraceEvent
+	{
+public:
+	TInt iLength;
+	TUint16 iText[KMaxTraceEventLength];
+	};
+
+class DTraceRedirect;
+
+class DTraceEventHandler : public DKernelEventHandler
+	{
+public:
+	DTraceEventHandler()
+		: DKernelEventHandler(HandleEvent, this) {}
+	TInt Create(DLogicalDevice* aDevice);
+	~DTraceEventHandler();
+	TInt GetNextEvent(TAny *outdes);
+private:
+	static TUint HandleEvent(TKernelEvent aEvent, TAny* a1, TAny* a2, TAny* aThis);
+	void HandleUserTrace(TText* aStr, TInt aLen);
+public:
+	DTraceRedirect *iChannel;
+	TTraceEvent *iTraceBuffer;
+	TInt iFront;
+	TInt iBack;
+	DMutex* iLock; // serialise calls to handler
+	DLogicalDevice* iDevice;	// open reference to LDD for avoiding lifetime issues
+	};
+
+class DTraceRedirectFactory : public DLogicalDevice
+	{
+public:
+	DTraceRedirectFactory();
+	virtual TInt Install();
+	virtual void GetCaps(TDes8& aDes) const;
+	virtual TInt Create(DLogicalChannelBase*& aChannel);
+	};
+
+class DTraceRedirect : public DLogicalChannelBase
+	{
+public:
+	virtual ~DTraceRedirect();
+protected:
+	virtual TInt DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer);
+	virtual TInt Request(TInt aFunction, TAny* a1, TAny* a2);
+	TInt NextTrace(TAny *outdes);
+public:
+	DTraceEventHandler *iEventHandler;
+	};
+
+
+
+DECLARE_STANDARD_LDD()
+	{
+	return new DTraceRedirectFactory;
+	}
+
+//
+// DTraceRedirectFactory
+//
+
+DTraceRedirectFactory::DTraceRedirectFactory()
+	{
+	iVersion=TVersion(KMajorVersionNumber,KMinorVersionNumber,KBuildVersionNumber);
+	}
+
+TInt DTraceRedirectFactory::Create(DLogicalChannelBase*& aChannel)
+/**
+ Create a new DSchedhookTest on this logical device
+*/
+	{
+	aChannel=new DTraceRedirect;
+	return aChannel ? KErrNone : KErrNoMemory;
+	}
+
+TInt DTraceRedirectFactory::Install()
+/**
+ Install the LDD - overriding pure virtual
+*/
+	{
+	return SetName(&KLddName);
+	}
+
+void DTraceRedirectFactory::GetCaps(TDes8& aDes) const
+/**
+ Get capabilities - overriding pure virtual
+*/
+	{
+	TCapsTestV01 b;
+	b.iVersion=TVersion(KMajorVersionNumber,KMinorVersionNumber,KBuildVersionNumber);
+    Kern::InfoCopy(aDes,(TUint8*)&b,sizeof(b));
+	}
+
+
+//
+// DSchedhookTest
+//
+
+TInt DTraceRedirect::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& aVer)
+/**
+ Create channel
+*/
+	{
+	if (!Kern::QueryVersionSupported(TVersion(KMajorVersionNumber,KMinorVersionNumber,KBuildVersionNumber),aVer))
+		return KErrNotSupported;
+
+	iEventHandler=new DTraceEventHandler;
+	if (iEventHandler == NULL)
+		return KErrNoMemory;
+	return iEventHandler->Create(iDevice);
+	}
+
+DTraceRedirect::~DTraceRedirect()
+	{
+	iEventHandler->Close();
+	}
+
+TInt DTraceEventHandler::Create(DLogicalDevice* aDevice)
+	{
+	TInt r;
+	r = aDevice->Open();
+	if (r != KErrNone)
+		return r;
+	iDevice = aDevice;
+	iFront=0;
+	iBack=0;
+	iTraceBuffer=new TTraceEvent[KTraceBufferSize];
+	if (iTraceBuffer == NULL)
+		return KErrNoMemory;
+	_LIT(KDataMutexName, "EventHandlerMutex");
+	r = Kern::MutexCreate(iLock, KDataMutexName, KMutexOrdDebug);
+	if (r != KErrNone)
+		return r;
+	return Add();
+	}
+
+DTraceEventHandler::~DTraceEventHandler()
+	{
+	if (iLock)
+		iLock->Close(NULL);
+	delete [] iTraceBuffer;
+	if (iDevice)
+		iDevice->Close(NULL);
+	}
+
+TUint DTraceEventHandler::HandleEvent(TKernelEvent aEvent, TAny* a1, TAny* a2, TAny* aThis)
+	{
+	if (aEvent==EEventUserTrace)
+		{
+		((DTraceEventHandler*)aThis)->HandleUserTrace((TText*)a1, (TInt)a2);
+		return ETraceHandled;
+		}
+	return ERunNext;
+	}
+
+// called in CS
+void DTraceEventHandler::HandleUserTrace(TText* aStr, TInt aLen)
+	{
+	Kern::MutexWait(*iLock);
+	TInt frontplus1=(iFront+1)&KTraceBufferSizeMask;
+	if (frontplus1!=iBack)  // check overflow
+		{
+		TTraceEvent *e=&iTraceBuffer[iFront];
+		XTRAPD(r, XT_DEFAULT, kumemget(e->iText, aStr, aLen*2));
+		if (r == KErrNone)
+			e->iLength=aLen;
+		else
+			e->iLength = -1; // an error will be reported in GetNextEvent()
+		iFront=frontplus1;
+		}
+	Kern::MutexSignal(*iLock);
+	}
+
+TInt DTraceEventHandler::GetNextEvent(TAny *outdes)
+	{
+
+	if (iBack==iFront)
+		{ // buffer empty
+		return KErrNone;
+		}
+	TTraceEvent *e=&iTraceBuffer[iBack];
+	if (e->iLength == -1)
+		return KErrCorrupt; // earlier error when copying trace data from userland
+	TPtr ptr((TUint8*)e->iText, e->iLength, e->iLength);
+	TInt r=KErrNone;
+	Kern::KUDesPut(*(TDes *)outdes, ptr);
+	iBack=(iBack+1)&KTraceBufferSizeMask;
+	return r;
+	}
+
+TInt DTraceRedirect::NextTrace(TAny *outdes)
+	{
+
+	TInt r=iEventHandler->GetNextEvent(outdes);
+	return r;
+	}
+
+TInt DTraceRedirect::Request(TInt aFunction, TAny* a1, TAny* /*a2*/)
+/**
+ Handle requests from the test program
+*/
+	{
+	TInt r=KErrNone;
+	switch (aFunction)
+		{
+		case RTraceRedirect::ENextTrace:
+			r=NextTrace(a1);
+			break;
+		default:
+			r=KErrNotSupported;
+			break;
+		}
+	return r;
+	}
+