|
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 } |