kerneltest/e32test/misc/t_ipccpy.cpp
changeset 0 a41df078684a
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     1 // Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of the License "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // e32test\misc\t_ipccpy.cpp
       
    15 // Overview:
       
    16 // Test and benchmark IPC reading, writing, copying.	
       
    17 // API Information:
       
    18 // RBusLogicalChannel, DLogicalChannel.	
       
    19 // Details:
       
    20 // - Load the specified logical device driver, open a channel to it, allocate 
       
    21 // a cell of specified size from the current thread's heap, get Kernel HAL
       
    22 // memory model information.
       
    23 // - Make a synchronous Kernel Executive type request to the logical channel 
       
    24 // to write specified data to the buffer, read the data and calculate the 
       
    25 // time taken for writing and reading the data. Benchmark the time required 
       
    26 // to for 1000 64K user->kernel and kernel->user copies.
       
    27 // - Create a chunk, get a pointer to the base of the chunk's reserved region,
       
    28 // create a server thread, establish a session with the server, signal 
       
    29 // completion of the client's request when message is received, read, 
       
    30 // write specified bits and check it is as expected.
       
    31 // Platforms/Drives/Compatibility:
       
    32 // All.
       
    33 // Assumptions/Requirement/Pre-requisites:
       
    34 // Failures and causes:
       
    35 // Base Port information:
       
    36 // 
       
    37 //
       
    38 
       
    39 #include <e32test.h>
       
    40 #include "d_ipccpy.h"
       
    41 #include "u32std.h"
       
    42 #include <e32kpan.h>
       
    43 #include "../mmu/mmudetect.h"
       
    44 #include <hal.h>
       
    45 
       
    46 RTest test(_L("T_IPCCPY"));
       
    47 TUint8* Buffer;
       
    48 TUint8* Disc;
       
    49 RIpcCpy Ipccpy;
       
    50 TUint32 MainId;
       
    51 TUint8 Bss[4096];
       
    52 TUint8* Kern;
       
    53 TUint8* RamDrive;
       
    54 TUint8* Nonexistent;
       
    55 TUint8* Unaligned=Bss+1;
       
    56 TInt CloseTime;
       
    57 TLinAddr HwChunkAddr[RIpcCpy::ENumHwChunkTypes];
       
    58 TPtr8 UserDes(Buffer+96,96,96);
       
    59 
       
    60 void SetupAddresses()
       
    61 	{
       
    62 	Kern=KernData();
       
    63 	TUint32 mm_attr=MemModelAttributes();
       
    64 	TUint32 mm_type=mm_attr & EMemModelTypeMask;
       
    65 	switch (mm_type)
       
    66 		{
       
    67 		case EMemModelTypeDirect:
       
    68 			RamDrive=(TUint8*)0;	// not used anyway
       
    69 			Nonexistent=(TUint8*)0xa8000000;
       
    70 			break;
       
    71 		case EMemModelTypeMoving:
       
    72 			RamDrive=(TUint8*)0x40000000;
       
    73 			Nonexistent=(TUint8*)0x60f00000;
       
    74 			break;
       
    75 		case EMemModelTypeMultiple:
       
    76 			RamDrive=(TUint8*)0xa0000000;
       
    77 			Nonexistent=(TUint8*)0xfe000000;
       
    78 			break;
       
    79 		case EMemModelTypeFlexible:
       
    80 			RamDrive=(TUint8*)0;
       
    81 			Nonexistent=(TUint8*)0x8ff00000;
       
    82 			break;
       
    83 		case EMemModelTypeEmul:
       
    84 			RamDrive=(TUint8*)0;	// not used anyway
       
    85 			Nonexistent=(TUint8*)0xf0000000;
       
    86 			break;
       
    87 		default:
       
    88 			test(0);
       
    89 			break;
       
    90 		}
       
    91 	new (&UserDes) TPtr8(Buffer+96,96,96);
       
    92 	Ipccpy.HardwareChunks(HwChunkAddr,UserDes);
       
    93 	test.Printf(_L("Buffer=%08x\n"),Buffer);
       
    94 	test.Printf(_L("Bss=%08x\n"),Bss);
       
    95 	test.Printf(_L("Kern=%08x\n"),Kern);
       
    96 	test.Printf(_L("RamDrive=%08x\n"),RamDrive);
       
    97 	test.Printf(_L("Nonexistent=%08x\n"),Nonexistent);
       
    98 	test.Printf(_L("Unaligned=%08x\n"),Unaligned);
       
    99 	test.Printf(_L("HwChunkSupRw=%08x\n"),HwChunkAddr[RIpcCpy::EHwChunkSupRw]);
       
   100 	test.Printf(_L("HwChunkUserRw=%08x\n"),HwChunkAddr[RIpcCpy::EHwChunkUserRw]);
       
   101 	test.Printf(_L("HwChunkUserRo=%08x\n"),HwChunkAddr[RIpcCpy::EHwChunkUserRo]);
       
   102 	}
       
   103 
       
   104 _LIT(KLitKernExec,"KERN-EXEC");
       
   105 
       
   106 void TestEq(TInt a, TInt b, TInt l);
       
   107 void Test(TBool c, TInt l);
       
   108 
       
   109 #define TESTEQ(a,b)		TestEq((a),(b),__LINE__)
       
   110 #define TEST(c)			Test((c),__LINE__)
       
   111 
       
   112 void TestEq(TInt a, TInt b, TInt l)
       
   113 	{
       
   114 	if (a!=b)
       
   115 		{
       
   116 		if (TUint32(RThread().Id())==MainId)
       
   117 			{
       
   118 			test.Printf(_L("Line %d a=%d, b=%d\n"),l,a,b);
       
   119 			test(0);
       
   120 			}
       
   121 		else
       
   122 			User::Panic(_L("TESTEQ"),l);
       
   123 		}
       
   124 	}
       
   125 
       
   126 void Test(TBool c, TInt l)
       
   127 	{
       
   128 	if (!c)
       
   129 		{
       
   130 		if (TUint32(RThread().Id())==MainId)
       
   131 			{
       
   132 			test.Printf(_L("Line %d FAIL\n"),l);
       
   133 			test(0);
       
   134 			}
       
   135 		else
       
   136 			User::Panic(_L("TEST"),l);
       
   137 		}
       
   138 	}
       
   139 
       
   140 struct SIpcTestInfo
       
   141 	{
       
   142 	const TAny* iLocal;
       
   143 	const TAny* iRemote;
       
   144 	TInt iOffset;
       
   145 	TInt iMode;			// bit 0 = 1 for 16 bit, bit 1 = 1 for write
       
   146 	};
       
   147 
       
   148 class RLocalSession : public RSessionBase
       
   149 	{
       
   150 public:
       
   151 	TInt Connect(RServer2 aSrv,TRequestStatus* aStat)
       
   152 		{return CreateSession(aSrv,TVersion(),-1,EIpcSession_Unsharable,0,aStat);}
       
   153 	void Test(const TAny* aRemote)
       
   154 		{Send(0,TIpcArgs((const TDesC8*)aRemote,(const TDesC16*)aRemote,(TDes8*)aRemote,(TDes16*)aRemote));}
       
   155 	void Wait()
       
   156 		{SendReceive(1);}
       
   157 	};
       
   158 
       
   159 RServer2 IpcServer;
       
   160 
       
   161 TInt IpcTestFn(TAny* aInfo)
       
   162 	{
       
   163 	SIpcTestInfo& i=*(SIpcTestInfo*)aInfo;
       
   164 
       
   165 	if (IpcServer.Handle())
       
   166 		IpcServer.Close();
       
   167 	
       
   168 	TESTEQ(IpcServer.CreateGlobal(KNullDesC),KErrNone);
       
   169 	RLocalSession sess;
       
   170 	TRequestStatus stat;
       
   171 	TESTEQ(sess.Connect(IpcServer,&stat),KErrNone);
       
   172 	RMessage2 m;
       
   173 	IpcServer.Receive(m);
       
   174 	m.Complete(KErrNone);	// connect
       
   175 	User::WaitForRequest(stat);	// connection message report
       
   176 	sess.Test(i.iRemote);
       
   177 	IpcServer.Receive(m);
       
   178 
       
   179 	TInt r=KMinTInt;
       
   180 	switch (i.iMode)
       
   181 		{
       
   182 		case 0:
       
   183 			{	// read 8 bit
       
   184 			TDesC8* pR=(TDesC8*)i.iRemote;
       
   185 			TDes8* pL=(TDes8*)i.iLocal;
       
   186 			r=m.Read(0,*pL,i.iOffset);
       
   187 			if (r==KErrNone)
       
   188 				{
       
   189 				TESTEQ(pL->Length(),pR->Length()-i.iOffset);
       
   190 				TEST(*pL==pR->Mid(i.iOffset));
       
   191 				}
       
   192 			break;
       
   193 			}
       
   194 		case 1:
       
   195 			{	// read 16 bit
       
   196 			TDesC16* pR=(TDesC16*)i.iRemote;
       
   197 			TDes16* pL=(TDes16*)i.iLocal;
       
   198 			r=m.Read(1,*pL,i.iOffset);
       
   199 			if (r==KErrNone)
       
   200 				{
       
   201 				TESTEQ(pL->Length(),pR->Length()-i.iOffset);
       
   202 				TEST(*pL==pR->Mid(i.iOffset));
       
   203 				}
       
   204 			break;
       
   205 			}
       
   206 		case 2:
       
   207 			{	// write 8 bit
       
   208 			TDes8* pR=(TDes8*)i.iRemote;
       
   209 			TDesC8* pL=(TDesC8*)i.iLocal;
       
   210 			r=m.Write(2,*pL,i.iOffset);
       
   211 			if (r==KErrNone)
       
   212 				{
       
   213 				TESTEQ(pR->Length(),pL->Length()+i.iOffset);
       
   214 				TEST(*pL==pR->Mid(i.iOffset));
       
   215 				}
       
   216 			break;
       
   217 			}
       
   218 		case 3:
       
   219 			{	// write 16 bit
       
   220 			TDes16* pR=(TDes16*)i.iRemote;
       
   221 			TDesC16* pL=(TDesC16*)i.iLocal;
       
   222 			r=m.Write(3,*pL,i.iOffset);
       
   223 			if (r==KErrNone)
       
   224 				{
       
   225 				TESTEQ(pR->Length(),pL->Length()+i.iOffset);
       
   226 				TEST(*pL==pR->Mid(i.iOffset));
       
   227 				}
       
   228 			break;
       
   229 			}
       
   230 		default:
       
   231 			User::Panic(_L("MODE"),i.iMode);
       
   232 		}
       
   233 	m.Complete(0);
       
   234 	sess.Close();
       
   235 	IpcServer.Close();
       
   236 
       
   237 	return r;
       
   238 	}
       
   239 
       
   240 void _DoIpcTest(const TAny* aLocal, const TAny* aRemote, TInt aOffset, TInt aMode, const TDesC* aPanicCat, TInt aResult, TInt aLine)
       
   241 	{
       
   242 	test.Printf(_L("Line %d\n"),aLine);
       
   243 	SIpcTestInfo info;
       
   244 	info.iLocal=aLocal;
       
   245 	info.iRemote=aRemote;
       
   246 	info.iOffset=aOffset;
       
   247 	info.iMode=aMode;
       
   248 	if (!aPanicCat)
       
   249 		{
       
   250 		// do test in this thread
       
   251 		TInt r=IpcTestFn(&info);
       
   252 		TESTEQ(r,aResult);
       
   253 		return;
       
   254 		}
       
   255 	TBool jit=User::JustInTime();
       
   256 	RThread t;
       
   257 	TInt r=t.Create(KNullDesC(),IpcTestFn,0x2000,NULL,&info);
       
   258 	test(r==KErrNone);
       
   259 	TRequestStatus s;
       
   260 	t.Logon(s);
       
   261 	User::SetJustInTime(EFalse);
       
   262 	t.Resume();
       
   263 	User::WaitForRequest(s);
       
   264 	User::SetJustInTime(jit);
       
   265 	test(t.ExitType()==EExitPanic);
       
   266 	test(t.ExitCategory()==*aPanicCat);
       
   267 	TESTEQ(t.ExitReason(),aResult);
       
   268 	t.Close();
       
   269 	}
       
   270 
       
   271 void DoIpcTest(const TUint8* aLocal, const TUint8* aRemote, TInt aLength, TInt aMode, const TDesC* aPanicCat, TInt aResult, TInt aLine)
       
   272 	{
       
   273 	TPtr8 local((TUint8*)aLocal,aLength,aLength);
       
   274 	TPtr8 remote((TUint8*)aRemote,aLength,aLength);
       
   275 	_DoIpcTest(&local,&remote,0,aMode,aPanicCat,aResult,aLine);
       
   276 	}
       
   277 
       
   278 void DoIpcTest(const TUint8* aLocal, const TDesC8& aRemote, TInt aLength, TInt aMode, const TDesC* aPanicCat, TInt aResult, TInt aLine)
       
   279 	{
       
   280 	TPtr8 local((TUint8*)aLocal,aLength,aLength);
       
   281 	_DoIpcTest(&local,&aRemote,0,aMode,aPanicCat,aResult,aLine);
       
   282 	}
       
   283 
       
   284 void TestIpcCopyErrors()
       
   285 	{
       
   286 	RChunk c;
       
   287 	TInt r=c.CreateDisconnectedLocal(0,0,0x500000);
       
   288 	test(r==KErrNone);
       
   289 	r=c.Commit(0,0x1000);
       
   290 	test(r==KErrNone);
       
   291 	r=c.Commit(0x2000,0x1000);
       
   292 	test(r==KErrNone);
       
   293 	r=c.Commit(0x3ff000,0x1000);
       
   294 	test(r==KErrNone);
       
   295 	Disc=c.Base();
       
   296 	test.Printf(_L("Disc=%08x\n"),Disc);
       
   297 	DoIpcTest(Buffer,(const TUint8*)&TestEq,100,0,NULL,KErrNone,__LINE__);
       
   298 	DoIpcTest(Buffer,(const TUint8*)&TestEq,100,2,NULL,KErrBadDescriptor,__LINE__);
       
   299 	DoIpcTest((const TUint8*)&TestEq,Buffer,100,2,NULL,KErrNone,__LINE__);
       
   300 	DoIpcTest((const TUint8*)&TestEq,Buffer,100,0,&KLitKernExec,ECausedException,__LINE__);
       
   301 	DoIpcTest(Buffer,Nonexistent,100,0,NULL,KErrBadDescriptor,__LINE__);
       
   302 	DoIpcTest(Buffer,Nonexistent,100,2,NULL,KErrBadDescriptor,__LINE__);
       
   303 	DoIpcTest(Nonexistent,Buffer,100,2,&KLitKernExec,ECausedException,__LINE__);
       
   304 	DoIpcTest(Nonexistent,Buffer,100,0,&KLitKernExec,ECausedException,__LINE__);
       
   305 	DoIpcTest(Buffer,Unaligned,100,0,NULL,KErrNone,__LINE__);
       
   306 	DoIpcTest(Buffer,Unaligned,100,2,NULL,KErrNone,__LINE__);
       
   307 	DoIpcTest(Unaligned,Buffer,100,2,NULL,KErrNone,__LINE__);
       
   308 	DoIpcTest(Unaligned,Buffer,100,0,NULL,KErrNone,__LINE__);
       
   309 
       
   310 	DoIpcTest(Disc+4001,Buffer,95,0,NULL,KErrNone,__LINE__);
       
   311 	if (HaveVirtMem())
       
   312 		DoIpcTest(Disc+4001,Buffer,96,0,&KLitKernExec,ECausedException,__LINE__);
       
   313 	DoIpcTest(Buffer,Disc+4001,95,0,NULL,KErrNone,__LINE__);
       
   314 	if (HaveVirtMem())
       
   315 		DoIpcTest(Buffer,Disc+4001,96,0,NULL,KErrBadDescriptor,__LINE__);
       
   316 
       
   317 	TPtr8* pdes;
       
   318 	if (HaveVirtMem())
       
   319 		{
       
   320 		// test descriptor stored stradling chunk end...
       
   321 		pdes = (TPtr8*)(Disc+0x3ffff4);
       
   322 		memcpy(pdes,&UserDes,12);
       
   323 		DoIpcTest(Buffer,*pdes,pdes->Size(),0,NULL,KErrNone,__LINE__);
       
   324 		pdes = (TPtr8*)(Disc+0x3ffff8);
       
   325 		memcpy(pdes,&UserDes,8);
       
   326 		DoIpcTest(Buffer,*pdes,pdes->Size(),0,NULL,KErrBadDescriptor,__LINE__);
       
   327 		pdes = (TPtr8*)(Disc+0x3ffffc);
       
   328 		memcpy(pdes,&UserDes,4);
       
   329 		DoIpcTest(Buffer,*pdes,pdes->Size(),0,NULL,KErrBadDescriptor,__LINE__);
       
   330 		r=c.Commit(0x400000,0x1000);
       
   331 		test(r==KErrNone);
       
   332 		pdes = (TPtr8*)(Disc+0x3ffff4);
       
   333 		memcpy(pdes,&UserDes,12);
       
   334 		DoIpcTest(Buffer,*pdes,pdes->Size(),0,NULL,KErrNone,__LINE__);
       
   335 		pdes = (TPtr8*)(Disc+0x3ffff8);
       
   336 		memcpy(pdes,&UserDes,12);
       
   337 		DoIpcTest(Buffer,*pdes,pdes->Size(),0,NULL,KErrNone,__LINE__);
       
   338 		pdes = (TPtr8*)(Disc+0x3ffffc);
       
   339 		memcpy(pdes,&UserDes,12);
       
   340 		DoIpcTest(Buffer,*pdes,pdes->Size(),0,NULL,KErrNone,__LINE__);
       
   341 		}
       
   342 
       
   343 	if (HaveMultAddr())
       
   344 		{
       
   345 		if(RamDrive)
       
   346 			{
       
   347 			DoIpcTest(Disc+0x100000,Buffer,96,0,&KLitKernExec,ECausedException,__LINE__);
       
   348 			DoIpcTest(Buffer,Disc+0x100000,96,0,NULL,KErrBadDescriptor,__LINE__);
       
   349 			DoIpcTest(RamDrive,Buffer,4,0,&KLitKernExec,ECausedException,__LINE__);
       
   350 			DoIpcTest(Buffer,RamDrive,4,0,NULL,KErrBadDescriptor,__LINE__);
       
   351 			DoIpcTest(RamDrive,Buffer,4,2,&KLitKernExec,ECausedException,__LINE__);
       
   352 			DoIpcTest(Buffer,RamDrive,4,2,NULL,KErrBadDescriptor,__LINE__);
       
   353 			}
       
   354 
       
   355 		// if memory alising happens during IPC then the memory at 'Disc' would be aliased
       
   356 		// at KIPCAliasAddress and so would not be protected by MMU permission checks.
       
   357 		// However, the kernel should still prevent this, to avoid degrading process
       
   358 		// protection for memory in other parts of the alias region.
       
   359 #ifdef __CPU_X86
       
   360 		const TUint8* KIPCAliasAddress;
       
   361 		if((MemModelAttributes()&EMemModelTypeMask) == EMemModelTypeFlexible)
       
   362 			KIPCAliasAddress = (TUint8*)0x7e000000;
       
   363 		else
       
   364 			KIPCAliasAddress = (TUint8*)0xc0400000;
       
   365 #else
       
   366 		const TUint8* KIPCAliasAddress = (TUint8*)0x00200000;
       
   367 #endif
       
   368 		DoIpcTest(KIPCAliasAddress,Disc,4,0,&KLitKernExec,ECausedException,__LINE__);
       
   369 		DoIpcTest(Disc,KIPCAliasAddress,4,0,NULL,KErrBadDescriptor,__LINE__);
       
   370 		DoIpcTest(KIPCAliasAddress,Disc,4,2,&KLitKernExec,ECausedException,__LINE__);
       
   371 		DoIpcTest(Disc,KIPCAliasAddress,4,2,NULL,KErrBadDescriptor,__LINE__);
       
   372 		}
       
   373 
       
   374 	if (HaveIPCKernProt())
       
   375 		{
       
   376 		DoIpcTest(Kern,Buffer,96,0,&KLitKernExec,ECausedException,__LINE__);
       
   377 		DoIpcTest(Buffer,Kern,96,0,NULL,KErrBadDescriptor,__LINE__);
       
   378 		TUint8* addrRW = (TUint8*)HwChunkAddr[RIpcCpy::EHwChunkSupRw];
       
   379 		if(addrRW)
       
   380 			{
       
   381 			DoIpcTest(Buffer,*(TDes8*)addrRW,96,0,NULL,KErrBadDescriptor,__LINE__);
       
   382 			DoIpcTest(Buffer,*(TDes8*)addrRW,96,2,NULL,KErrBadDescriptor,__LINE__);
       
   383 			DoIpcTest(addrRW+96,Buffer,96,0,&KLitKernExec,ECausedException,__LINE__);
       
   384 			DoIpcTest(Buffer,addrRW,96,0,NULL,KErrBadDescriptor,__LINE__);
       
   385 			DoIpcTest(addrRW+96,Buffer,96,2,&KLitKernExec,ECausedException,__LINE__);
       
   386 			DoIpcTest(Buffer,addrRW,96,2,NULL,KErrBadDescriptor,__LINE__);
       
   387 			}
       
   388 		}
       
   389 
       
   390 	if((MemModelAttributes()&EMemModelTypeMask) == EMemModelTypeMultiple
       
   391 		|| (MemModelAttributes()&EMemModelTypeMask) == EMemModelTypeFlexible
       
   392 		)
       
   393 		{
       
   394 		// On multiple memory model, test IPC to Hardware Chunks.
       
   395 		// IPC to hardware chunks not supported on Moving Memory
       
   396 		TUint8* addrRW = (TUint8*)HwChunkAddr[RIpcCpy::EHwChunkUserRw];
       
   397 		if(addrRW)
       
   398 			{
       
   399 			DoIpcTest(Buffer,*(TDes8*)addrRW,96,0,NULL,KErrNone,__LINE__);
       
   400 			DoIpcTest(Buffer,*(TDes8*)addrRW,96,2,NULL,KErrNone,__LINE__);
       
   401 			DoIpcTest(addrRW+96,Buffer,96,0,NULL,KErrNone,__LINE__);
       
   402 			DoIpcTest(Buffer,addrRW,96,0,NULL,KErrNone,__LINE__);
       
   403 			DoIpcTest(addrRW+96,Buffer,96,2,NULL,KErrNone,__LINE__);
       
   404 			DoIpcTest(Buffer,addrRW,96,2,NULL,KErrNone,__LINE__);
       
   405 			DoIpcTest(addrRW+96,addrRW,96,0,NULL,KErrNone,__LINE__);
       
   406 			DoIpcTest(addrRW+96,addrRW,96,2,NULL,KErrNone,__LINE__);
       
   407 			}
       
   408 		TUint8* addrRO = (TUint8*)HwChunkAddr[RIpcCpy::EHwChunkUserRo];
       
   409 		if(addrRO && HaveWriteProt())
       
   410 			{
       
   411 			DoIpcTest(Buffer,*(TDes8*)addrRO,96,0,NULL,KErrNone,__LINE__);
       
   412 			DoIpcTest(Buffer,*(TDes8*)addrRO,96,2,&KLitKernExec,EBadIpcDescriptor,__LINE__);
       
   413 			DoIpcTest(addrRO+96,Buffer,96,0,&KLitKernExec,ECausedException,__LINE__);
       
   414 			DoIpcTest(Buffer,addrRO,96,0,NULL,KErrNone,__LINE__);
       
   415 			DoIpcTest(addrRO+96,Buffer,96,2,NULL,KErrNone,__LINE__);
       
   416 			DoIpcTest(Buffer,addrRO,96,2,NULL,KErrBadDescriptor,__LINE__);
       
   417 			DoIpcTest(addrRW+96,addrRO,96,0,NULL,KErrNone,__LINE__);
       
   418 			DoIpcTest(addrRW+96,addrRW,96,2,NULL,KErrNone,__LINE__);
       
   419 			DoIpcTest(addrRO+96,addrRO,96,0,&KLitKernExec,ECausedException,__LINE__);
       
   420 			DoIpcTest(addrRO+96,addrRW,96,2,NULL,KErrNone,__LINE__);
       
   421 			}
       
   422 		}
       
   423 
       
   424 	c.Close();
       
   425 	}
       
   426 
       
   427 RMessage2 Msg1, Msg2;
       
   428 
       
   429 TInt SendAndExit(TAny* aPtr)
       
   430 	{
       
   431 	RLocalSession sess;
       
   432 	TInt r=sess.Connect(IpcServer,NULL);
       
   433 	if (r!=KErrNone)
       
   434 		return r;
       
   435 	sess.Test(aPtr);
       
   436 	sess.Wait();
       
   437 	sess.Close();
       
   438 	User::AfterHighRes(1000*CloseTime);
       
   439 	Msg1.Complete(0);		// complete my own message! - this removes message reference to thread
       
   440 	return 0;
       
   441 	}
       
   442 
       
   443 void TestIpcAsyncClose()
       
   444 	{
       
   445 
       
   446 	// Create a 16MB chunk
       
   447 	const TInt desSize = 8*1024*1024;
       
   448 	RChunk chunk;
       
   449 	test(chunk.CreateLocal(2 * desSize, 2 * desSize) == KErrNone);
       
   450 	test(chunk.Adjust(2 * desSize) == KErrNone);
       
   451 
       
   452 	TUint8* bigBuf=chunk.Base();
       
   453 	test(bigBuf!=NULL);
       
   454 	TUint8* bigBuf2=chunk.Base() + desSize;
       
   455 	test(bigBuf2!=NULL);
       
   456 	TPtr8 bigBufPtr(bigBuf, desSize, desSize);
       
   457 	TPtr8 bigBufPtr2(bigBuf2, 0, desSize);
       
   458 
       
   459 	if (IpcServer.Handle())
       
   460 		IpcServer.Close();
       
   461 	TESTEQ(IpcServer.CreateGlobal(KNullDesC),KErrNone);
       
   462 
       
   463 	RThread t;
       
   464 	TInt r=t.Create(KNullDesC,SendAndExit,0x1000,NULL,&bigBufPtr);
       
   465 	test(r==KErrNone);
       
   466 	TFullName fn(t.FullName());
       
   467 	TRequestStatus s;
       
   468 	t.Logon(s);
       
   469 	t.SetPriority(EPriorityMuchMore);
       
   470 	t.Resume();
       
   471 
       
   472 	IpcServer.Receive(Msg1);	// connect
       
   473 	Msg1.Complete(KErrNone);
       
   474 	IpcServer.Receive(Msg1);	// test message
       
   475 	IpcServer.Receive(Msg2);	// wait/synch message
       
   476 	TUint32 initial = User::NTickCount();
       
   477 	r=Msg1.Read(2,bigBufPtr2,0);	// arg2 is writable 8 bit descriptor
       
   478 	TUint32 final = User::NTickCount();
       
   479 	TUint32 elapsed = final - initial;
       
   480 	if (elapsed<3)
       
   481 		test.Printf(_L("*** WARNING! The big IPC only took %dms, which means the next test might fail! \n"),elapsed);
       
   482 	else
       
   483 		test.Printf(_L("Big IPC took %dms\n"),elapsed);
       
   484 	CloseTime = (TInt)(elapsed>>2);
       
   485 	Msg2.Complete(0);
       
   486 	IpcServer.Receive(Msg2);	// disconnect
       
   487 	TUint32 disconnect = User::NTickCount();
       
   488 	
       
   489 	// We expect this IPC read to fail part way through
       
   490 	r=Msg1.Read(2,bigBufPtr2,0);	// arg2 is writable 8 bit descriptor
       
   491 	test.Printf(_L("counters: initial=%d final=%d disconnect=%d current=%d\n"),initial,final,disconnect,User::NTickCount());
       
   492 	test.Printf(_L("2nd Big IPC returned %d\n"),r);
       
   493 	test(r==KErrDied);
       
   494 	test(Msg1.IsNull());
       
   495 	Msg2.Complete(0);		// complete session closure as well
       
   496 	User::WaitForRequest(s);
       
   497 	test(s==KErrNone);
       
   498 	CLOSE_AND_WAIT(t);
       
   499 	test(t.Open(fn)==KErrNotFound);
       
   500 	IpcServer.Close();
       
   501 
       
   502 	// t already closed
       
   503 //	User::Free(bigBuf);
       
   504 //	User::Free(bigBuf2);
       
   505 	chunk.Close();
       
   506 	}
       
   507 
       
   508 void BenchmarkTest()
       
   509 	{
       
   510 	TAny* bigbuf = User::Alloc(65536);
       
   511 	test(bigbuf != NULL);
       
   512 	TInt i;
       
   513 	TUint32 initial, final;
       
   514 	initial = User::NTickCount();
       
   515 	for (i=0; i<1000; ++i)
       
   516 		Ipccpy.BigWrite(bigbuf, 0);
       
   517 	final = User::NTickCount();
       
   518 	TUint32 wcal = final - initial;
       
   519 	initial = User::NTickCount();
       
   520 	for (i=0; i<1000; ++i)
       
   521 		Ipccpy.BigWrite(bigbuf, 65536);
       
   522 	final = User::NTickCount();
       
   523 	TUint32 write = final - initial;
       
   524 	test.Printf(_L("64K user->kernel copy takes %d us\n"), write - wcal);
       
   525 	initial = User::NTickCount();
       
   526 	for (i=0; i<1000; ++i)
       
   527 		Ipccpy.BigRead(bigbuf, 0);
       
   528 	final = User::NTickCount();
       
   529 	TUint32 rcal = final - initial;
       
   530 	initial = User::NTickCount();
       
   531 	for (i=0; i<1000; ++i)
       
   532 		Ipccpy.BigRead(bigbuf, 65536);
       
   533 	final = User::NTickCount();
       
   534 	TUint32 read = final - initial;
       
   535 	test.Printf(_L("64K kernel->user copy takes %d us\n"), read - rcal);
       
   536 	User::Free(bigbuf);
       
   537 //	User::After(10*1000*1000);
       
   538 	}
       
   539 
       
   540 
       
   541 RMessage2 IpcMesage;
       
   542 const TInt KTestChunkSize = 1024*1024;
       
   543 const TInt KReadSize = 4096;
       
   544 
       
   545 TInt IpcMultipleAliasesThread(TAny* aBuffer)
       
   546 	{
       
   547 	TBuf8<KReadSize> data;
       
   548 	TAny** dataStart = (TAny**)data.Ptr();
       
   549 	TAny** dataEnd = (TAny**)(data.Ptr()+KReadSize-sizeof(TAny*));
       
   550 	for(;;)
       
   551 		{
       
   552 		TInt offset;
       
   553 		for(offset=0; offset<KTestChunkSize; offset+=KReadSize)
       
   554 			{
       
   555 			TInt r = IpcMesage.Read(0,data,offset);
       
   556 			if(r!=KErrNone)
       
   557 				return r;
       
   558 			if(data.Size()!=KReadSize)
       
   559 				return 1;
       
   560 			TAny* expected = (TAny*)((TInt)aBuffer+offset);
       
   561 			if(*dataStart != expected)
       
   562 				{
       
   563 				RDebug::Printf("Offset=%x, expected %x but read %x",offset,expected,*dataStart);
       
   564 				return 2;
       
   565 				}
       
   566 			expected = (TAny*)((TInt)aBuffer+offset+KReadSize-sizeof(TAny*));
       
   567 			if(*dataEnd != expected)
       
   568 				{
       
   569 				RDebug::Printf("Offset=%x, expected %x but read %x",offset,expected,*dataEnd);
       
   570 				return 3;
       
   571 				}
       
   572 			}
       
   573 		}
       
   574 	}
       
   575 
       
   576 /*
       
   577 This tests exercises the situation where multiple threads are doing IPC simultaneousely.
       
   578 On the Multiple Memory Model, this aims to test the per-thread memory aliasing code.
       
   579 (DMemModelThread::Alias and company)
       
   580 */
       
   581 void TestIpcMultipleThreads()
       
   582 	{
       
   583 	test.Start(_L("Test Multiple Threads IPC"));
       
   584 
       
   585 	// create chunk for threads to do IPC from...
       
   586 	RChunk chunk;
       
   587 	TESTEQ(chunk.CreateLocal(KTestChunkSize,KTestChunkSize),KErrNone);
       
   588 	TAny** buffer = (TAny**)chunk.Base();
       
   589 	TAny** bufferEnd = (TAny**)((TInt)buffer+KTestChunkSize);
       
   590 	for(; buffer<bufferEnd; ++buffer)
       
   591 		*buffer=buffer;
       
   592 
       
   593 	// create a server message which test threads can use to do IPC memory operations
       
   594 	if (IpcServer.Handle())
       
   595 		IpcServer.Close();	
       
   596 	TESTEQ(IpcServer.CreateGlobal(KNullDesC),KErrNone);
       
   597 	RLocalSession sess;
       
   598 	TRequestStatus stat;
       
   599 	TESTEQ(sess.Connect(IpcServer,&stat),KErrNone);
       
   600 	RMessage2 m;
       
   601 	IpcServer.Receive(m);
       
   602 	m.Complete(KErrNone);	// connect
       
   603 	User::WaitForRequest(stat);	// connection message report
       
   604 	TAny* ptrMem = User::Alloc(0x2000);
       
   605 	TPtr8* pptr = (TPtr8*)(((TInt)ptrMem&~0xfff)+0x1000-sizeof(TInt));
       
   606 	new (pptr) TPtr8(chunk.Base(),KTestChunkSize,KTestChunkSize); // create a TPtr8 which straddles a page boundary
       
   607 	sess.Test(pptr);
       
   608 	IpcServer.Receive(IpcMesage);
       
   609 
       
   610 	// create some test threads...
       
   611 	const TInt KNumIpcThreads = 10;
       
   612 	RThread threads[KNumIpcThreads];
       
   613 	TRequestStatus stats[KNumIpcThreads];
       
   614 	TInt i;
       
   615 	for(i=0; i<KNumIpcThreads; i++)
       
   616 		{
       
   617 		TESTEQ(threads[i].Create(KNullDesC,IpcMultipleAliasesThread,KReadSize+0x1000,&User::Allocator(),chunk.Base()),KErrNone);
       
   618 		threads[i].Logon(stats[i]);
       
   619 		}
       
   620 	test.Printf(_L("Resuming threads...\n"));
       
   621 	for(i=0; i<KNumIpcThreads; i++)
       
   622 		threads[i].Resume();
       
   623 
       
   624 	User::After(10*1000000);
       
   625 	for(i=0; i<KNumIpcThreads; i++)
       
   626 		{
       
   627 		test(stats[i]==KRequestPending); // theads should still be running
       
   628 		}
       
   629 
       
   630 	// close chunk whilst test threads are still doing IPC...
       
   631 	test.Printf(_L("Closing chunk...\n"));
       
   632 	chunk.Close();
       
   633 	for(i=0; i<KNumIpcThreads; i++)
       
   634 		{
       
   635 		User::WaitForRequest(stats[i]);
       
   636 		TInt r=stats[i].Int();
       
   637 		test.Printf(_L("Thread %d result = %d\n"),i,r);
       
   638 		test(r==KErrBadDescriptor);
       
   639 		}
       
   640 
       
   641 	IpcServer.Close();
       
   642 	User::Free(ptrMem);
       
   643 	test.End();
       
   644 	}
       
   645 
       
   646 GLDEF_C TInt E32Main()
       
   647 	{
       
   648 	MainId=TUint32(RThread().Id());
       
   649 //	RThread().SetPriority(EPriorityAbsoluteForeground);
       
   650 	test.Title();
       
   651 	test.Start(_L("Load LDD"));
       
   652 	TInt r=User::LoadLogicalDevice(_L("D_IPCCPY"));
       
   653 	test(r==KErrNone || r==KErrAlreadyExists);
       
   654 	test.Next(_L("Open channel"));
       
   655 	r=Ipccpy.Open();
       
   656 	test(r==KErrNone);
       
   657 	test.Next(_L("Allocate heap buffer"));
       
   658 	Buffer=(TUint8*)User::Alloc(4096);
       
   659 	test(Buffer!=NULL);
       
   660 	SetupAddresses();
       
   661 
       
   662 	BenchmarkTest();
       
   663 
       
   664 	TestIpcCopyErrors();
       
   665 	TestIpcAsyncClose();
       
   666 	TestIpcMultipleThreads();
       
   667 
       
   668 	FOREVER
       
   669 		{
       
   670 		TRequestStatus s;
       
   671 		Mem::Fill(Buffer,272,0xcd);
       
   672 		TPtr8 ptr(Buffer,0,272);
       
   673 		Ipccpy.IpcCpy(s,ptr);
       
   674 		User::WaitForRequest(s);
       
   675 		TInt x=s.Int();
       
   676 		if (x<0)
       
   677 			{
       
   678 			test.Printf(_L("Error %d\n"),x);
       
   679 			test(0);
       
   680 			}
       
   681 		TInt src_offset=x&3;
       
   682 		TInt dest_offset=(x>>2)&3;
       
   683 		TInt length=(x>>4)+1;
       
   684 		TInt err=-1;
       
   685 		TInt i;
       
   686 		for (i=0; i<dest_offset && err<0; ++i)
       
   687 			{
       
   688 			if (Buffer[i]!=0xcd)
       
   689 				err=i;
       
   690 			}
       
   691 		TUint8 v=(TUint8)src_offset;
       
   692 		for (i=0; i<length && err<0; ++i)
       
   693 			{
       
   694 			++v;
       
   695 			if (Buffer[i+dest_offset]!=v)
       
   696 				err=i+dest_offset;
       
   697 			}
       
   698 		for (i=dest_offset+length; i<272 && err<0; ++i)
       
   699 			{
       
   700 			if (Buffer[i]!=0xcd)
       
   701 				err=i;
       
   702 			}
       
   703 		if (err>=0)
       
   704 			{
       
   705 			test.Printf(_L("Sequence number %03x\nSrcOffset %d, DestOffset %d, Length %d\n"),x,src_offset,dest_offset,length);
       
   706 			test.Printf(_L("First error at %d"),err);
       
   707 			for (i=0; i<272; i+=16)
       
   708 				{
       
   709 				TInt j;
       
   710 				test.Printf(_L("%03x:"),i);
       
   711 				for (j=0; j<16; ++j)
       
   712 					{
       
   713 					test.Printf(_L(" %02x"),Buffer[i+j]);
       
   714 					}
       
   715 				}
       
   716 			test(0);
       
   717 			}
       
   718 		if (x==4095)
       
   719 			break;
       
   720 		}
       
   721 	Ipccpy.Close();
       
   722 	test.End();
       
   723 	return KErrNone;
       
   724 	}