|
1 /* |
|
2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of the License "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 /** |
|
20 Overview: |
|
21 Test DLL Writeable Static Data support |
|
22 |
|
23 API Information: |
|
24 |
|
25 |
|
26 Details: |
|
27 - Each process has independent DLL WSD |
|
28 - Whether DLL linked directly or indirectly |
|
29 - Whether DLL loaded dynamically or statically |
|
30 - DLL WSD is consistent under heavy usage by multiple processes |
|
31 - IPC works to/from DLL WSD descriptors & TRequestStatus |
|
32 This source file builds in 4 configurations, with each of |
|
33 direct and indirect linking either used or not used. |
|
34 These configurations are set by 4 MM files, t_dllwsd[d][i].mmp |
|
35 Any of the exe created from the MMP files can be started |
|
36 to run the tests, it does not matter which is used. |
|
37 All exe configurations will be used during the tests. |
|
38 |
|
39 Platforms/Drives/Compatibility: |
|
40 All. |
|
41 |
|
42 Assumptions/Requirement/Pre-requisites: |
|
43 |
|
44 |
|
45 Failures and causes: |
|
46 |
|
47 |
|
48 Base Port information: |
|
49 |
|
50 */ |
|
51 |
|
52 #define __E32TEST_EXTENSION__ |
|
53 |
|
54 #include <e32test.h> |
|
55 #include <e32svr.h> |
|
56 #include <f32dbg.h> |
|
57 #include <u32std.h> |
|
58 #include "t_dllwsd_dll.h" |
|
59 #include "t_dllwsd_dlli.h" |
|
60 |
|
61 |
|
62 LOCAL_D RTest test(_L("T_DLLWSD")); |
|
63 |
|
64 enum TTestFunc |
|
65 { |
|
66 ETestFuncTestCons=1, |
|
67 ETestFuncThrash1, |
|
68 ETestFuncIpcTest, |
|
69 ETestFuncIpcGet, |
|
70 ETestFuncIpcReverse, |
|
71 ETestFuncIpcSet, |
|
72 ETestFuncPanic, |
|
73 }; |
|
74 |
|
75 // Test session for IPC use of WSD, talks to the same server as RDllWsd |
|
76 class RIpcTestSession : public RSessionBase |
|
77 { |
|
78 public: |
|
79 TInt Connect() |
|
80 { |
|
81 return CreateSession(_L("IpcTestServer"), TVersion()); |
|
82 } |
|
83 void Get(TBuf<60000>& buf, TRequestStatus& req) |
|
84 { |
|
85 SendReceive(ETestFuncIpcGet, TIpcArgs(&buf), req); |
|
86 } |
|
87 void Reverse(TRequestStatus& req) |
|
88 { |
|
89 SendReceive(ETestFuncIpcReverse, req); |
|
90 } |
|
91 void Set(const TBuf<60000>& buf, TRequestStatus& req) |
|
92 { |
|
93 SendReceive(ETestFuncIpcSet, TIpcArgs(&buf), req); |
|
94 } |
|
95 }; |
|
96 |
|
97 #ifdef T_DLLWSD_DIRECT |
|
98 void FillBuf(TInt start, TInt inc) |
|
99 { |
|
100 for (int ii=0; ii<WsdBuf().Length(); ii++) |
|
101 { |
|
102 WsdBuf()[ii] = (unsigned short)start; |
|
103 start += inc; |
|
104 } |
|
105 } |
|
106 |
|
107 TInt CheckBuf(TInt start, TInt inc) |
|
108 { |
|
109 for (int ii=0; ii<WsdBuf().Length(); ii++) |
|
110 { |
|
111 if (WsdBuf()[ii] != start) |
|
112 return KErrGeneral; |
|
113 start += inc; |
|
114 } |
|
115 return KErrNone; |
|
116 } |
|
117 #endif |
|
118 |
|
119 class CDllWsdServer : public CServer2 |
|
120 { |
|
121 public: |
|
122 CDllWsdServer() : CServer2(EPriorityStandard) |
|
123 { |
|
124 } |
|
125 CSession2* NewSessionL(const TVersion& /*aVersion*/,const RMessage2& /*aMessage*/) const; |
|
126 mutable TInt iCount; |
|
127 }; |
|
128 |
|
129 class CDllWsdSession : public CSession2 |
|
130 { |
|
131 public: |
|
132 CDllWsdSession() |
|
133 { |
|
134 ResetConsistencyCheck(); |
|
135 } |
|
136 |
|
137 ~CDllWsdSession() |
|
138 { |
|
139 // transient server immediate shutdown when last client disconnects |
|
140 if (--((CDllWsdServer*)Server())->iCount == 0) |
|
141 CActiveScheduler::Stop(); |
|
142 } |
|
143 |
|
144 void ResetConsistencyCheck() |
|
145 { |
|
146 iX=42; |
|
147 iY=0; |
|
148 } |
|
149 |
|
150 void OptResetConsistencyCheck() |
|
151 { |
|
152 #if !defined(T_DLLWSD_DIRECT) && !defined(T_DLLWSD_INDIRECT) |
|
153 // if DLL has been unloaded (dynamic library closed, no static link) |
|
154 // WSD will be reset |
|
155 ResetConsistencyCheck(); |
|
156 #endif |
|
157 } |
|
158 |
|
159 TInt TestConsistency() |
|
160 { |
|
161 #ifdef T_DLLWSD_DIRECT |
|
162 // static direct |
|
163 if (WsdFuncX() != iX++) |
|
164 return KErrGeneral; |
|
165 if (WsdFuncY() != iY++) |
|
166 return KErrGeneral; |
|
167 #endif |
|
168 |
|
169 #ifdef T_DLLWSD_INDIRECT |
|
170 // static indirect |
|
171 if (IndWsdFuncX() != iX++) |
|
172 return KErrGeneral; |
|
173 if (IndWsdFuncY() != iY++) |
|
174 return KErrGeneral; |
|
175 #endif |
|
176 |
|
177 // dynamic direct |
|
178 OptResetConsistencyCheck(); |
|
179 RLibrary lib; |
|
180 TInt err = lib.Load(_L("t_dllwsd_dll")); |
|
181 if (err) return err; |
|
182 if ((*lib.Lookup(1))/*WsdFuncX*/() != iX++) |
|
183 return KErrGeneral; |
|
184 if ((*lib.Lookup(2))/*WsdFuncX*/() != iY++) |
|
185 return KErrGeneral; |
|
186 lib.Close(); |
|
187 |
|
188 // dynamic indirect |
|
189 OptResetConsistencyCheck(); |
|
190 err = lib.Load(_L("t_dllwsd_dlli")); |
|
191 if (err) return err; |
|
192 if ((*lib.Lookup(1))/*IndWsdFuncX*/() != iX++) |
|
193 return KErrGeneral; |
|
194 if ((*lib.Lookup(2))/*IndWsdFuncX*/() != iY++) |
|
195 return KErrGeneral; |
|
196 lib.Close(); |
|
197 |
|
198 return KErrNone; |
|
199 } |
|
200 |
|
201 TInt Thrash1() |
|
202 { |
|
203 TTime start; |
|
204 start.HomeTime(); |
|
205 TInt count = 0; |
|
206 const TTimeIntervalMicroSeconds limit(10000000); // 10 seconds |
|
207 for (;; count++) |
|
208 { |
|
209 TInt err = TestConsistency(); |
|
210 if (err) return err; |
|
211 TTime now; |
|
212 now.HomeTime(); |
|
213 if (now.MicroSecondsFrom(start) > limit) |
|
214 break; |
|
215 } |
|
216 return count > 0 ? count : -count; |
|
217 } |
|
218 |
|
219 TInt IpcTest() |
|
220 { |
|
221 #ifdef T_DLLWSD_DIRECT |
|
222 RIpcTestSession s; |
|
223 TInt err = s.Connect(); |
|
224 if (!err) return err; |
|
225 WsdBuf().SetLength(WsdBuf().MaxLength()); |
|
226 for (int i=0; i<10; i++) |
|
227 { |
|
228 // 0..n -> buf |
|
229 FillBuf(0,1); |
|
230 err = CheckBuf(0,1); |
|
231 if (!err) return err; |
|
232 |
|
233 // buf -> server |
|
234 s.Set(WsdBuf(), WsdReq()); |
|
235 err = CheckBuf(0,1); |
|
236 if (!err) return err; |
|
237 |
|
238 // use TReqestStatus in WSD |
|
239 User::WaitForRequest(WsdReq()); |
|
240 if (!WsdReq().Int()) return WsdReq().Int(); |
|
241 |
|
242 // 0..0 -> buf |
|
243 FillBuf(0,0); |
|
244 err = CheckBuf(0,0); |
|
245 if (!err) return err; |
|
246 WsdReq() = KRequestPending; |
|
247 |
|
248 // reverse buf on server |
|
249 s.Reverse(WsdReq()); |
|
250 |
|
251 // local buf is still 0..0 |
|
252 err = CheckBuf(0,0); |
|
253 if (!err) return err; |
|
254 |
|
255 // use TReqestStatus in WSD |
|
256 User::WaitForRequest(WsdReq()); |
|
257 if (!WsdReq().Int()) return WsdReq().Int(); |
|
258 |
|
259 // local buf is still 0..0 |
|
260 err = CheckBuf(0,0); |
|
261 if (!err) return err; |
|
262 |
|
263 // get buf from server |
|
264 s.Get(WsdBuf(), WsdReq()); |
|
265 User::WaitForRequest(WsdReq()); |
|
266 |
|
267 // buf is n..0 |
|
268 err = CheckBuf(59999,-1); |
|
269 if (!err) return err; |
|
270 } |
|
271 s.Close(); |
|
272 return KErrNone; |
|
273 #else |
|
274 return KErrNotSupported; |
|
275 #endif |
|
276 } |
|
277 |
|
278 void ServiceL(const RMessage2& aMessage) |
|
279 { |
|
280 #ifdef T_DLLWSD_DIRECT |
|
281 TInt ii=0; |
|
282 #endif |
|
283 switch (aMessage.Function()) |
|
284 { |
|
285 case ETestFuncTestCons: |
|
286 aMessage.Complete(TestConsistency()); |
|
287 break; |
|
288 case ETestFuncThrash1: |
|
289 aMessage.Complete(Thrash1()); |
|
290 break; |
|
291 case ETestFuncIpcTest: |
|
292 aMessage.Complete(IpcTest()); |
|
293 break; |
|
294 case ETestFuncIpcGet: |
|
295 #ifdef T_DLLWSD_DIRECT |
|
296 aMessage.WriteL(0, WsdBuf()); |
|
297 aMessage.Complete(KErrNone); |
|
298 #else |
|
299 aMessage.Complete(KErrNotSupported); |
|
300 #endif |
|
301 break; |
|
302 case ETestFuncIpcReverse: |
|
303 #ifdef T_DLLWSD_DIRECT |
|
304 for (ii=0; ii<WsdBuf().Length()/2; ii++) |
|
305 { |
|
306 TInt o = WsdBuf().Length() - 1 - ii; |
|
307 TInt t = WsdBuf()[ii]; |
|
308 WsdBuf()[ii] = WsdBuf()[o]; |
|
309 WsdBuf()[o] = (unsigned short)t; |
|
310 } |
|
311 aMessage.Complete(KErrNone); |
|
312 #else |
|
313 aMessage.Complete(KErrNotSupported); |
|
314 #endif |
|
315 break; |
|
316 case ETestFuncIpcSet: |
|
317 #ifdef T_DLLWSD_DIRECT |
|
318 aMessage.ReadL(0, WsdBuf()); |
|
319 aMessage.Complete(KErrNone); |
|
320 #else |
|
321 aMessage.Complete(KErrNotSupported); |
|
322 #endif |
|
323 break; |
|
324 case ETestFuncPanic: |
|
325 User::Panic(_L("As requested..."), 0); |
|
326 break; |
|
327 default: |
|
328 aMessage.Panic(_L("Unrecognised"), aMessage.Function()); |
|
329 break; |
|
330 } |
|
331 } |
|
332 |
|
333 int iX; |
|
334 int iY; |
|
335 }; |
|
336 |
|
337 CSession2* CDllWsdServer::NewSessionL(const TVersion& /*aVersion*/,const RMessage2& /*aMessage*/) const |
|
338 { |
|
339 iCount++; |
|
340 return new(ELeave) CDllWsdSession; |
|
341 } |
|
342 |
|
343 TInt SlaveMain() |
|
344 { |
|
345 TName name; |
|
346 User::CommandLine(name); |
|
347 |
|
348 CTrapCleanup* cleanup = CTrapCleanup::New(); |
|
349 if (!cleanup) |
|
350 return KErrNoMemory; |
|
351 |
|
352 TRAPD(err, |
|
353 { |
|
354 CActiveScheduler* sched=new(ELeave) CActiveScheduler; |
|
355 CActiveScheduler::Install(sched); |
|
356 |
|
357 CDllWsdServer* server = new(ELeave) CDllWsdServer; |
|
358 server->StartL(name); |
|
359 |
|
360 RProcess::Rendezvous(KErrNone); |
|
361 CActiveScheduler::Start(); |
|
362 |
|
363 delete server; |
|
364 delete sched; |
|
365 }); |
|
366 delete cleanup; |
|
367 |
|
368 return err; |
|
369 } |
|
370 |
|
371 // |
|
372 // Master test controller |
|
373 // |
|
374 |
|
375 class RDllWsd : public RSessionBase |
|
376 { |
|
377 public: |
|
378 RDllWsd(const TDesC& aServerName, const TDesC& aExeName = _L("t_dllwsddi")) |
|
379 { |
|
380 test.Start(_L("RDllWsd create")); |
|
381 RProcess proc; |
|
382 test_KErrNone(proc.Create(aExeName, aServerName)); |
|
383 TRequestStatus req; |
|
384 proc.Rendezvous(req); |
|
385 proc.Resume(); |
|
386 User::WaitForRequest(req); |
|
387 test_KErrNone(req.Int()); |
|
388 test_KErrNone(CreateSession(aServerName, TVersion())); |
|
389 proc.Close(); |
|
390 test.End(); |
|
391 } |
|
392 TInt ConsistencyTest() |
|
393 { |
|
394 return SendReceive(ETestFuncTestCons); |
|
395 } |
|
396 void ThrashTest1(TRequestStatus& aStatus) |
|
397 { |
|
398 SendReceive(ETestFuncThrash1, aStatus); |
|
399 } |
|
400 TInt IpcTest() |
|
401 { |
|
402 return SendReceive(ETestFuncIpcTest); |
|
403 } |
|
404 TInt Panic() |
|
405 { |
|
406 return SendReceive(ETestFuncPanic); |
|
407 } |
|
408 }; |
|
409 |
|
410 void BasicTest() |
|
411 { |
|
412 test.Start(_L("BasicConsistency")); |
|
413 |
|
414 // create a test server/process for each link variant |
|
415 RDllWsd slaves[] = |
|
416 { |
|
417 RDllWsd(_L("slave1"), _L("t_dllwsd")), |
|
418 RDllWsd(_L("slave2"), _L("t_dllwsdd")), |
|
419 RDllWsd(_L("slave3"), _L("t_dllwsdi")), |
|
420 RDllWsd(_L("slave4"), _L("t_dllwsddi")), |
|
421 RDllWsd(_L("slave5"), _L("t_dllwsd")), |
|
422 RDllWsd(_L("slave6"), _L("t_dllwsdd")), |
|
423 RDllWsd(_L("slave7"), _L("t_dllwsdi")), |
|
424 RDllWsd(_L("slave8"), _L("t_dllwsddi")) |
|
425 }; |
|
426 TInt nSlaves = sizeof(slaves)/sizeof(slaves[0]); |
|
427 TInt ii; |
|
428 // do this a few times |
|
429 for (TInt jj=0; jj<10; jj++) |
|
430 { |
|
431 // all four test variants |
|
432 for (ii=0; ii<nSlaves; ii++) |
|
433 { |
|
434 // repeat the test different numbers of times, to ensure WSD values diverge |
|
435 for (TInt kk=0; kk<ii+2; kk++) |
|
436 { |
|
437 // change order in which processes run the tests |
|
438 int idx = (ii + jj) % nSlaves; |
|
439 test_KErrNone(slaves[idx].ConsistencyTest()); |
|
440 } |
|
441 } |
|
442 // start and stop an extra process |
|
443 RDllWsd extra(_L("slave9"), _L("t_dllwsddi")); |
|
444 test_KErrNone(extra.ConsistencyTest()); |
|
445 extra.Close(); |
|
446 } |
|
447 |
|
448 for (ii=nSlaves-1; ii>=0; ii--) |
|
449 slaves[ii].Close(); |
|
450 |
|
451 test.End(); |
|
452 } |
|
453 |
|
454 void ThrashTest1() |
|
455 { |
|
456 test.Start(_L("ThrashTest1")); |
|
457 |
|
458 // create a test server/process for each link variant |
|
459 RDllWsd slaves[4] = |
|
460 { |
|
461 RDllWsd(_L("slaveA"), _L("t_dllwsd")), |
|
462 RDllWsd(_L("slaveB"), _L("t_dllwsdd")), |
|
463 RDllWsd(_L("slaveC"), _L("t_dllwsdi")), |
|
464 RDllWsd(_L("slaveD"), _L("t_dllwsddi")) |
|
465 }; |
|
466 |
|
467 TRequestStatus req[4]; |
|
468 TInt ii; |
|
469 // start the thrash tests |
|
470 for (ii=0; ii<4; ii++) |
|
471 { |
|
472 slaves[ii].ThrashTest1(req[ii]); |
|
473 test.Printf(_L("slave %d thrash started\n"), ii); |
|
474 } |
|
475 |
|
476 // show some progress to indicate that things are running |
|
477 for (ii=0; ii<8; ii++) |
|
478 { |
|
479 test.Printf(_L("Waiting %d\n"), ii); |
|
480 User::After(1000000); |
|
481 } |
|
482 // demonstrate that test processes are still doing their stuff |
|
483 test.Printf(_L("Still a couple of seconds to wait...\n")); |
|
484 |
|
485 // wait till the test process are done |
|
486 for (ii=0; ii<4; ii++) |
|
487 { |
|
488 User::WaitForRequest(req[ii]); |
|
489 // show how much each process did |
|
490 test.Printf(_L("Slave %d count = %d\n"), ii, req[ii].Int()); |
|
491 test_NotNegative(req[ii].Int()); |
|
492 } |
|
493 |
|
494 for (ii=3; ii>=0; ii--) |
|
495 slaves[ii].Close(); |
|
496 |
|
497 test.End(); |
|
498 } |
|
499 |
|
500 void PanicTest() |
|
501 { |
|
502 test.Start(_L("PanicTest1")); |
|
503 |
|
504 // create a test server/process for each link variant |
|
505 RDllWsd slaves[4] = |
|
506 { |
|
507 RDllWsd(_L("slaveP1"), _L("t_dllwsd")), |
|
508 RDllWsd(_L("slaveP2"), _L("t_dllwsdd")), |
|
509 RDllWsd(_L("slaveP3"), _L("t_dllwsdi")), |
|
510 RDllWsd(_L("slaveP4"), _L("t_dllwsddi")) |
|
511 }; |
|
512 TInt ii; |
|
513 for (ii=0; ii<4; ii++) |
|
514 slaves[ii].Panic(); |
|
515 |
|
516 for (ii=0; ii<4; ii++) |
|
517 slaves[ii].Close(); |
|
518 } |
|
519 |
|
520 void IpcTest() |
|
521 { |
|
522 test.Start(_L("IPC test")); |
|
523 // these two processes will use t_dllwsddi, static link variant |
|
524 RDllWsd server(_L("IpcTestServer")); |
|
525 RDllWsd client(_L("IpcTestClient")); |
|
526 // client will talk to IpcTestServer, ie the server |
|
527 test_KErrNone(client.IpcTest()); |
|
528 client.Close(); |
|
529 server.Close(); |
|
530 test.End(); |
|
531 } |
|
532 |
|
533 TInt MasterMain() |
|
534 { |
|
535 test.Title(); |
|
536 test.Start(_L("Test")); |
|
537 |
|
538 BasicTest(); |
|
539 ThrashTest1(); |
|
540 IpcTest(); |
|
541 // PanicTest(); |
|
542 |
|
543 test.End(); |
|
544 return KErrNone; |
|
545 } |
|
546 |
|
547 TInt E32Main() |
|
548 { |
|
549 if (User::CommandLineLength() > 0) // command line contains server name |
|
550 return SlaveMain(); |
|
551 else |
|
552 return MasterMain(); |
|
553 } |
|
554 |