--- /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);
+ }
+