kerneltest/e32test/misc/d_ipccpy.cpp
changeset 0 a41df078684a
child 31 56f325a607ea
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32test/misc/d_ipccpy.cpp	Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,363 @@
+// Copyright (c) 1997-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\misc\d_ipccpy.cpp
+// LDD for testing IPC copy functions
+// 
+//
+
+#include "platform.h"
+#include <kernel/kern_priv.h>
+#include "d_ipccpy.h"
+
+const TInt KMajorVersionNumber=0;
+const TInt KMinorVersionNumber=1;
+const TInt KBuildVersionNumber=1;
+
+const TInt KBigBufferSize = 65536;
+
+_LIT(KDIpcCpyPanicCategory,"DIpcCpy");
+
+class DIpcCpyFactory : public DLogicalDevice
+//
+// IPC copy LDD factory
+//
+	{
+public:
+	DIpcCpyFactory();
+	~DIpcCpyFactory();
+	virtual TInt Install();						//overriding pure virtual
+	virtual void GetCaps(TDes8& aDes) const;	//overriding pure virtual
+	virtual TInt Create(DLogicalChannelBase*& aChannel);	//overriding pure virtual
+
+private:
+	TDynamicDfcQue* iDfcQ;
+	};
+
+class DIpcCpy : public DLogicalChannel
+//
+// Millisecond timer LDD channel
+//
+	{
+public:
+	DIpcCpy(TDfcQue* aDfcQ);
+	virtual ~DIpcCpy();
+protected:
+	virtual TInt DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer);
+	virtual TInt Request(TInt aFunc, TAny* a1, TAny* a2);
+	virtual void HandleMsg(TMessageBase* aMsg);
+public:
+	void TimerExpired();
+	TInt CreateHardwareChunks(TPtr8& aUserDes);
+
+	// Panic reasons
+	enum TPanic
+		{
+		ERequestAlreadyPending = 1
+		};
+public:
+	DThread* iThread;
+	TClientRequest* iAsyncRequest;
+	TAny* iDest;
+	TInt iSeqNum;
+	NTimer iTimer;
+	TDfc iDfc;
+	TUint8 iBuffer[260];
+	TUint8* iBigBuffer;
+#ifdef __EPOC32__
+	DPlatChunkHw* iHwChunks[RIpcCpy::ENumHwChunkTypes];
+#endif
+	TLinAddr iHwChunkLinAddrs[RIpcCpy::ENumHwChunkTypes];
+	};
+
+DECLARE_STANDARD_LDD()
+	{
+    return new DIpcCpyFactory;
+    }
+
+DIpcCpyFactory::DIpcCpyFactory()
+//
+// Constructor
+//
+    {
+    iVersion=TVersion(KMajorVersionNumber,KMinorVersionNumber,KBuildVersionNumber);
+    //iParseMask=0;//No units, no info, no PDD
+    //iUnitsMask=0;//Only one thing
+    }
+
+DIpcCpyFactory::~DIpcCpyFactory()
+//
+// Destructor
+//
+	{
+	if (iDfcQ)
+		iDfcQ->Destroy();
+	}
+
+TInt DIpcCpyFactory::Create(DLogicalChannelBase*& aChannel)
+//
+// Create a new DIpcCpy on this logical device
+//
+    {
+	aChannel=new DIpcCpy(iDfcQ);
+    return aChannel?KErrNone:KErrNoMemory;
+    }
+
+const TInt KIpcCpyThreadPriority = 27;
+_LIT(KIpcCpyThread,"IpcCpyThread");
+
+TInt DIpcCpyFactory::Install()
+//
+// Install the LDD - overriding pure virtual
+//
+    {
+	// Allocate a kernel thread to run the DFC 
+	TInt r = Kern::DynamicDfcQCreate(iDfcQ, KIpcCpyThreadPriority, KIpcCpyThread);
+
+	if (r != KErrNone)
+		return r; 	
+
+    return SetName(&KIpcCpyLddName);
+    }
+
+void DIpcCpyFactory::GetCaps(TDes8& aDes) const
+//
+// Get capabilities - overriding pure virtual
+//
+    {
+    TCapsIpcCpyV01 b;
+    b.iVersion=TVersion(KMajorVersionNumber,KMinorVersionNumber,KBuildVersionNumber);
+    Kern::InfoCopy(aDes,(TUint8*)&b,sizeof(b));
+    }
+
+void timerExpired(TAny* aPtr)
+	{
+	DIpcCpy* p=(DIpcCpy*)aPtr;
+	p->iDfc.Add();
+	}
+
+void dfcFn(TAny* aPtr)
+	{
+	DIpcCpy* p=(DIpcCpy*)aPtr;
+	p->TimerExpired();
+	}
+
+DIpcCpy::DIpcCpy(TDfcQue* aDfcQ)
+//
+// Constructor
+//
+	:	iTimer(timerExpired,this),
+		iDfc(dfcFn,this,aDfcQ,1)
+    {
+	iThread=&Kern::CurrentThread();
+	iThread->Open();
+//	iSeqNum=0;
+//	iDest=NULL;
+	SetDfcQ(aDfcQ);
+    }
+
+DIpcCpy::~DIpcCpy()
+	{
+	if (iAsyncRequest)
+		{
+		Kern::QueueRequestComplete(iThread, iAsyncRequest, KErrCancel);	// does nothing if request not pending
+		Kern::DestroyClientRequest(iAsyncRequest);
+		}
+	Kern::Free(iBigBuffer);
+	Kern::SafeClose((DObject*&)iThread, NULL);
+
+#ifdef __EPOC32__
+	for(TInt i=0; i<RIpcCpy::ENumHwChunkTypes; i++)
+		Kern::SafeClose((DObject*&)iHwChunks[i], NULL);
+#endif
+	}
+
+TInt DIpcCpy::DoCreate(TInt /*aUnit*/, const TDesC8* /*anInfo*/, const TVersion& aVer)
+//
+// Create channel
+//
+    {
+
+    if (!Kern::QueryVersionSupported(TVersion(KMajorVersionNumber,KMinorVersionNumber,KBuildVersionNumber),aVer))
+    	return KErrNotSupported;
+	TInt r = Kern::CreateClientRequest(iAsyncRequest);
+	if (r!=KErrNone)
+		return r;
+	iBigBuffer = (TUint8*)Kern::Alloc(KBigBufferSize);
+	if (!iBigBuffer)
+		return KErrNoMemory;
+	iMsgQ.Receive();
+	return KErrNone;
+	}
+
+
+TInt DIpcCpy::CreateHardwareChunks(TPtr8& aUserDes)
+	{
+#ifndef __EPOC32__
+	(void)aUserDes;
+	return KErrNone;
+#else
+	NKern::ThreadEnterCS();
+	TInt r;
+	TUint32 size=Kern::RoundToPageSize(1);
+#ifdef __X86__
+	const TUint attrs[] = { EMapAttrSupRw, EMapAttrUserRw, EMapAttrReadUser }; // X86 does support EMapAttrUserRo, so use EMapAttrReadUser
+#else
+	const TUint attrs[] = { EMapAttrSupRw, EMapAttrUserRw, EMapAttrUserRo };
+#endif
+	for(TInt i=0; i<RIpcCpy::ENumHwChunkTypes; i++)
+		{
+		TPhysAddr phys;
+		r = Epoc::AllocPhysicalRam(size,phys);
+		if(r!=KErrNone)
+			{
+			NKern::ThreadLeaveCS();
+			return r;
+			}
+
+		TChunkCreateInfo info;
+		info.iType = TChunkCreateInfo::ESharedKernelMultiple;
+		info.iMaxSize = size;
+		info.iMapAttr = 0;
+		info.iOwnsMemory = EFalse;
+		DChunk* chunk;
+		TLinAddr base;
+		TUint32 attr;
+		r = Kern::ChunkCreate(info,chunk,base,attr);
+		if(r==KErrNone)
+			{
+			r=Kern::ChunkCommitPhysical(chunk, 0, size, phys);
+			if(r==KErrNone)
+				{
+				memcpy((TAny*)base,&aUserDes,sizeof(TPtr8));
+				}
+			Kern::ChunkClose(chunk);
+			if(r==KErrNone)
+				r = DPlatChunkHw::New(iHwChunks[i], phys, size, attrs[i]);
+			}
+
+		if(r==KErrNone)
+			{
+			iHwChunkLinAddrs[i] = iHwChunks[i]->LinearAddress();
+			}
+		else if (r==KErrNotSupported) //ARMv6K && ARMv7 do not support EMapAttrUserRo
+			{
+			iHwChunkLinAddrs[i] = 0;
+			r = KErrNone;			
+			}
+		else
+			{
+			Epoc::FreePhysicalRam(phys,size);
+			NKern::ThreadLeaveCS();
+			return r;
+			}
+
+		}
+	NKern::ThreadLeaveCS();
+	return r;
+#endif
+	}
+
+
+TInt DIpcCpy::Request(TInt aFunc, TAny* a1, TAny* a2)
+	{
+	if (aFunc == RIpcCpy::EControlBigRead)
+		{
+		TUint size = (TUint)a2;
+		if (size > (TUint)KBigBufferSize)
+			return KErrOverflow;
+		kumemput(a1, iBigBuffer, size);
+		return KErrNone;
+		}
+	else if (aFunc == RIpcCpy::EControlBigWrite)
+		{
+		TUint size = (TUint)a2;
+		if (size > (TUint)KBigBufferSize)
+			return KErrOverflow;
+		kumemget(iBigBuffer, a1, size);
+		return KErrNone;
+		}
+	else if (aFunc == RIpcCpy::EControlHardwareChunks)
+		{
+		TPtr8 des(0,0,0);
+		kumemget(&des,a2,sizeof(TPtr8));
+		TInt r=CreateHardwareChunks(des);
+		if(r==KErrNone)
+			kumemput(a1, iHwChunkLinAddrs, sizeof(iHwChunkLinAddrs));
+		return r;
+		}
+	return DLogicalChannel::Request(aFunc, a1, a2);
+	}
+
+void DIpcCpy::HandleMsg(TMessageBase* aMsg)
+	{
+	TInt r=KErrNone;
+	TThreadMessage& m=*(TThreadMessage*)aMsg;
+	TInt id=m.iValue;
+	if (id==(TInt)ECloseMsg)
+		{
+		iTimer.Cancel();
+		iDfc.Cancel();
+		m.Complete(KErrNone,EFalse);
+		iMsgQ.CompleteAll(KErrServerTerminated);
+		return;
+		}
+	else if (id<0)
+		{
+		TRequestStatus* pS=(TRequestStatus*)m.Ptr0();
+		if (iAsyncRequest->SetStatus(pS) != KErrNone)
+			Kern::ThreadKill(iThread,EExitPanic,ERequestAlreadyPending,KDIpcCpyPanicCategory);
+
+		if (id==~RIpcCpy::ERequestIpcCpy)
+			{
+			iDest=m.Ptr1();
+			iTimer.OneShot(1);
+			}
+		else
+			{
+			r=KErrNotSupported;
+			}
+
+		if(r!=KErrNone)
+			{
+			Kern::QueueRequestComplete(iThread, iAsyncRequest, r);
+			r = KErrNone;
+			}
+		}
+	else
+		{
+		r=KErrNotSupported;
+		}
+
+	m.Complete(r,ETrue);
+	}
+
+void DIpcCpy::TimerExpired()
+	{
+	TInt src_offset=iSeqNum&3;
+	TInt dest_offset=(iSeqNum>>2)&3;
+	TInt length=(iSeqNum>>4)+1;
+	TInt i;
+	for (i=src_offset; i<length+src_offset; ++i)
+		iBuffer[i]=(TUint8)(i+1);
+	TPtrC8 ptr(iBuffer+src_offset, length);
+	TInt r=Kern::ThreadDesWrite(iThread, iDest, ptr, dest_offset, KChunkShiftBy0, NULL);
+	if (r==KErrNone)
+		{
+		r=iSeqNum;
+		if (++iSeqNum==4096)
+			iSeqNum=0;
+		}
+	Kern::QueueRequestComplete(iThread, iAsyncRequest, r);
+	}
+