os/kernelhwsrv/kerneltest/e32test/misc/t_ipccpy.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     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 	}