1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/kerneltest/e32test/misc/t_ipccpy.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,724 @@
1.4 +// Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of the License "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// e32test\misc\t_ipccpy.cpp
1.18 +// Overview:
1.19 +// Test and benchmark IPC reading, writing, copying.
1.20 +// API Information:
1.21 +// RBusLogicalChannel, DLogicalChannel.
1.22 +// Details:
1.23 +// - Load the specified logical device driver, open a channel to it, allocate
1.24 +// a cell of specified size from the current thread's heap, get Kernel HAL
1.25 +// memory model information.
1.26 +// - Make a synchronous Kernel Executive type request to the logical channel
1.27 +// to write specified data to the buffer, read the data and calculate the
1.28 +// time taken for writing and reading the data. Benchmark the time required
1.29 +// to for 1000 64K user->kernel and kernel->user copies.
1.30 +// - Create a chunk, get a pointer to the base of the chunk's reserved region,
1.31 +// create a server thread, establish a session with the server, signal
1.32 +// completion of the client's request when message is received, read,
1.33 +// write specified bits and check it is as expected.
1.34 +// Platforms/Drives/Compatibility:
1.35 +// All.
1.36 +// Assumptions/Requirement/Pre-requisites:
1.37 +// Failures and causes:
1.38 +// Base Port information:
1.39 +//
1.40 +//
1.41 +
1.42 +#include <e32test.h>
1.43 +#include "d_ipccpy.h"
1.44 +#include "u32std.h"
1.45 +#include <e32kpan.h>
1.46 +#include "../mmu/mmudetect.h"
1.47 +#include <hal.h>
1.48 +
1.49 +RTest test(_L("T_IPCCPY"));
1.50 +TUint8* Buffer;
1.51 +TUint8* Disc;
1.52 +RIpcCpy Ipccpy;
1.53 +TUint32 MainId;
1.54 +TUint8 Bss[4096];
1.55 +TUint8* Kern;
1.56 +TUint8* RamDrive;
1.57 +TUint8* Nonexistent;
1.58 +TUint8* Unaligned=Bss+1;
1.59 +TInt CloseTime;
1.60 +TLinAddr HwChunkAddr[RIpcCpy::ENumHwChunkTypes];
1.61 +TPtr8 UserDes(Buffer+96,96,96);
1.62 +
1.63 +void SetupAddresses()
1.64 + {
1.65 + Kern=KernData();
1.66 + TUint32 mm_attr=MemModelAttributes();
1.67 + TUint32 mm_type=mm_attr & EMemModelTypeMask;
1.68 + switch (mm_type)
1.69 + {
1.70 + case EMemModelTypeDirect:
1.71 + RamDrive=(TUint8*)0; // not used anyway
1.72 + Nonexistent=(TUint8*)0xa8000000;
1.73 + break;
1.74 + case EMemModelTypeMoving:
1.75 + RamDrive=(TUint8*)0x40000000;
1.76 + Nonexistent=(TUint8*)0x60f00000;
1.77 + break;
1.78 + case EMemModelTypeMultiple:
1.79 + RamDrive=(TUint8*)0xa0000000;
1.80 + Nonexistent=(TUint8*)0xfe000000;
1.81 + break;
1.82 + case EMemModelTypeFlexible:
1.83 + RamDrive=(TUint8*)0;
1.84 + Nonexistent=(TUint8*)0x8ff00000;
1.85 + break;
1.86 + case EMemModelTypeEmul:
1.87 + RamDrive=(TUint8*)0; // not used anyway
1.88 + Nonexistent=(TUint8*)0xf0000000;
1.89 + break;
1.90 + default:
1.91 + test(0);
1.92 + break;
1.93 + }
1.94 + new (&UserDes) TPtr8(Buffer+96,96,96);
1.95 + Ipccpy.HardwareChunks(HwChunkAddr,UserDes);
1.96 + test.Printf(_L("Buffer=%08x\n"),Buffer);
1.97 + test.Printf(_L("Bss=%08x\n"),Bss);
1.98 + test.Printf(_L("Kern=%08x\n"),Kern);
1.99 + test.Printf(_L("RamDrive=%08x\n"),RamDrive);
1.100 + test.Printf(_L("Nonexistent=%08x\n"),Nonexistent);
1.101 + test.Printf(_L("Unaligned=%08x\n"),Unaligned);
1.102 + test.Printf(_L("HwChunkSupRw=%08x\n"),HwChunkAddr[RIpcCpy::EHwChunkSupRw]);
1.103 + test.Printf(_L("HwChunkUserRw=%08x\n"),HwChunkAddr[RIpcCpy::EHwChunkUserRw]);
1.104 + test.Printf(_L("HwChunkUserRo=%08x\n"),HwChunkAddr[RIpcCpy::EHwChunkUserRo]);
1.105 + }
1.106 +
1.107 +_LIT(KLitKernExec,"KERN-EXEC");
1.108 +
1.109 +void TestEq(TInt a, TInt b, TInt l);
1.110 +void Test(TBool c, TInt l);
1.111 +
1.112 +#define TESTEQ(a,b) TestEq((a),(b),__LINE__)
1.113 +#define TEST(c) Test((c),__LINE__)
1.114 +
1.115 +void TestEq(TInt a, TInt b, TInt l)
1.116 + {
1.117 + if (a!=b)
1.118 + {
1.119 + if (TUint32(RThread().Id())==MainId)
1.120 + {
1.121 + test.Printf(_L("Line %d a=%d, b=%d\n"),l,a,b);
1.122 + test(0);
1.123 + }
1.124 + else
1.125 + User::Panic(_L("TESTEQ"),l);
1.126 + }
1.127 + }
1.128 +
1.129 +void Test(TBool c, TInt l)
1.130 + {
1.131 + if (!c)
1.132 + {
1.133 + if (TUint32(RThread().Id())==MainId)
1.134 + {
1.135 + test.Printf(_L("Line %d FAIL\n"),l);
1.136 + test(0);
1.137 + }
1.138 + else
1.139 + User::Panic(_L("TEST"),l);
1.140 + }
1.141 + }
1.142 +
1.143 +struct SIpcTestInfo
1.144 + {
1.145 + const TAny* iLocal;
1.146 + const TAny* iRemote;
1.147 + TInt iOffset;
1.148 + TInt iMode; // bit 0 = 1 for 16 bit, bit 1 = 1 for write
1.149 + };
1.150 +
1.151 +class RLocalSession : public RSessionBase
1.152 + {
1.153 +public:
1.154 + TInt Connect(RServer2 aSrv,TRequestStatus* aStat)
1.155 + {return CreateSession(aSrv,TVersion(),-1,EIpcSession_Unsharable,0,aStat);}
1.156 + void Test(const TAny* aRemote)
1.157 + {Send(0,TIpcArgs((const TDesC8*)aRemote,(const TDesC16*)aRemote,(TDes8*)aRemote,(TDes16*)aRemote));}
1.158 + void Wait()
1.159 + {SendReceive(1);}
1.160 + };
1.161 +
1.162 +RServer2 IpcServer;
1.163 +
1.164 +TInt IpcTestFn(TAny* aInfo)
1.165 + {
1.166 + SIpcTestInfo& i=*(SIpcTestInfo*)aInfo;
1.167 +
1.168 + if (IpcServer.Handle())
1.169 + IpcServer.Close();
1.170 +
1.171 + TESTEQ(IpcServer.CreateGlobal(KNullDesC),KErrNone);
1.172 + RLocalSession sess;
1.173 + TRequestStatus stat;
1.174 + TESTEQ(sess.Connect(IpcServer,&stat),KErrNone);
1.175 + RMessage2 m;
1.176 + IpcServer.Receive(m);
1.177 + m.Complete(KErrNone); // connect
1.178 + User::WaitForRequest(stat); // connection message report
1.179 + sess.Test(i.iRemote);
1.180 + IpcServer.Receive(m);
1.181 +
1.182 + TInt r=KMinTInt;
1.183 + switch (i.iMode)
1.184 + {
1.185 + case 0:
1.186 + { // read 8 bit
1.187 + TDesC8* pR=(TDesC8*)i.iRemote;
1.188 + TDes8* pL=(TDes8*)i.iLocal;
1.189 + r=m.Read(0,*pL,i.iOffset);
1.190 + if (r==KErrNone)
1.191 + {
1.192 + TESTEQ(pL->Length(),pR->Length()-i.iOffset);
1.193 + TEST(*pL==pR->Mid(i.iOffset));
1.194 + }
1.195 + break;
1.196 + }
1.197 + case 1:
1.198 + { // read 16 bit
1.199 + TDesC16* pR=(TDesC16*)i.iRemote;
1.200 + TDes16* pL=(TDes16*)i.iLocal;
1.201 + r=m.Read(1,*pL,i.iOffset);
1.202 + if (r==KErrNone)
1.203 + {
1.204 + TESTEQ(pL->Length(),pR->Length()-i.iOffset);
1.205 + TEST(*pL==pR->Mid(i.iOffset));
1.206 + }
1.207 + break;
1.208 + }
1.209 + case 2:
1.210 + { // write 8 bit
1.211 + TDes8* pR=(TDes8*)i.iRemote;
1.212 + TDesC8* pL=(TDesC8*)i.iLocal;
1.213 + r=m.Write(2,*pL,i.iOffset);
1.214 + if (r==KErrNone)
1.215 + {
1.216 + TESTEQ(pR->Length(),pL->Length()+i.iOffset);
1.217 + TEST(*pL==pR->Mid(i.iOffset));
1.218 + }
1.219 + break;
1.220 + }
1.221 + case 3:
1.222 + { // write 16 bit
1.223 + TDes16* pR=(TDes16*)i.iRemote;
1.224 + TDesC16* pL=(TDesC16*)i.iLocal;
1.225 + r=m.Write(3,*pL,i.iOffset);
1.226 + if (r==KErrNone)
1.227 + {
1.228 + TESTEQ(pR->Length(),pL->Length()+i.iOffset);
1.229 + TEST(*pL==pR->Mid(i.iOffset));
1.230 + }
1.231 + break;
1.232 + }
1.233 + default:
1.234 + User::Panic(_L("MODE"),i.iMode);
1.235 + }
1.236 + m.Complete(0);
1.237 + sess.Close();
1.238 + IpcServer.Close();
1.239 +
1.240 + return r;
1.241 + }
1.242 +
1.243 +void _DoIpcTest(const TAny* aLocal, const TAny* aRemote, TInt aOffset, TInt aMode, const TDesC* aPanicCat, TInt aResult, TInt aLine)
1.244 + {
1.245 + test.Printf(_L("Line %d\n"),aLine);
1.246 + SIpcTestInfo info;
1.247 + info.iLocal=aLocal;
1.248 + info.iRemote=aRemote;
1.249 + info.iOffset=aOffset;
1.250 + info.iMode=aMode;
1.251 + if (!aPanicCat)
1.252 + {
1.253 + // do test in this thread
1.254 + TInt r=IpcTestFn(&info);
1.255 + TESTEQ(r,aResult);
1.256 + return;
1.257 + }
1.258 + TBool jit=User::JustInTime();
1.259 + RThread t;
1.260 + TInt r=t.Create(KNullDesC(),IpcTestFn,0x2000,NULL,&info);
1.261 + test(r==KErrNone);
1.262 + TRequestStatus s;
1.263 + t.Logon(s);
1.264 + User::SetJustInTime(EFalse);
1.265 + t.Resume();
1.266 + User::WaitForRequest(s);
1.267 + User::SetJustInTime(jit);
1.268 + test(t.ExitType()==EExitPanic);
1.269 + test(t.ExitCategory()==*aPanicCat);
1.270 + TESTEQ(t.ExitReason(),aResult);
1.271 + t.Close();
1.272 + }
1.273 +
1.274 +void DoIpcTest(const TUint8* aLocal, const TUint8* aRemote, TInt aLength, TInt aMode, const TDesC* aPanicCat, TInt aResult, TInt aLine)
1.275 + {
1.276 + TPtr8 local((TUint8*)aLocal,aLength,aLength);
1.277 + TPtr8 remote((TUint8*)aRemote,aLength,aLength);
1.278 + _DoIpcTest(&local,&remote,0,aMode,aPanicCat,aResult,aLine);
1.279 + }
1.280 +
1.281 +void DoIpcTest(const TUint8* aLocal, const TDesC8& aRemote, TInt aLength, TInt aMode, const TDesC* aPanicCat, TInt aResult, TInt aLine)
1.282 + {
1.283 + TPtr8 local((TUint8*)aLocal,aLength,aLength);
1.284 + _DoIpcTest(&local,&aRemote,0,aMode,aPanicCat,aResult,aLine);
1.285 + }
1.286 +
1.287 +void TestIpcCopyErrors()
1.288 + {
1.289 + RChunk c;
1.290 + TInt r=c.CreateDisconnectedLocal(0,0,0x500000);
1.291 + test(r==KErrNone);
1.292 + r=c.Commit(0,0x1000);
1.293 + test(r==KErrNone);
1.294 + r=c.Commit(0x2000,0x1000);
1.295 + test(r==KErrNone);
1.296 + r=c.Commit(0x3ff000,0x1000);
1.297 + test(r==KErrNone);
1.298 + Disc=c.Base();
1.299 + test.Printf(_L("Disc=%08x\n"),Disc);
1.300 + DoIpcTest(Buffer,(const TUint8*)&TestEq,100,0,NULL,KErrNone,__LINE__);
1.301 + DoIpcTest(Buffer,(const TUint8*)&TestEq,100,2,NULL,KErrBadDescriptor,__LINE__);
1.302 + DoIpcTest((const TUint8*)&TestEq,Buffer,100,2,NULL,KErrNone,__LINE__);
1.303 + DoIpcTest((const TUint8*)&TestEq,Buffer,100,0,&KLitKernExec,ECausedException,__LINE__);
1.304 + DoIpcTest(Buffer,Nonexistent,100,0,NULL,KErrBadDescriptor,__LINE__);
1.305 + DoIpcTest(Buffer,Nonexistent,100,2,NULL,KErrBadDescriptor,__LINE__);
1.306 + DoIpcTest(Nonexistent,Buffer,100,2,&KLitKernExec,ECausedException,__LINE__);
1.307 + DoIpcTest(Nonexistent,Buffer,100,0,&KLitKernExec,ECausedException,__LINE__);
1.308 + DoIpcTest(Buffer,Unaligned,100,0,NULL,KErrNone,__LINE__);
1.309 + DoIpcTest(Buffer,Unaligned,100,2,NULL,KErrNone,__LINE__);
1.310 + DoIpcTest(Unaligned,Buffer,100,2,NULL,KErrNone,__LINE__);
1.311 + DoIpcTest(Unaligned,Buffer,100,0,NULL,KErrNone,__LINE__);
1.312 +
1.313 + DoIpcTest(Disc+4001,Buffer,95,0,NULL,KErrNone,__LINE__);
1.314 + if (HaveVirtMem())
1.315 + DoIpcTest(Disc+4001,Buffer,96,0,&KLitKernExec,ECausedException,__LINE__);
1.316 + DoIpcTest(Buffer,Disc+4001,95,0,NULL,KErrNone,__LINE__);
1.317 + if (HaveVirtMem())
1.318 + DoIpcTest(Buffer,Disc+4001,96,0,NULL,KErrBadDescriptor,__LINE__);
1.319 +
1.320 + TPtr8* pdes;
1.321 + if (HaveVirtMem())
1.322 + {
1.323 + // test descriptor stored stradling chunk end...
1.324 + pdes = (TPtr8*)(Disc+0x3ffff4);
1.325 + memcpy(pdes,&UserDes,12);
1.326 + DoIpcTest(Buffer,*pdes,pdes->Size(),0,NULL,KErrNone,__LINE__);
1.327 + pdes = (TPtr8*)(Disc+0x3ffff8);
1.328 + memcpy(pdes,&UserDes,8);
1.329 + DoIpcTest(Buffer,*pdes,pdes->Size(),0,NULL,KErrBadDescriptor,__LINE__);
1.330 + pdes = (TPtr8*)(Disc+0x3ffffc);
1.331 + memcpy(pdes,&UserDes,4);
1.332 + DoIpcTest(Buffer,*pdes,pdes->Size(),0,NULL,KErrBadDescriptor,__LINE__);
1.333 + r=c.Commit(0x400000,0x1000);
1.334 + test(r==KErrNone);
1.335 + pdes = (TPtr8*)(Disc+0x3ffff4);
1.336 + memcpy(pdes,&UserDes,12);
1.337 + DoIpcTest(Buffer,*pdes,pdes->Size(),0,NULL,KErrNone,__LINE__);
1.338 + pdes = (TPtr8*)(Disc+0x3ffff8);
1.339 + memcpy(pdes,&UserDes,12);
1.340 + DoIpcTest(Buffer,*pdes,pdes->Size(),0,NULL,KErrNone,__LINE__);
1.341 + pdes = (TPtr8*)(Disc+0x3ffffc);
1.342 + memcpy(pdes,&UserDes,12);
1.343 + DoIpcTest(Buffer,*pdes,pdes->Size(),0,NULL,KErrNone,__LINE__);
1.344 + }
1.345 +
1.346 + if (HaveMultAddr())
1.347 + {
1.348 + if(RamDrive)
1.349 + {
1.350 + DoIpcTest(Disc+0x100000,Buffer,96,0,&KLitKernExec,ECausedException,__LINE__);
1.351 + DoIpcTest(Buffer,Disc+0x100000,96,0,NULL,KErrBadDescriptor,__LINE__);
1.352 + DoIpcTest(RamDrive,Buffer,4,0,&KLitKernExec,ECausedException,__LINE__);
1.353 + DoIpcTest(Buffer,RamDrive,4,0,NULL,KErrBadDescriptor,__LINE__);
1.354 + DoIpcTest(RamDrive,Buffer,4,2,&KLitKernExec,ECausedException,__LINE__);
1.355 + DoIpcTest(Buffer,RamDrive,4,2,NULL,KErrBadDescriptor,__LINE__);
1.356 + }
1.357 +
1.358 + // if memory alising happens during IPC then the memory at 'Disc' would be aliased
1.359 + // at KIPCAliasAddress and so would not be protected by MMU permission checks.
1.360 + // However, the kernel should still prevent this, to avoid degrading process
1.361 + // protection for memory in other parts of the alias region.
1.362 +#ifdef __CPU_X86
1.363 + const TUint8* KIPCAliasAddress;
1.364 + if((MemModelAttributes()&EMemModelTypeMask) == EMemModelTypeFlexible)
1.365 + KIPCAliasAddress = (TUint8*)0x7e000000;
1.366 + else
1.367 + KIPCAliasAddress = (TUint8*)0xc0400000;
1.368 +#else
1.369 + const TUint8* KIPCAliasAddress = (TUint8*)0x00200000;
1.370 +#endif
1.371 + DoIpcTest(KIPCAliasAddress,Disc,4,0,&KLitKernExec,ECausedException,__LINE__);
1.372 + DoIpcTest(Disc,KIPCAliasAddress,4,0,NULL,KErrBadDescriptor,__LINE__);
1.373 + DoIpcTest(KIPCAliasAddress,Disc,4,2,&KLitKernExec,ECausedException,__LINE__);
1.374 + DoIpcTest(Disc,KIPCAliasAddress,4,2,NULL,KErrBadDescriptor,__LINE__);
1.375 + }
1.376 +
1.377 + if (HaveIPCKernProt())
1.378 + {
1.379 + DoIpcTest(Kern,Buffer,96,0,&KLitKernExec,ECausedException,__LINE__);
1.380 + DoIpcTest(Buffer,Kern,96,0,NULL,KErrBadDescriptor,__LINE__);
1.381 + TUint8* addrRW = (TUint8*)HwChunkAddr[RIpcCpy::EHwChunkSupRw];
1.382 + if(addrRW)
1.383 + {
1.384 + DoIpcTest(Buffer,*(TDes8*)addrRW,96,0,NULL,KErrBadDescriptor,__LINE__);
1.385 + DoIpcTest(Buffer,*(TDes8*)addrRW,96,2,NULL,KErrBadDescriptor,__LINE__);
1.386 + DoIpcTest(addrRW+96,Buffer,96,0,&KLitKernExec,ECausedException,__LINE__);
1.387 + DoIpcTest(Buffer,addrRW,96,0,NULL,KErrBadDescriptor,__LINE__);
1.388 + DoIpcTest(addrRW+96,Buffer,96,2,&KLitKernExec,ECausedException,__LINE__);
1.389 + DoIpcTest(Buffer,addrRW,96,2,NULL,KErrBadDescriptor,__LINE__);
1.390 + }
1.391 + }
1.392 +
1.393 + if((MemModelAttributes()&EMemModelTypeMask) == EMemModelTypeMultiple
1.394 + || (MemModelAttributes()&EMemModelTypeMask) == EMemModelTypeFlexible
1.395 + )
1.396 + {
1.397 + // On multiple memory model, test IPC to Hardware Chunks.
1.398 + // IPC to hardware chunks not supported on Moving Memory
1.399 + TUint8* addrRW = (TUint8*)HwChunkAddr[RIpcCpy::EHwChunkUserRw];
1.400 + if(addrRW)
1.401 + {
1.402 + DoIpcTest(Buffer,*(TDes8*)addrRW,96,0,NULL,KErrNone,__LINE__);
1.403 + DoIpcTest(Buffer,*(TDes8*)addrRW,96,2,NULL,KErrNone,__LINE__);
1.404 + DoIpcTest(addrRW+96,Buffer,96,0,NULL,KErrNone,__LINE__);
1.405 + DoIpcTest(Buffer,addrRW,96,0,NULL,KErrNone,__LINE__);
1.406 + DoIpcTest(addrRW+96,Buffer,96,2,NULL,KErrNone,__LINE__);
1.407 + DoIpcTest(Buffer,addrRW,96,2,NULL,KErrNone,__LINE__);
1.408 + DoIpcTest(addrRW+96,addrRW,96,0,NULL,KErrNone,__LINE__);
1.409 + DoIpcTest(addrRW+96,addrRW,96,2,NULL,KErrNone,__LINE__);
1.410 + }
1.411 + TUint8* addrRO = (TUint8*)HwChunkAddr[RIpcCpy::EHwChunkUserRo];
1.412 + if(addrRO && HaveWriteProt())
1.413 + {
1.414 + DoIpcTest(Buffer,*(TDes8*)addrRO,96,0,NULL,KErrNone,__LINE__);
1.415 + DoIpcTest(Buffer,*(TDes8*)addrRO,96,2,&KLitKernExec,EBadIpcDescriptor,__LINE__);
1.416 + DoIpcTest(addrRO+96,Buffer,96,0,&KLitKernExec,ECausedException,__LINE__);
1.417 + DoIpcTest(Buffer,addrRO,96,0,NULL,KErrNone,__LINE__);
1.418 + DoIpcTest(addrRO+96,Buffer,96,2,NULL,KErrNone,__LINE__);
1.419 + DoIpcTest(Buffer,addrRO,96,2,NULL,KErrBadDescriptor,__LINE__);
1.420 + DoIpcTest(addrRW+96,addrRO,96,0,NULL,KErrNone,__LINE__);
1.421 + DoIpcTest(addrRW+96,addrRW,96,2,NULL,KErrNone,__LINE__);
1.422 + DoIpcTest(addrRO+96,addrRO,96,0,&KLitKernExec,ECausedException,__LINE__);
1.423 + DoIpcTest(addrRO+96,addrRW,96,2,NULL,KErrNone,__LINE__);
1.424 + }
1.425 + }
1.426 +
1.427 + c.Close();
1.428 + }
1.429 +
1.430 +RMessage2 Msg1, Msg2;
1.431 +
1.432 +TInt SendAndExit(TAny* aPtr)
1.433 + {
1.434 + RLocalSession sess;
1.435 + TInt r=sess.Connect(IpcServer,NULL);
1.436 + if (r!=KErrNone)
1.437 + return r;
1.438 + sess.Test(aPtr);
1.439 + sess.Wait();
1.440 + sess.Close();
1.441 + User::AfterHighRes(1000*CloseTime);
1.442 + Msg1.Complete(0); // complete my own message! - this removes message reference to thread
1.443 + return 0;
1.444 + }
1.445 +
1.446 +void TestIpcAsyncClose()
1.447 + {
1.448 +
1.449 + // Create a 16MB chunk
1.450 + const TInt desSize = 8*1024*1024;
1.451 + RChunk chunk;
1.452 + test(chunk.CreateLocal(2 * desSize, 2 * desSize) == KErrNone);
1.453 + test(chunk.Adjust(2 * desSize) == KErrNone);
1.454 +
1.455 + TUint8* bigBuf=chunk.Base();
1.456 + test(bigBuf!=NULL);
1.457 + TUint8* bigBuf2=chunk.Base() + desSize;
1.458 + test(bigBuf2!=NULL);
1.459 + TPtr8 bigBufPtr(bigBuf, desSize, desSize);
1.460 + TPtr8 bigBufPtr2(bigBuf2, 0, desSize);
1.461 +
1.462 + if (IpcServer.Handle())
1.463 + IpcServer.Close();
1.464 + TESTEQ(IpcServer.CreateGlobal(KNullDesC),KErrNone);
1.465 +
1.466 + RThread t;
1.467 + TInt r=t.Create(KNullDesC,SendAndExit,0x1000,NULL,&bigBufPtr);
1.468 + test(r==KErrNone);
1.469 + TFullName fn(t.FullName());
1.470 + TRequestStatus s;
1.471 + t.Logon(s);
1.472 + t.SetPriority(EPriorityMuchMore);
1.473 + t.Resume();
1.474 +
1.475 + IpcServer.Receive(Msg1); // connect
1.476 + Msg1.Complete(KErrNone);
1.477 + IpcServer.Receive(Msg1); // test message
1.478 + IpcServer.Receive(Msg2); // wait/synch message
1.479 + TUint32 initial = User::NTickCount();
1.480 + r=Msg1.Read(2,bigBufPtr2,0); // arg2 is writable 8 bit descriptor
1.481 + TUint32 final = User::NTickCount();
1.482 + TUint32 elapsed = final - initial;
1.483 + if (elapsed<3)
1.484 + test.Printf(_L("*** WARNING! The big IPC only took %dms, which means the next test might fail! \n"),elapsed);
1.485 + else
1.486 + test.Printf(_L("Big IPC took %dms\n"),elapsed);
1.487 + CloseTime = (TInt)(elapsed>>2);
1.488 + Msg2.Complete(0);
1.489 + IpcServer.Receive(Msg2); // disconnect
1.490 + TUint32 disconnect = User::NTickCount();
1.491 +
1.492 + // We expect this IPC read to fail part way through
1.493 + r=Msg1.Read(2,bigBufPtr2,0); // arg2 is writable 8 bit descriptor
1.494 + test.Printf(_L("counters: initial=%d final=%d disconnect=%d current=%d\n"),initial,final,disconnect,User::NTickCount());
1.495 + test.Printf(_L("2nd Big IPC returned %d\n"),r);
1.496 + test(r==KErrDied);
1.497 + test(Msg1.IsNull());
1.498 + Msg2.Complete(0); // complete session closure as well
1.499 + User::WaitForRequest(s);
1.500 + test(s==KErrNone);
1.501 + CLOSE_AND_WAIT(t);
1.502 + test(t.Open(fn)==KErrNotFound);
1.503 + IpcServer.Close();
1.504 +
1.505 + // t already closed
1.506 +// User::Free(bigBuf);
1.507 +// User::Free(bigBuf2);
1.508 + chunk.Close();
1.509 + }
1.510 +
1.511 +void BenchmarkTest()
1.512 + {
1.513 + TAny* bigbuf = User::Alloc(65536);
1.514 + test(bigbuf != NULL);
1.515 + TInt i;
1.516 + TUint32 initial, final;
1.517 + initial = User::NTickCount();
1.518 + for (i=0; i<1000; ++i)
1.519 + Ipccpy.BigWrite(bigbuf, 0);
1.520 + final = User::NTickCount();
1.521 + TUint32 wcal = final - initial;
1.522 + initial = User::NTickCount();
1.523 + for (i=0; i<1000; ++i)
1.524 + Ipccpy.BigWrite(bigbuf, 65536);
1.525 + final = User::NTickCount();
1.526 + TUint32 write = final - initial;
1.527 + test.Printf(_L("64K user->kernel copy takes %d us\n"), write - wcal);
1.528 + initial = User::NTickCount();
1.529 + for (i=0; i<1000; ++i)
1.530 + Ipccpy.BigRead(bigbuf, 0);
1.531 + final = User::NTickCount();
1.532 + TUint32 rcal = final - initial;
1.533 + initial = User::NTickCount();
1.534 + for (i=0; i<1000; ++i)
1.535 + Ipccpy.BigRead(bigbuf, 65536);
1.536 + final = User::NTickCount();
1.537 + TUint32 read = final - initial;
1.538 + test.Printf(_L("64K kernel->user copy takes %d us\n"), read - rcal);
1.539 + User::Free(bigbuf);
1.540 +// User::After(10*1000*1000);
1.541 + }
1.542 +
1.543 +
1.544 +RMessage2 IpcMesage;
1.545 +const TInt KTestChunkSize = 1024*1024;
1.546 +const TInt KReadSize = 4096;
1.547 +
1.548 +TInt IpcMultipleAliasesThread(TAny* aBuffer)
1.549 + {
1.550 + TBuf8<KReadSize> data;
1.551 + TAny** dataStart = (TAny**)data.Ptr();
1.552 + TAny** dataEnd = (TAny**)(data.Ptr()+KReadSize-sizeof(TAny*));
1.553 + for(;;)
1.554 + {
1.555 + TInt offset;
1.556 + for(offset=0; offset<KTestChunkSize; offset+=KReadSize)
1.557 + {
1.558 + TInt r = IpcMesage.Read(0,data,offset);
1.559 + if(r!=KErrNone)
1.560 + return r;
1.561 + if(data.Size()!=KReadSize)
1.562 + return 1;
1.563 + TAny* expected = (TAny*)((TInt)aBuffer+offset);
1.564 + if(*dataStart != expected)
1.565 + {
1.566 + RDebug::Printf("Offset=%x, expected %x but read %x",offset,expected,*dataStart);
1.567 + return 2;
1.568 + }
1.569 + expected = (TAny*)((TInt)aBuffer+offset+KReadSize-sizeof(TAny*));
1.570 + if(*dataEnd != expected)
1.571 + {
1.572 + RDebug::Printf("Offset=%x, expected %x but read %x",offset,expected,*dataEnd);
1.573 + return 3;
1.574 + }
1.575 + }
1.576 + }
1.577 + }
1.578 +
1.579 +/*
1.580 +This tests exercises the situation where multiple threads are doing IPC simultaneousely.
1.581 +On the Multiple Memory Model, this aims to test the per-thread memory aliasing code.
1.582 +(DMemModelThread::Alias and company)
1.583 +*/
1.584 +void TestIpcMultipleThreads()
1.585 + {
1.586 + test.Start(_L("Test Multiple Threads IPC"));
1.587 +
1.588 + // create chunk for threads to do IPC from...
1.589 + RChunk chunk;
1.590 + TESTEQ(chunk.CreateLocal(KTestChunkSize,KTestChunkSize),KErrNone);
1.591 + TAny** buffer = (TAny**)chunk.Base();
1.592 + TAny** bufferEnd = (TAny**)((TInt)buffer+KTestChunkSize);
1.593 + for(; buffer<bufferEnd; ++buffer)
1.594 + *buffer=buffer;
1.595 +
1.596 + // create a server message which test threads can use to do IPC memory operations
1.597 + if (IpcServer.Handle())
1.598 + IpcServer.Close();
1.599 + TESTEQ(IpcServer.CreateGlobal(KNullDesC),KErrNone);
1.600 + RLocalSession sess;
1.601 + TRequestStatus stat;
1.602 + TESTEQ(sess.Connect(IpcServer,&stat),KErrNone);
1.603 + RMessage2 m;
1.604 + IpcServer.Receive(m);
1.605 + m.Complete(KErrNone); // connect
1.606 + User::WaitForRequest(stat); // connection message report
1.607 + TAny* ptrMem = User::Alloc(0x2000);
1.608 + TPtr8* pptr = (TPtr8*)(((TInt)ptrMem&~0xfff)+0x1000-sizeof(TInt));
1.609 + new (pptr) TPtr8(chunk.Base(),KTestChunkSize,KTestChunkSize); // create a TPtr8 which straddles a page boundary
1.610 + sess.Test(pptr);
1.611 + IpcServer.Receive(IpcMesage);
1.612 +
1.613 + // create some test threads...
1.614 + const TInt KNumIpcThreads = 10;
1.615 + RThread threads[KNumIpcThreads];
1.616 + TRequestStatus stats[KNumIpcThreads];
1.617 + TInt i;
1.618 + for(i=0; i<KNumIpcThreads; i++)
1.619 + {
1.620 + TESTEQ(threads[i].Create(KNullDesC,IpcMultipleAliasesThread,KReadSize+0x1000,&User::Allocator(),chunk.Base()),KErrNone);
1.621 + threads[i].Logon(stats[i]);
1.622 + }
1.623 + test.Printf(_L("Resuming threads...\n"));
1.624 + for(i=0; i<KNumIpcThreads; i++)
1.625 + threads[i].Resume();
1.626 +
1.627 + User::After(10*1000000);
1.628 + for(i=0; i<KNumIpcThreads; i++)
1.629 + {
1.630 + test(stats[i]==KRequestPending); // theads should still be running
1.631 + }
1.632 +
1.633 + // close chunk whilst test threads are still doing IPC...
1.634 + test.Printf(_L("Closing chunk...\n"));
1.635 + chunk.Close();
1.636 + for(i=0; i<KNumIpcThreads; i++)
1.637 + {
1.638 + User::WaitForRequest(stats[i]);
1.639 + TInt r=stats[i].Int();
1.640 + test.Printf(_L("Thread %d result = %d\n"),i,r);
1.641 + test(r==KErrBadDescriptor);
1.642 + }
1.643 +
1.644 + IpcServer.Close();
1.645 + User::Free(ptrMem);
1.646 + test.End();
1.647 + }
1.648 +
1.649 +GLDEF_C TInt E32Main()
1.650 + {
1.651 + MainId=TUint32(RThread().Id());
1.652 +// RThread().SetPriority(EPriorityAbsoluteForeground);
1.653 + test.Title();
1.654 + test.Start(_L("Load LDD"));
1.655 + TInt r=User::LoadLogicalDevice(_L("D_IPCCPY"));
1.656 + test(r==KErrNone || r==KErrAlreadyExists);
1.657 + test.Next(_L("Open channel"));
1.658 + r=Ipccpy.Open();
1.659 + test(r==KErrNone);
1.660 + test.Next(_L("Allocate heap buffer"));
1.661 + Buffer=(TUint8*)User::Alloc(4096);
1.662 + test(Buffer!=NULL);
1.663 + SetupAddresses();
1.664 +
1.665 + BenchmarkTest();
1.666 +
1.667 + TestIpcCopyErrors();
1.668 + TestIpcAsyncClose();
1.669 + TestIpcMultipleThreads();
1.670 +
1.671 + FOREVER
1.672 + {
1.673 + TRequestStatus s;
1.674 + Mem::Fill(Buffer,272,0xcd);
1.675 + TPtr8 ptr(Buffer,0,272);
1.676 + Ipccpy.IpcCpy(s,ptr);
1.677 + User::WaitForRequest(s);
1.678 + TInt x=s.Int();
1.679 + if (x<0)
1.680 + {
1.681 + test.Printf(_L("Error %d\n"),x);
1.682 + test(0);
1.683 + }
1.684 + TInt src_offset=x&3;
1.685 + TInt dest_offset=(x>>2)&3;
1.686 + TInt length=(x>>4)+1;
1.687 + TInt err=-1;
1.688 + TInt i;
1.689 + for (i=0; i<dest_offset && err<0; ++i)
1.690 + {
1.691 + if (Buffer[i]!=0xcd)
1.692 + err=i;
1.693 + }
1.694 + TUint8 v=(TUint8)src_offset;
1.695 + for (i=0; i<length && err<0; ++i)
1.696 + {
1.697 + ++v;
1.698 + if (Buffer[i+dest_offset]!=v)
1.699 + err=i+dest_offset;
1.700 + }
1.701 + for (i=dest_offset+length; i<272 && err<0; ++i)
1.702 + {
1.703 + if (Buffer[i]!=0xcd)
1.704 + err=i;
1.705 + }
1.706 + if (err>=0)
1.707 + {
1.708 + test.Printf(_L("Sequence number %03x\nSrcOffset %d, DestOffset %d, Length %d\n"),x,src_offset,dest_offset,length);
1.709 + test.Printf(_L("First error at %d"),err);
1.710 + for (i=0; i<272; i+=16)
1.711 + {
1.712 + TInt j;
1.713 + test.Printf(_L("%03x:"),i);
1.714 + for (j=0; j<16; ++j)
1.715 + {
1.716 + test.Printf(_L(" %02x"),Buffer[i+j]);
1.717 + }
1.718 + }
1.719 + test(0);
1.720 + }
1.721 + if (x==4095)
1.722 + break;
1.723 + }
1.724 + Ipccpy.Close();
1.725 + test.End();
1.726 + return KErrNone;
1.727 + }