|
1 // Copyright (c) 2007-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\nkernsa\testdfc.cpp |
|
15 // |
|
16 // |
|
17 |
|
18 #include <nktest/nkutils.h> |
|
19 |
|
20 #ifndef __SMP__ |
|
21 #define iNThreadBaseSpare7 iSpare7 |
|
22 class NSchedulable; |
|
23 #endif |
|
24 |
|
25 extern "C" TUint32 set_bit0_if_nonnull(TUint32&); |
|
26 extern "C" void flip_bit0(TUint32&); |
|
27 extern "C" TUint32 swap_out_if_bit0_clear(TUint32&); |
|
28 |
|
29 #ifdef __SMP__ |
|
30 class TAddDfc : public TGenericIPI |
|
31 #else |
|
32 class TAddDfc : public NTimer |
|
33 #endif |
|
34 { |
|
35 public: |
|
36 TAddDfc(); |
|
37 TDfc* Add(TDfc* aDfc, TUint32 aCpuMask); |
|
38 static TAddDfc* New(); |
|
39 #ifdef __SMP__ |
|
40 static void Isr(TGenericIPI*); |
|
41 #else |
|
42 static void TimerCallBack(TAny*); |
|
43 void WaitCompletion(); |
|
44 #endif |
|
45 public: |
|
46 TDfc* iDfc; |
|
47 }; |
|
48 |
|
49 TAddDfc::TAddDfc() |
|
50 #ifdef __SMP__ |
|
51 : iDfc(0) |
|
52 #else |
|
53 : NTimer(&TimerCallBack, this), |
|
54 iDfc(0) |
|
55 #endif |
|
56 { |
|
57 } |
|
58 |
|
59 TAddDfc* TAddDfc::New() |
|
60 { |
|
61 TAddDfc* p = new TAddDfc; |
|
62 TEST_OOM(p); |
|
63 return p; |
|
64 } |
|
65 |
|
66 #ifdef __SMP__ |
|
67 void TAddDfc::Isr(TGenericIPI* a) |
|
68 #else |
|
69 void TAddDfc::TimerCallBack(TAny* a) |
|
70 #endif |
|
71 { |
|
72 TAddDfc& adder = *(TAddDfc*)a; |
|
73 TDfc* dfc = (TDfc*)__e32_atomic_swp_ord_ptr(&adder.iDfc, 0); |
|
74 if (dfc) |
|
75 dfc->Add(); |
|
76 } |
|
77 |
|
78 TDfc* TAddDfc::Add(TDfc* aDfc, TUint32 aCpuMask) |
|
79 { |
|
80 TDfc* old = (TDfc*)__e32_atomic_swp_ord_ptr(&iDfc, aDfc); |
|
81 #ifdef __SMP__ |
|
82 Queue(&Isr, aCpuMask); |
|
83 #else |
|
84 (void)aCpuMask; |
|
85 OneShot(1); |
|
86 #endif |
|
87 return old; |
|
88 } |
|
89 |
|
90 #ifndef __SMP__ |
|
91 void TAddDfc::WaitCompletion() |
|
92 { |
|
93 while (iDfc) |
|
94 {} |
|
95 } |
|
96 #endif |
|
97 |
|
98 class TTestDfc : public TDfc |
|
99 { |
|
100 public: |
|
101 TTestDfc(TUint aId); |
|
102 TTestDfc(TUint aId, TDfcQue* aQ, TInt aPri); |
|
103 static void Run(TAny* aPtr); |
|
104 |
|
105 static void CheckEmpty(TInt aLine); |
|
106 static void CheckFirstEntry(TInt aLine, TUint32 aCpu, TUint32 aContext, TDfcQue* aQ, TUint32 aId); |
|
107 |
|
108 static CircBuf* Buffer; |
|
109 static volatile TBool Full; |
|
110 static volatile TUint32 Last; |
|
111 |
|
112 enum {EBufferSlots=1024}; |
|
113 }; |
|
114 |
|
115 #define CHECK_EMPTY() TTestDfc::CheckEmpty(__LINE__) |
|
116 #define CHECK_FIRST_ENTRY(cpu, ctx, q, id) TTestDfc::CheckFirstEntry(__LINE__, cpu, ctx, q, id) |
|
117 |
|
118 CircBuf* TTestDfc::Buffer; |
|
119 volatile TBool TTestDfc::Full = FALSE; |
|
120 volatile TUint32 TTestDfc::Last; |
|
121 |
|
122 TTestDfc::TTestDfc(TUint aId) |
|
123 : TDfc(&Run, (TAny*)aId) |
|
124 { |
|
125 } |
|
126 |
|
127 TTestDfc::TTestDfc(TUint aId, TDfcQue* aQ, TInt aPri) |
|
128 : TDfc(&Run, (TAny*)aId, aQ, aPri) |
|
129 { |
|
130 } |
|
131 |
|
132 void TTestDfc::Run(TAny* aPtr) |
|
133 { |
|
134 TUint32 id = (TUint32)aPtr; |
|
135 TUint32 tid = 0; |
|
136 TUint32 ctx = NKern::CurrentContext(); |
|
137 TUint32 cpu = NKern::CurrentCpu(); |
|
138 if (ctx == NKern::EThread) |
|
139 { |
|
140 NThread* t = NKern::CurrentThread(); |
|
141 tid = t->iNThreadBaseSpare7; |
|
142 } |
|
143 TUint32 x = (cpu<<24) | (ctx<<16) | (tid<<8) | id; |
|
144 TInt r = Buffer->TryPut(x); |
|
145 if (r != KErrNone) |
|
146 Full = TRUE; |
|
147 Last = id; |
|
148 } |
|
149 |
|
150 void TTestDfc::CheckEmpty(TInt aLine) |
|
151 { |
|
152 TInt c = Buffer->Count(); |
|
153 TUint32 x; |
|
154 Buffer->TryGet(x); |
|
155 if (c!=0) |
|
156 { |
|
157 TEST_PRINT3("Line %d Buffer not empty C:%d X:%08x", aLine, c, x); |
|
158 } |
|
159 } |
|
160 |
|
161 void TTestDfc::CheckFirstEntry(TInt aLine, TUint32 aCpu, TUint32 aContext, TDfcQue* aQ, TUint32 aId) |
|
162 { |
|
163 TUint32 tid = aQ ? aQ->iThread->iNThreadBaseSpare7 : 0; |
|
164 TUint32 expected = (aCpu<<24) | (aContext<<16) | (tid << 8) | aId; |
|
165 TUint32 x; |
|
166 TInt r = Buffer->TryGet(x); |
|
167 if (r!=KErrNone) |
|
168 { |
|
169 TEST_PRINT2("Line %d Buffer empty, Expected %08x", aLine, expected); |
|
170 } |
|
171 else if (x != expected) |
|
172 { |
|
173 TEST_PRINT3("Line %d Got %08x Expected %08x", aLine, x, expected); |
|
174 } |
|
175 } |
|
176 |
|
177 class TPauseIDFC : public TDfc |
|
178 { |
|
179 public: |
|
180 TPauseIDFC(); |
|
181 void Pause(TInt aCpu); |
|
182 void Release(); |
|
183 static void Run(TAny*); |
|
184 public: |
|
185 volatile TInt iFlag; |
|
186 }; |
|
187 |
|
188 TPauseIDFC::TPauseIDFC() |
|
189 : TDfc(&Run, this), |
|
190 iFlag(-1) |
|
191 { |
|
192 } |
|
193 |
|
194 void TPauseIDFC::Pause(TInt aCpu) |
|
195 { |
|
196 TAddDfc adder; |
|
197 iFlag = -1; |
|
198 __e32_memory_barrier(); |
|
199 adder.Add(this, 1u<<aCpu); |
|
200 adder.WaitCompletion(); |
|
201 while (iFlag == -1) |
|
202 {} |
|
203 } |
|
204 |
|
205 void TPauseIDFC::Release() |
|
206 { |
|
207 __e32_atomic_store_ord32(&iFlag, 1); |
|
208 } |
|
209 |
|
210 void TPauseIDFC::Run(TAny* aPtr) |
|
211 { |
|
212 TPauseIDFC* p = (TPauseIDFC*)aPtr; |
|
213 __e32_atomic_store_ord32(&p->iFlag, 0); |
|
214 while (__e32_atomic_load_acq32(&p->iFlag) == 0) |
|
215 {} |
|
216 } |
|
217 |
|
218 class TPauseDFC : public TDfc |
|
219 { |
|
220 public: |
|
221 TPauseDFC(TDfcQue* aQ); |
|
222 void Pause(TInt aWait=0); |
|
223 void BusyPause(); |
|
224 void Release(); |
|
225 static void Run(TAny*); |
|
226 public: |
|
227 NFastSemaphore* volatile iSem; |
|
228 volatile TInt iWait; |
|
229 }; |
|
230 |
|
231 TPauseDFC::TPauseDFC(TDfcQue* aQ) |
|
232 : TDfc(&Run, this, aQ, 0), |
|
233 iSem(0) |
|
234 { |
|
235 } |
|
236 |
|
237 void TPauseDFC::Pause(TInt aWait) |
|
238 { |
|
239 iWait = aWait; |
|
240 NFastSemaphore entrySem(0); |
|
241 iSem = &entrySem; |
|
242 Enque(); |
|
243 NKern::FSWait(&entrySem); |
|
244 } |
|
245 |
|
246 void TPauseDFC::BusyPause() |
|
247 { |
|
248 volatile TInt& flag = (volatile TInt&)iSem; |
|
249 __e32_atomic_store_ord32(&flag, 0xfffffffe); |
|
250 Enque(); |
|
251 while (__e32_atomic_load_acq32(&flag) == 0xfffffffe) |
|
252 {} |
|
253 } |
|
254 |
|
255 void TPauseDFC::Release() |
|
256 { |
|
257 NFastSemaphore* s = (NFastSemaphore*)__e32_atomic_swp_ord_ptr(&iSem, 0); |
|
258 if (((TInt)s)==-1) |
|
259 { |
|
260 volatile TInt& flag = (volatile TInt&)iSem; |
|
261 __e32_atomic_store_ord32(&flag, 0); |
|
262 } |
|
263 else |
|
264 NKern::FSSignal(s); |
|
265 } |
|
266 |
|
267 void TPauseDFC::Run(TAny* aPtr) |
|
268 { |
|
269 TPauseDFC* p = (TPauseDFC*)aPtr; |
|
270 volatile TInt& flag = (volatile TInt&)p->iSem; |
|
271 if (flag == -2) |
|
272 { |
|
273 flag = -1; |
|
274 __e32_memory_barrier(); |
|
275 while (flag == -1) |
|
276 {} |
|
277 } |
|
278 else |
|
279 { |
|
280 NFastSemaphore exitSem(0); |
|
281 NFastSemaphore* s = (NFastSemaphore*)__e32_atomic_swp_ord_ptr(&p->iSem, &exitSem); |
|
282 if (p->iWait) |
|
283 { |
|
284 nfcfspin(__microseconds_to_norm_fast_counter(10000)); |
|
285 NKern::Sleep(p->iWait); |
|
286 } |
|
287 NKern::FSSignal(s); |
|
288 NKern::FSWait(&exitSem); |
|
289 } |
|
290 } |
|
291 |
|
292 void DoDFCTest1() |
|
293 { |
|
294 TEST_PRINT("DFCTest1"); |
|
295 TInt cpu; |
|
296 for_each_cpu(cpu) |
|
297 { |
|
298 TDfcQue* q = CreateDfcQ("DfcQ0", 1, cpu); |
|
299 DestroyDfcQ(q); |
|
300 q = CreateDfcQ("DfcQ1", 32, cpu); |
|
301 DestroyDfcQ(q); |
|
302 } |
|
303 } |
|
304 |
|
305 TBool QueueDfc(TDfc* aDfc, TInt aMode, TBool aExRet) |
|
306 { |
|
307 if (aMode==0) |
|
308 return !aExRet == !aDfc->Enque(); |
|
309 else if (aMode>0) |
|
310 { |
|
311 TAddDfc adder; |
|
312 TInt cpu = aMode - 1; |
|
313 adder.Add(aDfc, 1u<<cpu); |
|
314 adder.WaitCompletion(); |
|
315 nfcfspin(__microseconds_to_norm_fast_counter(10000)); |
|
316 return TRUE; |
|
317 } |
|
318 else if (aMode==-1) |
|
319 { |
|
320 NKern::Lock(); |
|
321 TBool ret = aDfc->Add(); |
|
322 NKern::Unlock(); |
|
323 return !aExRet == !ret; |
|
324 } |
|
325 return FALSE; |
|
326 } |
|
327 |
|
328 #define QUEUE_DFC(dfc, mode, exret) TEST_RESULT(QueueDfc(dfc,mode,exret),"") |
|
329 |
|
330 void DoDFCTest2() |
|
331 { |
|
332 TEST_PRINT("DFCTest2"); |
|
333 TInt num_cpus = NKern::NumberOfCpus(); |
|
334 TInt this_cpu = NKern::CurrentCpu(); |
|
335 TDfcQue* q; |
|
336 q = CreateDfcQ("DfcQ2", 1, this_cpu); |
|
337 TEST_OOM(q); |
|
338 q->iThread->iNThreadBaseSpare7 = 1; |
|
339 |
|
340 TTestDfc* d1 = new TTestDfc(1, q, 1); |
|
341 TEST_OOM(d1); |
|
342 TEST_RESULT(!d1->IsIDFC(), ""); |
|
343 TTestDfc* d2 = new TTestDfc(2, q, 2); |
|
344 TEST_OOM(d2); |
|
345 TEST_RESULT(!d2->IsIDFC(), ""); |
|
346 TTestDfc* d3 = new TTestDfc(3, q, 2); |
|
347 TEST_OOM(d3); |
|
348 TEST_RESULT(!d3->IsIDFC(), ""); |
|
349 TTestDfc* d4 = new TTestDfc(4, q, 3); |
|
350 TEST_OOM(d4); |
|
351 TEST_RESULT(!d4->IsIDFC(), ""); |
|
352 |
|
353 TInt mode; |
|
354 for (mode=-1; mode<=num_cpus; ++mode) |
|
355 { |
|
356 TEST_PRINT1("Mode %d", mode); |
|
357 CHECK_EMPTY(); |
|
358 TEST_RESULT(!d1->Queued(), ""); |
|
359 QUEUE_DFC(d1, mode, TRUE); |
|
360 TEST_RESULT(d1->Queued(), ""); |
|
361 QUEUE_DFC(d1, mode, FALSE); |
|
362 TEST_RESULT(d1->Queued(), ""); |
|
363 QUEUE_DFC(d2, mode, TRUE); |
|
364 QUEUE_DFC(d3, mode, TRUE); |
|
365 QUEUE_DFC(d4, mode, TRUE); |
|
366 CHECK_EMPTY(); |
|
367 NKern::Sleep(30); |
|
368 CHECK_FIRST_ENTRY(this_cpu, NKern::EThread, q, 4); |
|
369 CHECK_FIRST_ENTRY(this_cpu, NKern::EThread, q, 2); |
|
370 CHECK_FIRST_ENTRY(this_cpu, NKern::EThread, q, 3); |
|
371 CHECK_FIRST_ENTRY(this_cpu, NKern::EThread, q, 1); |
|
372 CHECK_EMPTY(); |
|
373 QUEUE_DFC(d4, mode, TRUE); |
|
374 QUEUE_DFC(d3, mode, TRUE); |
|
375 QUEUE_DFC(d2, mode, TRUE); |
|
376 QUEUE_DFC(d1, mode, TRUE); |
|
377 CHECK_EMPTY(); |
|
378 NKern::Sleep(30); |
|
379 CHECK_FIRST_ENTRY(this_cpu, NKern::EThread, q, 4); |
|
380 CHECK_FIRST_ENTRY(this_cpu, NKern::EThread, q, 3); |
|
381 CHECK_FIRST_ENTRY(this_cpu, NKern::EThread, q, 2); |
|
382 CHECK_FIRST_ENTRY(this_cpu, NKern::EThread, q, 1); |
|
383 CHECK_EMPTY(); |
|
384 QUEUE_DFC(d4, mode, TRUE); |
|
385 QUEUE_DFC(d3, mode, TRUE); |
|
386 QUEUE_DFC(d2, mode, TRUE); |
|
387 QUEUE_DFC(d1, mode, TRUE); |
|
388 TEST_RESULT(d4->Queued(), ""); |
|
389 TEST_RESULT(d4->Cancel(), ""); |
|
390 TEST_RESULT(!d4->Cancel(), ""); |
|
391 TEST_RESULT(!d4->Queued(), ""); |
|
392 CHECK_EMPTY(); |
|
393 NKern::Sleep(30); |
|
394 CHECK_FIRST_ENTRY(this_cpu, NKern::EThread, q, 3); |
|
395 CHECK_FIRST_ENTRY(this_cpu, NKern::EThread, q, 2); |
|
396 CHECK_FIRST_ENTRY(this_cpu, NKern::EThread, q, 1); |
|
397 CHECK_EMPTY(); |
|
398 QUEUE_DFC(d4, mode, TRUE); |
|
399 QUEUE_DFC(d3, mode, TRUE); |
|
400 QUEUE_DFC(d2, mode, TRUE); |
|
401 QUEUE_DFC(d1, mode, TRUE); |
|
402 TEST_RESULT(d3->Queued(), ""); |
|
403 TEST_RESULT(d3->Cancel(), ""); |
|
404 TEST_RESULT(!d3->Queued(), ""); |
|
405 CHECK_EMPTY(); |
|
406 NKern::Sleep(30); |
|
407 CHECK_FIRST_ENTRY(this_cpu, NKern::EThread, q, 4); |
|
408 CHECK_FIRST_ENTRY(this_cpu, NKern::EThread, q, 2); |
|
409 CHECK_FIRST_ENTRY(this_cpu, NKern::EThread, q, 1); |
|
410 CHECK_EMPTY(); |
|
411 QUEUE_DFC(d4, mode, TRUE); |
|
412 QUEUE_DFC(d3, mode, TRUE); |
|
413 QUEUE_DFC(d2, mode, TRUE); |
|
414 QUEUE_DFC(d1, mode, TRUE); |
|
415 TEST_RESULT(d3->Queued(), ""); |
|
416 TEST_RESULT(d2->Queued(), ""); |
|
417 TEST_RESULT(d3->Cancel(), ""); |
|
418 TEST_RESULT(d2->Cancel(), ""); |
|
419 TEST_RESULT(!d3->Queued(), ""); |
|
420 TEST_RESULT(!d2->Queued(), ""); |
|
421 CHECK_EMPTY(); |
|
422 NKern::Sleep(30); |
|
423 CHECK_FIRST_ENTRY(this_cpu, NKern::EThread, q, 4); |
|
424 CHECK_FIRST_ENTRY(this_cpu, NKern::EThread, q, 1); |
|
425 CHECK_EMPTY(); |
|
426 QUEUE_DFC(d4, mode, TRUE); |
|
427 QUEUE_DFC(d3, mode, TRUE); |
|
428 QUEUE_DFC(d2, mode, TRUE); |
|
429 QUEUE_DFC(d1, mode, TRUE); |
|
430 TEST_RESULT(d3->Cancel(), ""); |
|
431 TEST_RESULT(d2->Cancel(), ""); |
|
432 TEST_RESULT(d4->Cancel(), ""); |
|
433 TEST_RESULT(d1->Cancel(), ""); |
|
434 CHECK_EMPTY(); |
|
435 NKern::Sleep(30); |
|
436 CHECK_EMPTY(); |
|
437 QUEUE_DFC(d4, mode, TRUE); |
|
438 QUEUE_DFC(d3, mode, TRUE); |
|
439 QUEUE_DFC(d2, mode, TRUE); |
|
440 QUEUE_DFC(d1, mode, TRUE); |
|
441 TEST_RESULT(d1->Queued(), ""); |
|
442 TEST_RESULT(d3->Cancel(), ""); |
|
443 TEST_RESULT(d2->Cancel(), ""); |
|
444 TEST_RESULT(d4->Cancel(), ""); |
|
445 TEST_RESULT(d1->Cancel(), ""); |
|
446 TEST_RESULT(!d1->Queued(), ""); |
|
447 QUEUE_DFC(d1, mode, TRUE); |
|
448 TEST_RESULT(d1->Queued(), ""); |
|
449 QUEUE_DFC(d1, mode, FALSE); |
|
450 TEST_RESULT(d1->Queued(), ""); |
|
451 CHECK_EMPTY(); |
|
452 NKern::Sleep(30); |
|
453 CHECK_FIRST_ENTRY(this_cpu, NKern::EThread, q, 1); |
|
454 CHECK_EMPTY(); |
|
455 } |
|
456 |
|
457 delete d4; |
|
458 delete d3; |
|
459 delete d2; |
|
460 delete d1; |
|
461 DestroyDfcQ(q); |
|
462 } |
|
463 |
|
464 void DoDFCTest3(TInt aCpu) |
|
465 { |
|
466 TEST_PRINT1("DFCTest3 CPU %d", aCpu); |
|
467 TInt num_cpus = NKern::NumberOfCpus(); |
|
468 TInt this_cpu = NKern::CurrentCpu(); |
|
469 TBool same_cpu = (aCpu==this_cpu); |
|
470 TDfcQue* q; |
|
471 q = CreateDfcQ("DfcQ2", 32, aCpu); |
|
472 TEST_OOM(q); |
|
473 q->iThread->iNThreadBaseSpare7 = 1; |
|
474 TPauseDFC pauser(q); |
|
475 |
|
476 TTestDfc* d1 = new TTestDfc(1, q, 1); |
|
477 TEST_OOM(d1); |
|
478 TEST_RESULT(!d1->IsIDFC(), ""); |
|
479 TTestDfc* d2 = new TTestDfc(2, q, 2); |
|
480 TEST_OOM(d2); |
|
481 TEST_RESULT(!d2->IsIDFC(), ""); |
|
482 TTestDfc* d3 = new TTestDfc(3, q, 2); |
|
483 TEST_OOM(d3); |
|
484 TEST_RESULT(!d3->IsIDFC(), ""); |
|
485 TTestDfc* d4 = new TTestDfc(4, q, 3); |
|
486 TEST_OOM(d4); |
|
487 TEST_RESULT(!d4->IsIDFC(), ""); |
|
488 |
|
489 TInt mode; |
|
490 for (mode=-1; mode<=num_cpus; ++mode) |
|
491 { |
|
492 TEST_PRINT1("Mode %d", mode); |
|
493 CHECK_EMPTY(); |
|
494 TEST_RESULT(!d1->Queued(), ""); |
|
495 QUEUE_DFC(d1, mode, TRUE); |
|
496 if (!same_cpu) |
|
497 while (d1->Queued()) {} |
|
498 TEST_RESULT(!d1->Queued(), ""); |
|
499 QUEUE_DFC(d1, mode, TRUE); |
|
500 if (!same_cpu) |
|
501 while (d1->Queued()) {} |
|
502 TEST_RESULT(!d1->Queued(), ""); |
|
503 QUEUE_DFC(d2, mode, TRUE); |
|
504 if (!same_cpu) |
|
505 while (d2->Queued()) {} |
|
506 QUEUE_DFC(d3, mode, TRUE); |
|
507 if (!same_cpu) |
|
508 while (d3->Queued()) {} |
|
509 QUEUE_DFC(d4, mode, TRUE); |
|
510 if (!same_cpu) |
|
511 while (d4->Queued()) {} |
|
512 CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 1); |
|
513 CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 1); |
|
514 CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 2); |
|
515 CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 3); |
|
516 CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 4); |
|
517 CHECK_EMPTY(); |
|
518 QUEUE_DFC(d4, mode, TRUE); |
|
519 QUEUE_DFC(d3, mode, TRUE); |
|
520 QUEUE_DFC(d2, mode, TRUE); |
|
521 QUEUE_DFC(d1, mode, TRUE); |
|
522 if (!same_cpu) |
|
523 while (d1->Queued()) {} |
|
524 CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 4); |
|
525 CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 3); |
|
526 CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 2); |
|
527 CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 1); |
|
528 CHECK_EMPTY(); |
|
529 QUEUE_DFC(d4, mode, TRUE); |
|
530 QUEUE_DFC(d3, mode, TRUE); |
|
531 QUEUE_DFC(d2, mode, TRUE); |
|
532 QUEUE_DFC(d1, mode, TRUE); |
|
533 if (!same_cpu) |
|
534 while (d1->Queued()) {} |
|
535 TEST_RESULT(!d4->Queued(), ""); |
|
536 TEST_RESULT(!d4->Cancel(), ""); |
|
537 TEST_RESULT(!d4->Queued(), ""); |
|
538 CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 4); |
|
539 CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 3); |
|
540 CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 2); |
|
541 CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 1); |
|
542 CHECK_EMPTY(); |
|
543 pauser.Pause(); |
|
544 CHECK_EMPTY(); |
|
545 TEST_RESULT(!d1->Queued(), ""); |
|
546 QUEUE_DFC(d1, mode, TRUE); |
|
547 TEST_RESULT(d1->Queued(), ""); |
|
548 QUEUE_DFC(d1, mode, FALSE); |
|
549 TEST_RESULT(d1->Queued(), ""); |
|
550 QUEUE_DFC(d2, mode, TRUE); |
|
551 QUEUE_DFC(d3, mode, TRUE); |
|
552 QUEUE_DFC(d4, mode, TRUE); |
|
553 QUEUE_DFC(d4, mode, FALSE); |
|
554 CHECK_EMPTY(); |
|
555 pauser.Release(); |
|
556 pauser.Pause(); |
|
557 pauser.Release(); |
|
558 CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 4); |
|
559 CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 2); |
|
560 CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 3); |
|
561 CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 1); |
|
562 CHECK_EMPTY(); |
|
563 pauser.Pause(); |
|
564 CHECK_EMPTY(); |
|
565 TEST_RESULT(!d1->Queued(), ""); |
|
566 QUEUE_DFC(d1, mode, TRUE); |
|
567 TEST_RESULT(d1->Queued(), ""); |
|
568 QUEUE_DFC(d1, mode, FALSE); |
|
569 TEST_RESULT(d1->Queued(), ""); |
|
570 QUEUE_DFC(d4, mode, TRUE); |
|
571 QUEUE_DFC(d3, mode, TRUE); |
|
572 QUEUE_DFC(d2, mode, TRUE); |
|
573 CHECK_EMPTY(); |
|
574 pauser.Release(); |
|
575 pauser.Pause(); |
|
576 pauser.Release(); |
|
577 CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 4); |
|
578 CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 3); |
|
579 CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 2); |
|
580 CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 1); |
|
581 CHECK_EMPTY(); |
|
582 pauser.Pause(); |
|
583 CHECK_EMPTY(); |
|
584 TEST_RESULT(!d1->Queued(), ""); |
|
585 QUEUE_DFC(d1, mode, TRUE); |
|
586 TEST_RESULT(d1->Queued(), ""); |
|
587 QUEUE_DFC(d1, mode, FALSE); |
|
588 TEST_RESULT(d1->Queued(), ""); |
|
589 QUEUE_DFC(d2, mode, TRUE); |
|
590 QUEUE_DFC(d3, mode, TRUE); |
|
591 QUEUE_DFC(d4, mode, TRUE); |
|
592 CHECK_EMPTY(); |
|
593 TEST_RESULT(d1->Cancel(), ""); |
|
594 TEST_RESULT(!d1->Queued(), ""); |
|
595 pauser.Release(); |
|
596 pauser.Pause(); |
|
597 pauser.Release(); |
|
598 CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 4); |
|
599 CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 2); |
|
600 CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 3); |
|
601 CHECK_EMPTY(); |
|
602 } |
|
603 |
|
604 delete d4; |
|
605 delete d3; |
|
606 delete d2; |
|
607 delete d1; |
|
608 DestroyDfcQ(q); |
|
609 } |
|
610 |
|
611 TBool QueueIDfc(TDfc* aDfc, TInt aMode, TBool aExRet) |
|
612 { |
|
613 if (aMode==0) |
|
614 return !aExRet == !aDfc->RawAdd(); |
|
615 else if (aMode>0) |
|
616 { |
|
617 TTestDfc::Last = 0xffffffffu; |
|
618 TAddDfc adder; |
|
619 TInt cpu = (aMode&0xff) - 1; |
|
620 adder.Add(aDfc, 1u<<cpu); |
|
621 adder.WaitCompletion(); |
|
622 if (!(aMode&0x100)) |
|
623 { |
|
624 while (TTestDfc::Last != (TUint32)aDfc->iPtr) |
|
625 {} |
|
626 } |
|
627 return TRUE; |
|
628 } |
|
629 else if (aMode==-1) |
|
630 { |
|
631 NKern::Lock(); |
|
632 TBool ret = aDfc->Add(); |
|
633 NKern::Unlock(); |
|
634 return !aExRet == !ret; |
|
635 } |
|
636 return FALSE; |
|
637 } |
|
638 |
|
639 #define QUEUE_IDFC(dfc, mode, exret) TEST_RESULT(QueueIDfc(dfc,mode,exret),"") |
|
640 |
|
641 void DoIDFCTest1() |
|
642 { |
|
643 TEST_PRINT("IDFCTest1"); |
|
644 |
|
645 TInt num_cpus = NKern::NumberOfCpus(); |
|
646 TInt this_cpu = NKern::CurrentCpu(); |
|
647 |
|
648 TTestDfc* d1 = new TTestDfc(1); |
|
649 TEST_OOM(d1); |
|
650 TEST_RESULT(d1->IsIDFC(), ""); |
|
651 TTestDfc* d2 = new TTestDfc(2); |
|
652 TEST_OOM(d2); |
|
653 TEST_RESULT(d2->IsIDFC(), ""); |
|
654 TTestDfc* d3 = new TTestDfc(3); |
|
655 TEST_OOM(d3); |
|
656 TEST_RESULT(d3->IsIDFC(), ""); |
|
657 TTestDfc* d4 = new TTestDfc(4); |
|
658 TEST_OOM(d4); |
|
659 TEST_RESULT(d4->IsIDFC(), ""); |
|
660 |
|
661 TInt mode; |
|
662 for (mode=-1; mode<=num_cpus; ++mode) |
|
663 { |
|
664 TInt xcpu = (mode>0) ? (mode-1) : this_cpu; |
|
665 TEST_PRINT1("Mode %d", mode); |
|
666 CHECK_EMPTY(); |
|
667 TEST_RESULT(!d1->Queued(), ""); |
|
668 QUEUE_IDFC(d1, mode, TRUE); |
|
669 TEST_RESULT(!d1->Queued(), ""); |
|
670 QUEUE_IDFC(d1, mode, TRUE); |
|
671 TEST_RESULT(!d1->Queued(), ""); |
|
672 QUEUE_IDFC(d2, mode, TRUE); |
|
673 QUEUE_IDFC(d3, mode, TRUE); |
|
674 QUEUE_IDFC(d4, mode, TRUE); |
|
675 CHECK_FIRST_ENTRY(xcpu, NKern::EIDFC, 0, 1); |
|
676 CHECK_FIRST_ENTRY(xcpu, NKern::EIDFC, 0, 1); |
|
677 CHECK_FIRST_ENTRY(xcpu, NKern::EIDFC, 0, 2); |
|
678 CHECK_FIRST_ENTRY(xcpu, NKern::EIDFC, 0, 3); |
|
679 CHECK_FIRST_ENTRY(xcpu, NKern::EIDFC, 0, 4); |
|
680 CHECK_EMPTY(); |
|
681 QUEUE_IDFC(d4, mode, TRUE); |
|
682 QUEUE_IDFC(d3, mode, TRUE); |
|
683 QUEUE_IDFC(d2, mode, TRUE); |
|
684 QUEUE_IDFC(d1, mode, TRUE); |
|
685 CHECK_FIRST_ENTRY(xcpu, NKern::EIDFC, 0, 4); |
|
686 CHECK_FIRST_ENTRY(xcpu, NKern::EIDFC, 0, 3); |
|
687 CHECK_FIRST_ENTRY(xcpu, NKern::EIDFC, 0, 2); |
|
688 CHECK_FIRST_ENTRY(xcpu, NKern::EIDFC, 0, 1); |
|
689 CHECK_EMPTY(); |
|
690 } |
|
691 TInt irq = NKern::DisableAllInterrupts(); |
|
692 TEST_RESULT(d1->RawAdd(), ""); |
|
693 TEST_RESULT(d1->Queued(), ""); |
|
694 CHECK_EMPTY(); |
|
695 NKern::RestoreInterrupts(irq); |
|
696 TEST_RESULT(!d1->Queued(), ""); |
|
697 CHECK_FIRST_ENTRY(this_cpu, NKern::EIDFC, 0, 1); |
|
698 |
|
699 NKern::Lock(); |
|
700 TEST_RESULT(d1->Add(), ""); |
|
701 TEST_RESULT(d3->Add(), ""); |
|
702 TEST_RESULT(d2->Add(), ""); |
|
703 TEST_RESULT(d4->Add(), ""); |
|
704 TEST_RESULT(!d1->Add(), ""); |
|
705 TEST_RESULT(d1->Queued(), ""); |
|
706 TEST_RESULT(d2->Queued(), ""); |
|
707 TEST_RESULT(d3->Queued(), ""); |
|
708 TEST_RESULT(d4->Queued(), ""); |
|
709 CHECK_EMPTY(); |
|
710 NKern::Unlock(); |
|
711 TEST_RESULT(!d1->Queued(), ""); |
|
712 TEST_RESULT(!d2->Queued(), ""); |
|
713 TEST_RESULT(!d3->Queued(), ""); |
|
714 TEST_RESULT(!d4->Queued(), ""); |
|
715 CHECK_FIRST_ENTRY(this_cpu, NKern::EIDFC, 0, 1); |
|
716 CHECK_FIRST_ENTRY(this_cpu, NKern::EIDFC, 0, 3); |
|
717 CHECK_FIRST_ENTRY(this_cpu, NKern::EIDFC, 0, 2); |
|
718 CHECK_FIRST_ENTRY(this_cpu, NKern::EIDFC, 0, 4); |
|
719 CHECK_EMPTY(); |
|
720 |
|
721 NKern::Lock(); |
|
722 TEST_RESULT(d1->Add(), ""); |
|
723 TEST_RESULT(d3->Add(), ""); |
|
724 TEST_RESULT(d2->Add(), ""); |
|
725 TEST_RESULT(d4->Add(), ""); |
|
726 TEST_RESULT(d1->Queued(), ""); |
|
727 TEST_RESULT(d2->Queued(), ""); |
|
728 TEST_RESULT(d3->Queued(), ""); |
|
729 TEST_RESULT(d4->Queued(), ""); |
|
730 TEST_RESULT(d3->Cancel(), ""); |
|
731 TEST_RESULT(!d3->Queued(), ""); |
|
732 TEST_RESULT(!d3->Cancel(), ""); |
|
733 CHECK_EMPTY(); |
|
734 NKern::Unlock(); |
|
735 TEST_RESULT(!d1->Queued(), ""); |
|
736 TEST_RESULT(!d2->Queued(), ""); |
|
737 TEST_RESULT(!d4->Queued(), ""); |
|
738 CHECK_FIRST_ENTRY(this_cpu, NKern::EIDFC, 0, 1); |
|
739 CHECK_FIRST_ENTRY(this_cpu, NKern::EIDFC, 0, 2); |
|
740 CHECK_FIRST_ENTRY(this_cpu, NKern::EIDFC, 0, 4); |
|
741 CHECK_EMPTY(); |
|
742 |
|
743 NKern::Lock(); |
|
744 TEST_RESULT(d1->Add(), ""); |
|
745 TEST_RESULT(d3->Add(), ""); |
|
746 TEST_RESULT(d2->Add(), ""); |
|
747 TEST_RESULT(d4->Add(), ""); |
|
748 TEST_RESULT(d1->Queued(), ""); |
|
749 TEST_RESULT(d2->Queued(), ""); |
|
750 TEST_RESULT(d3->Queued(), ""); |
|
751 TEST_RESULT(d4->Queued(), ""); |
|
752 TEST_RESULT(d3->Cancel(), ""); |
|
753 TEST_RESULT(d1->Cancel(), ""); |
|
754 TEST_RESULT(d2->Cancel(), ""); |
|
755 TEST_RESULT(d4->Cancel(), ""); |
|
756 TEST_RESULT(!d1->Queued(), ""); |
|
757 TEST_RESULT(!d2->Queued(), ""); |
|
758 TEST_RESULT(!d3->Queued(), ""); |
|
759 TEST_RESULT(!d4->Queued(), ""); |
|
760 CHECK_EMPTY(); |
|
761 NKern::Unlock(); |
|
762 CHECK_EMPTY(); |
|
763 |
|
764 TPauseIDFC pauser; |
|
765 TInt cpu; |
|
766 for_each_cpu(cpu) |
|
767 { |
|
768 if (cpu == this_cpu) |
|
769 continue; |
|
770 mode = cpu + 0x101; |
|
771 TEST_PRINT1("CPU %d", cpu); |
|
772 pauser.Pause(cpu); |
|
773 CHECK_EMPTY(); |
|
774 TEST_RESULT(!d1->Queued(), ""); |
|
775 QUEUE_IDFC(d1, mode, TRUE); |
|
776 TEST_RESULT(d1->Queued(), ""); |
|
777 QUEUE_IDFC(d1, mode, FALSE); |
|
778 TEST_RESULT(d1->Queued(), ""); |
|
779 QUEUE_IDFC(d2, mode, TRUE); |
|
780 QUEUE_IDFC(d3, mode, TRUE); |
|
781 QUEUE_IDFC(d4, mode, TRUE); |
|
782 CHECK_EMPTY(); |
|
783 pauser.Release(); |
|
784 pauser.Pause(cpu); |
|
785 pauser.Release(); |
|
786 CHECK_FIRST_ENTRY(cpu, NKern::EIDFC, 0, 1); |
|
787 CHECK_FIRST_ENTRY(cpu, NKern::EIDFC, 0, 2); |
|
788 CHECK_FIRST_ENTRY(cpu, NKern::EIDFC, 0, 3); |
|
789 CHECK_FIRST_ENTRY(cpu, NKern::EIDFC, 0, 4); |
|
790 CHECK_EMPTY(); |
|
791 pauser.Pause(cpu); |
|
792 CHECK_EMPTY(); |
|
793 TEST_RESULT(!d1->Queued(), ""); |
|
794 QUEUE_IDFC(d1, mode, TRUE); |
|
795 TEST_RESULT(d1->Queued(), ""); |
|
796 QUEUE_IDFC(d2, mode, TRUE); |
|
797 QUEUE_IDFC(d3, mode, TRUE); |
|
798 QUEUE_IDFC(d4, mode, TRUE); |
|
799 TEST_RESULT(d1->Cancel(), ""); |
|
800 TEST_RESULT(!d1->Queued(), ""); |
|
801 TEST_RESULT(!d1->Cancel(), ""); |
|
802 CHECK_EMPTY(); |
|
803 pauser.Release(); |
|
804 pauser.Pause(cpu); |
|
805 pauser.Release(); |
|
806 CHECK_FIRST_ENTRY(cpu, NKern::EIDFC, 0, 2); |
|
807 CHECK_FIRST_ENTRY(cpu, NKern::EIDFC, 0, 3); |
|
808 CHECK_FIRST_ENTRY(cpu, NKern::EIDFC, 0, 4); |
|
809 CHECK_EMPTY(); |
|
810 pauser.Pause(cpu); |
|
811 CHECK_EMPTY(); |
|
812 TEST_RESULT(!d1->Queued(), ""); |
|
813 QUEUE_IDFC(d1, mode, TRUE); |
|
814 TEST_RESULT(d1->Queued(), ""); |
|
815 QUEUE_IDFC(d2, mode, TRUE); |
|
816 QUEUE_IDFC(d3, mode, TRUE); |
|
817 QUEUE_IDFC(d4, mode, TRUE); |
|
818 TEST_RESULT(d1->Cancel(), ""); |
|
819 TEST_RESULT(!d1->Queued(), ""); |
|
820 TEST_RESULT(d4->Cancel(), ""); |
|
821 TEST_RESULT(d2->Cancel(), ""); |
|
822 TEST_RESULT(d3->Cancel(), ""); |
|
823 CHECK_EMPTY(); |
|
824 pauser.Release(); |
|
825 pauser.Pause(cpu); |
|
826 pauser.Release(); |
|
827 CHECK_EMPTY(); |
|
828 } |
|
829 |
|
830 delete d4; |
|
831 delete d3; |
|
832 delete d2; |
|
833 delete d1; |
|
834 } |
|
835 |
|
836 void DoIdleDFCTest1(TInt aCpu) |
|
837 { |
|
838 #ifdef __SMP__ |
|
839 TEST_PRINT2("IdleDFCTest1 CPU %d (%08x)", aCpu, TheScheduler.iCpusNotIdle); |
|
840 #else |
|
841 TEST_PRINT1("IdleDFCTest1 CPU %d (%08x)", aCpu); |
|
842 #endif |
|
843 // TInt num_cpus = NKern::NumberOfCpus(); |
|
844 TInt this_cpu = NKern::CurrentCpu(); |
|
845 TBool same_cpu = (aCpu==this_cpu); |
|
846 TDfcQue* q = 0; |
|
847 TPauseDFC* pauser = 0; |
|
848 if (!same_cpu) |
|
849 { |
|
850 q = CreateDfcQ("DfcQ3", 1, aCpu); |
|
851 TEST_OOM(q); |
|
852 pauser = new TPauseDFC(q); |
|
853 TEST_OOM(pauser); |
|
854 } |
|
855 |
|
856 TTestDfc* d1 = new TTestDfc(1); |
|
857 TEST_OOM(d1); |
|
858 TEST_RESULT(d1->IsIDFC(), ""); |
|
859 TTestDfc* d2 = new TTestDfc(2); |
|
860 TEST_OOM(d2); |
|
861 TEST_RESULT(d2->IsIDFC(), ""); |
|
862 TTestDfc* d3 = new TTestDfc(3); |
|
863 TEST_OOM(d3); |
|
864 TEST_RESULT(d3->IsIDFC(), ""); |
|
865 TTestDfc* d4 = new TTestDfc(4); |
|
866 TEST_OOM(d4); |
|
867 TEST_RESULT(d4->IsIDFC(), ""); |
|
868 |
|
869 TEST_RESULT(!d1->Queued(), ""); |
|
870 TEST_RESULT(d1->QueueOnIdle(), ""); |
|
871 TEST_RESULT(d1->Queued(), ""); |
|
872 TEST_RESULT(!d1->QueueOnIdle(), ""); |
|
873 CHECK_EMPTY(); |
|
874 if (pauser) |
|
875 pauser->BusyPause(); |
|
876 NKern::Sleep(1); |
|
877 if (pauser) |
|
878 TEST_RESULT(d1->Queued(), ""); |
|
879 else |
|
880 { |
|
881 TEST_RESULT(!d1->Queued(), ""); |
|
882 CHECK_FIRST_ENTRY(this_cpu, NKern::EIDFC, 0, 1); |
|
883 } |
|
884 CHECK_EMPTY(); |
|
885 TBool ret = d1->QueueOnIdle(); |
|
886 TEST_RESULT(pauser?!ret:ret, ""); |
|
887 TEST_RESULT(d1->Queued(), ""); |
|
888 TEST_RESULT(d1->Cancel(), ""); |
|
889 TEST_RESULT(!d1->Queued(), ""); |
|
890 CHECK_EMPTY(); |
|
891 NKern::Sleep(1); |
|
892 CHECK_EMPTY(); |
|
893 if (pauser) |
|
894 pauser->Release(); |
|
895 TEST_RESULT(d4->QueueOnIdle(), ""); |
|
896 TEST_RESULT(d3->QueueOnIdle(), ""); |
|
897 TEST_RESULT(d1->QueueOnIdle(), ""); |
|
898 TEST_RESULT(d2->QueueOnIdle(), ""); |
|
899 TEST_RESULT(d3->Cancel(), ""); |
|
900 CHECK_EMPTY(); |
|
901 TInt xcpu = this_cpu; |
|
902 if (pauser) |
|
903 { |
|
904 xcpu = aCpu; |
|
905 pauser->Pause(1); |
|
906 pauser->Release(); |
|
907 } |
|
908 else |
|
909 NKern::Sleep(1); |
|
910 CHECK_FIRST_ENTRY(xcpu, NKern::EIDFC, 0, 4); |
|
911 CHECK_FIRST_ENTRY(xcpu, NKern::EIDFC, 0, 1); |
|
912 CHECK_FIRST_ENTRY(xcpu, NKern::EIDFC, 0, 2); |
|
913 CHECK_EMPTY(); |
|
914 |
|
915 delete d4; |
|
916 delete d3; |
|
917 delete d2; |
|
918 delete d1; |
|
919 delete pauser; |
|
920 if (q) |
|
921 DestroyDfcQ(q); |
|
922 } |
|
923 |
|
924 TDfc* Dfcs[6]; |
|
925 NFastSemaphore* IdleDFCTest2Fs; |
|
926 |
|
927 void IdleDFCTest2Fn(TAny* a) |
|
928 { |
|
929 TUint32 id = (TUint32)a; |
|
930 if (id==1) |
|
931 { |
|
932 TEST_RESULT(Dfcs[1]->Cancel(), ""); |
|
933 TEST_RESULT(Dfcs[3]->QueueOnIdle(), ""); |
|
934 TEST_RESULT(Dfcs[4]->QueueOnIdle(), ""); |
|
935 TEST_RESULT(Dfcs[5]->QueueOnIdle(), ""); |
|
936 } |
|
937 if (id==1 || id==4) |
|
938 IdleDFCTest2Fs->Signal(); |
|
939 if (id==3) |
|
940 { |
|
941 TEST_RESULT(Dfcs[5]->Cancel(), ""); |
|
942 } |
|
943 TTestDfc::Run(a); |
|
944 } |
|
945 |
|
946 void DoIdleDFCTest2() |
|
947 { |
|
948 TEST_PRINT("IdleDFCTest2"); |
|
949 NFastSemaphore sem(0); |
|
950 TInt this_cpu = NKern::CurrentCpu(); |
|
951 TInt i; |
|
952 for (i=0; i<6; ++i) |
|
953 { |
|
954 Dfcs[i] = new TDfc(&IdleDFCTest2Fn, (TAny*)(i+1)); |
|
955 TEST_OOM(Dfcs[i]); |
|
956 } |
|
957 TEST_RESULT(Dfcs[0]->QueueOnIdle(), ""); |
|
958 TEST_RESULT(Dfcs[1]->QueueOnIdle(), ""); |
|
959 TEST_RESULT(Dfcs[2]->QueueOnIdle(), ""); |
|
960 IdleDFCTest2Fs = &sem; |
|
961 CHECK_EMPTY(); |
|
962 NKern::FSWait(&sem); |
|
963 CHECK_FIRST_ENTRY(this_cpu, NKern::EIDFC, 0, 1); |
|
964 CHECK_FIRST_ENTRY(this_cpu, NKern::EIDFC, 0, 3); |
|
965 CHECK_EMPTY(); |
|
966 NKern::FSWait(&sem); |
|
967 CHECK_FIRST_ENTRY(this_cpu, NKern::EIDFC, 0, 4); |
|
968 CHECK_FIRST_ENTRY(this_cpu, NKern::EIDFC, 0, 5); |
|
969 CHECK_EMPTY(); |
|
970 for (i=0; i<6; ++i) |
|
971 delete Dfcs[i]; |
|
972 } |
|
973 |
|
974 #ifdef __SMP__ |
|
975 |
|
976 class TDfcStress; |
|
977 class TDfcX |
|
978 { |
|
979 public: |
|
980 enum |
|
981 { |
|
982 EFlag_IdleDFC=1, |
|
983 EFlag_IDFC=2, |
|
984 EFlag_DFC=4, |
|
985 EFlag_Timer=8, |
|
986 EFlag_Tied=16 |
|
987 }; |
|
988 public: |
|
989 TDfcX(); |
|
990 ~TDfcX(); |
|
991 static void IDfcFn(TAny*); |
|
992 static void DfcFn(TAny*); |
|
993 static void TimerIsrFn(TAny*); |
|
994 static void TimerDfcFn(TAny*); |
|
995 void Update(); |
|
996 TBool Add(TAny* a=0); |
|
997 TBool Cancel(TAny* a=0); |
|
998 TBool Enque(TAny* a=0); |
|
999 TBool QueueOnIdle(TAny* a=0); |
|
1000 TBool SafeAdd(); |
|
1001 TBool SafeCancel(); |
|
1002 TBool SafeEnque(); |
|
1003 TBool SafeQueueOnIdle(); |
|
1004 void CreateDfcOrTimer(); |
|
1005 void GetDesc(char* aDesc); |
|
1006 inline TBool IsIDFC() |
|
1007 {return (iFlags & (EFlag_IDFC|EFlag_Timer)) == EFlag_IDFC;} |
|
1008 inline TBool IsIdler() |
|
1009 {return iFlags & EFlag_IdleDFC;} |
|
1010 void ThreadActivity(); |
|
1011 public: |
|
1012 union |
|
1013 { |
|
1014 TDfc* volatile iDfc; |
|
1015 NTimer* volatile iTimer; |
|
1016 }; |
|
1017 TDfcQue* iDfcQ; |
|
1018 TUint32 iQueueCount; |
|
1019 TUint32 iRunCount[KMaxCpus]; |
|
1020 TUint32 iCancelCount; |
|
1021 TUint32 iExclusionFailCount; |
|
1022 TUint32 iId; |
|
1023 TUint32 iFlags; |
|
1024 TDfcStress* iS; |
|
1025 TUint64 iTimeQueued; |
|
1026 TUint64 iMaxTime; |
|
1027 TUint64 iSumTime; |
|
1028 TSpinLock iSpinLock; |
|
1029 NSchedulable* iXTied; |
|
1030 volatile TUint32* iExclusionCheck; |
|
1031 }; |
|
1032 |
|
1033 TDfcX::TDfcX() |
|
1034 : iSpinLock(TSpinLock::EOrderGenericIrqLow1) |
|
1035 { |
|
1036 memclr(this,sizeof(TDfcX)); |
|
1037 new (&iSpinLock) TSpinLock(TSpinLock::EOrderGenericIrqLow1); |
|
1038 } |
|
1039 |
|
1040 TDfcX::~TDfcX() |
|
1041 { |
|
1042 TAny* p = __e32_atomic_swp_ord_ptr(&iDfc, 0); |
|
1043 if (p) |
|
1044 { |
|
1045 if (iFlags & EFlag_Timer) |
|
1046 delete ((NTimer*)p); |
|
1047 else |
|
1048 delete ((TDfc*)p); |
|
1049 } |
|
1050 } |
|
1051 |
|
1052 class TDfcStress |
|
1053 { |
|
1054 public: |
|
1055 enum |
|
1056 { |
|
1057 EMode_Wait =0x00000001u, |
|
1058 EMode_AllowCancel =0x00000002u, |
|
1059 EMode_AllowIdle =0x00000004u, |
|
1060 EMode_AllowEnque =0x00000008u, |
|
1061 EMode_Recycle =0x00000010u, |
|
1062 EMode_UseTied =0x00000020u, |
|
1063 EMode_Migrate =0x00000040u, |
|
1064 EMode_SelfMigrate =0x00000080u, |
|
1065 EMode_Exit =0x80000000u |
|
1066 }; |
|
1067 public: |
|
1068 enum {EMaxDfc=48, EMaxDfcQ=8}; |
|
1069 |
|
1070 TDfcStress(); |
|
1071 static TDfcStress* New(TInt aNumDfc, TInt aNumDfcQ, TBool aTimerTest); |
|
1072 void Create(); |
|
1073 static void DoThreadFn(TAny*); |
|
1074 void ThreadFn(); |
|
1075 static void BackStopFn(TAny*); |
|
1076 void Run(); |
|
1077 void Close(); |
|
1078 void DoTestPhase(TInt aMode, TInt aTime, TInt aCount); |
|
1079 void GetModeText(char* aName); |
|
1080 public: |
|
1081 TDfcX* NewDfc(TUint32 aId, TUint32 aFlags, TInt aDfcQ); |
|
1082 TDfcX* NewIDfc(TUint32 aId, TUint32 aFlags, NSchedulable* aTied=0); |
|
1083 TDfcX* NewTimer(TUint32 aId, TUint32 aFlags, TInt aDfcQ, NSchedulable* aTied); |
|
1084 void CreateDfc(TUint32 aId); |
|
1085 public: |
|
1086 TInt iNumDfc; |
|
1087 TDfcX* iDfcX[EMaxDfc]; |
|
1088 TInt iNumDfcQ; |
|
1089 TBool iTimerTest; |
|
1090 TDfcQue* iDfcQ[EMaxDfcQ]; |
|
1091 NThread* iThread[KMaxCpus]; |
|
1092 volatile TBool iStop; |
|
1093 volatile TInt iRunning; |
|
1094 volatile TInt iMode; |
|
1095 NFastSemaphore* iExitSem; |
|
1096 TDfcX* volatile iGarbage; |
|
1097 TUint32 iRandomTimeLimit; |
|
1098 TDfc* iBackStopIdleDfc; |
|
1099 TDfcQue* iBackStopIdleDfcQ; |
|
1100 }; |
|
1101 |
|
1102 void TDfcX::Update() |
|
1103 { |
|
1104 TUint32 exc0 = 0; |
|
1105 TUint32 exc1 = 0; |
|
1106 if (iExclusionCheck) |
|
1107 exc0 = *iExclusionCheck; |
|
1108 TInt cpu = NKern::CurrentCpu(); |
|
1109 __e32_atomic_add_ord32(&iRunCount[cpu], 1); |
|
1110 TInt ctx = NKern::CurrentContext(); |
|
1111 TBool is_idfc = IsIDFC(); |
|
1112 TBool is_timer = iFlags & EFlag_Timer; |
|
1113 TBool is_tied = iFlags & EFlag_Tied; |
|
1114 if ((is_idfc||is_timer) && is_tied && !(iS->iMode & (TDfcStress::EMode_Migrate|TDfcStress::EMode_SelfMigrate))) |
|
1115 { |
|
1116 TInt cpu = NKern::CurrentCpu(); |
|
1117 TInt xcpu = iXTied->iCpuAffinity; |
|
1118 if (cpu != xcpu) |
|
1119 { |
|
1120 __crash(); |
|
1121 } |
|
1122 } |
|
1123 TInt irq=0; |
|
1124 if ((ctx!=NKern::EThread) && (iS->iMode & TDfcStress::EMode_AllowCancel)) |
|
1125 irq = iSpinLock.LockIrqSave(); |
|
1126 TUint64 now = fast_counter(); |
|
1127 TUint64 delta = now - iTimeQueued; |
|
1128 if (TInt64(delta)>=0) |
|
1129 { |
|
1130 if (delta > iMaxTime) |
|
1131 iMaxTime = delta; |
|
1132 iSumTime += delta; |
|
1133 } |
|
1134 if ((ctx!=NKern::EThread) && (iS->iMode & TDfcStress::EMode_AllowCancel)) |
|
1135 iSpinLock.UnlockIrqRestore(irq); |
|
1136 if (IsIdler()) |
|
1137 { |
|
1138 TInt i; |
|
1139 NKern::Lock(); |
|
1140 for (i=0; i<KMaxCpus; ++i) |
|
1141 { |
|
1142 NThread* t = iS->iThread[i]; |
|
1143 if (t) |
|
1144 t->iRequestSemaphore.Reset(); |
|
1145 } |
|
1146 NKern::Unlock(); |
|
1147 iS->iBackStopIdleDfc->Cancel(); |
|
1148 } |
|
1149 if (iExclusionCheck) |
|
1150 exc1 = *iExclusionCheck; |
|
1151 if (exc0!=exc1) |
|
1152 __e32_atomic_add_ord32(&iExclusionFailCount, 1); |
|
1153 } |
|
1154 |
|
1155 void TDfcStress::BackStopFn(TAny* a) |
|
1156 { |
|
1157 TDfcStress* s = (TDfcStress*)a; |
|
1158 TInt i; |
|
1159 NKern::Lock(); |
|
1160 for (i=0; i<KMaxCpus; ++i) |
|
1161 { |
|
1162 NThread* t = s->iThread[i]; |
|
1163 if (t) |
|
1164 t->iRequestSemaphore.Reset(); |
|
1165 } |
|
1166 NKern::Unlock(); |
|
1167 } |
|
1168 |
|
1169 void TDfcX::IDfcFn(TAny* a) |
|
1170 { |
|
1171 TDfcX* d = (TDfcX*)a; |
|
1172 d->Update(); |
|
1173 } |
|
1174 |
|
1175 void TDfcX::DfcFn(TAny* a) |
|
1176 { |
|
1177 TDfcX* d = (TDfcX*)a; |
|
1178 d->ThreadActivity(); |
|
1179 d->Update(); |
|
1180 d->ThreadActivity(); |
|
1181 } |
|
1182 |
|
1183 void TDfcX::TimerDfcFn(TAny* a) |
|
1184 { |
|
1185 TDfcX* d = (TDfcX*)a; |
|
1186 d->ThreadActivity(); |
|
1187 d->Update(); |
|
1188 d->ThreadActivity(); |
|
1189 } |
|
1190 |
|
1191 void TDfcX::TimerIsrFn(TAny* a) |
|
1192 { |
|
1193 TDfcX* d = (TDfcX*)a; |
|
1194 d->Update(); |
|
1195 } |
|
1196 |
|
1197 void TDfcX::ThreadActivity() |
|
1198 { |
|
1199 TInt ncpus = NKern::NumberOfCpus(); |
|
1200 TInt ocpu = NKern::CurrentCpu(); |
|
1201 NThread* pC = NKern::CurrentThread(); |
|
1202 volatile TUint32* pX = (volatile TUint32*)&pC->iRunCount32[1]; // HACK! |
|
1203 TInt cpu = ocpu; |
|
1204 TInt i; |
|
1205 if ((iS->iMode & TDfcStress::EMode_SelfMigrate) && !pC->iEvents.IsEmpty()) |
|
1206 { |
|
1207 for (i=0; i<ncpus; ++i) |
|
1208 { |
|
1209 ++*pX; |
|
1210 if (++cpu == ncpus) |
|
1211 cpu = 0; |
|
1212 NKern::ThreadSetCpuAffinity(pC, cpu); |
|
1213 } |
|
1214 } |
|
1215 else |
|
1216 { |
|
1217 ++*pX; |
|
1218 ++*pX; |
|
1219 ++*pX; |
|
1220 ++*pX; |
|
1221 ++*pX; |
|
1222 ++*pX; |
|
1223 ++*pX; |
|
1224 ++*pX; |
|
1225 } |
|
1226 ++*pX; |
|
1227 ++*pX; |
|
1228 ++*pX; |
|
1229 } |
|
1230 |
|
1231 TBool TDfcX::Add(TAny* a) |
|
1232 { |
|
1233 TBool is_timer = iFlags & EFlag_Timer; |
|
1234 if (!a) |
|
1235 a = iDfc; |
|
1236 TUint64 time = fast_counter(); |
|
1237 TBool ok; |
|
1238 if (is_timer) |
|
1239 ok = ((NTimer*)a)->OneShot(1) == KErrNone; |
|
1240 else |
|
1241 ok = ((TDfc*)a)->Add(); |
|
1242 if (ok) |
|
1243 { |
|
1244 iTimeQueued = time; |
|
1245 __e32_atomic_add_ord32(&iQueueCount, 1); |
|
1246 } |
|
1247 return ok; |
|
1248 } |
|
1249 |
|
1250 TBool TDfcX::Cancel(TAny* a) |
|
1251 { |
|
1252 TBool is_timer = iFlags & EFlag_Timer; |
|
1253 if (!a) |
|
1254 a = iDfc; |
|
1255 TBool ok; |
|
1256 if (is_timer) |
|
1257 ok = ((NTimer*)a)->Cancel(); |
|
1258 else |
|
1259 ok = ((TDfc*)a)->Cancel(); |
|
1260 if (ok) |
|
1261 __e32_atomic_add_ord32(&iCancelCount, 1); |
|
1262 return ok; |
|
1263 } |
|
1264 |
|
1265 TBool TDfcX::Enque(TAny* a) |
|
1266 { |
|
1267 TBool is_timer = iFlags & EFlag_Timer; |
|
1268 if (!a) |
|
1269 a = iDfc; |
|
1270 TUint64 time = fast_counter(); |
|
1271 TBool ok; |
|
1272 if (is_timer) |
|
1273 ok = ((NTimer*)a)->Again(2) == KErrNone; |
|
1274 else |
|
1275 ok = ((TDfc*)a)->Enque(); |
|
1276 if (ok) |
|
1277 { |
|
1278 iTimeQueued = time; |
|
1279 __e32_atomic_add_ord32(&iQueueCount, 1); |
|
1280 } |
|
1281 return ok; |
|
1282 } |
|
1283 |
|
1284 TBool TDfcX::QueueOnIdle(TAny* a) |
|
1285 { |
|
1286 TBool is_timer = iFlags & EFlag_Timer; |
|
1287 if (is_timer) |
|
1288 return FALSE; |
|
1289 if (!a) |
|
1290 a = iDfc; |
|
1291 TUint64 time = fast_counter(); |
|
1292 TBool ok = ((TDfc*)a)->QueueOnIdle(); |
|
1293 if (ok) |
|
1294 { |
|
1295 iTimeQueued = time; |
|
1296 __e32_atomic_add_ord32(&iQueueCount, 1); |
|
1297 } |
|
1298 return ok; |
|
1299 } |
|
1300 |
|
1301 TBool TDfcX::SafeAdd() |
|
1302 { |
|
1303 TBool ret = FALSE; |
|
1304 TUint32 x = set_bit0_if_nonnull((TUint32&)iDfc); |
|
1305 if (x && !(x&1)) |
|
1306 { |
|
1307 TDfc* p = (TDfc*)x; |
|
1308 ret = Add(p); |
|
1309 flip_bit0((TUint32&)iDfc); |
|
1310 } |
|
1311 return ret; |
|
1312 } |
|
1313 |
|
1314 TBool TDfcX::SafeEnque() |
|
1315 { |
|
1316 TBool ret = FALSE; |
|
1317 TUint32 x = set_bit0_if_nonnull((TUint32&)iDfc); |
|
1318 if (x && !(x&1)) |
|
1319 { |
|
1320 TDfc* p = (TDfc*)x; |
|
1321 ret = Enque(p); |
|
1322 flip_bit0((TUint32&)iDfc); |
|
1323 } |
|
1324 return ret; |
|
1325 } |
|
1326 |
|
1327 TBool TDfcX::SafeQueueOnIdle() |
|
1328 { |
|
1329 TBool ret = FALSE; |
|
1330 TUint32 x = set_bit0_if_nonnull((TUint32&)iDfc); |
|
1331 if (x && !(x&1)) |
|
1332 { |
|
1333 TDfc* p = (TDfc*)x; |
|
1334 ret = QueueOnIdle(p); |
|
1335 flip_bit0((TUint32&)iDfc); |
|
1336 } |
|
1337 return ret; |
|
1338 } |
|
1339 |
|
1340 TBool TDfcX::SafeCancel() |
|
1341 { |
|
1342 TBool ret = FALSE; |
|
1343 TUint32 x = swap_out_if_bit0_clear((TUint32&)iDfc); |
|
1344 if (x && !(x&1)) |
|
1345 { |
|
1346 if (iFlags & EFlag_Timer) |
|
1347 { |
|
1348 NTimer* p = (NTimer*)x; |
|
1349 ret = Cancel(p); |
|
1350 p->~NTimer(); |
|
1351 memset(p, 0xbb, sizeof(NTimer)); |
|
1352 free(p); |
|
1353 } |
|
1354 else |
|
1355 { |
|
1356 TDfc* p = (TDfc*)x; |
|
1357 ret = Cancel(p); |
|
1358 p->~TDfc(); |
|
1359 memset(p, 0xbb, sizeof(TDfc)); |
|
1360 free(p); |
|
1361 } |
|
1362 CreateDfcOrTimer(); |
|
1363 } |
|
1364 return ret; |
|
1365 } |
|
1366 |
|
1367 void TDfcX::GetDesc(char* a) |
|
1368 { |
|
1369 memset(a, 0x20, 8); |
|
1370 if (iFlags & EFlag_Timer) |
|
1371 *a++ = 'T'; |
|
1372 if (iFlags & EFlag_IDFC) |
|
1373 *a++ = 'I'; |
|
1374 if (iFlags & EFlag_DFC) |
|
1375 *a++ = 'D'; |
|
1376 if (iFlags & EFlag_IdleDFC) |
|
1377 *a++ = 'i'; |
|
1378 if (iFlags & EFlag_Tied) |
|
1379 *a++ = 't'; |
|
1380 } |
|
1381 |
|
1382 TDfcStress::TDfcStress() |
|
1383 { |
|
1384 memclr(this, sizeof(*this)); |
|
1385 } |
|
1386 |
|
1387 TDfcX* TDfcStress::NewDfc(TUint32 aId, TUint32 aFlags, TInt aDfcQ) |
|
1388 { |
|
1389 TDfcX* d = new TDfcX; |
|
1390 TEST_OOM(d); |
|
1391 d->iId = aId; |
|
1392 d->iFlags = aFlags; |
|
1393 d->iS = this; |
|
1394 |
|
1395 d->iDfcQ = iDfcQ[aDfcQ]; |
|
1396 d->CreateDfcOrTimer(); |
|
1397 return d; |
|
1398 } |
|
1399 |
|
1400 TDfcX* TDfcStress::NewIDfc(TUint32 aId, TUint32 aFlags, NSchedulable* aTied) |
|
1401 { |
|
1402 TDfcX* d = new TDfcX; |
|
1403 TEST_OOM(d); |
|
1404 d->iId = aId; |
|
1405 d->iFlags = aFlags; |
|
1406 d->iS = this; |
|
1407 |
|
1408 d->iXTied = aTied; |
|
1409 d->CreateDfcOrTimer(); |
|
1410 return d; |
|
1411 } |
|
1412 |
|
1413 TDfcX* TDfcStress::NewTimer(TUint32 aId, TUint32 aFlags, TInt aDfcQ, NSchedulable* aTied) |
|
1414 { |
|
1415 TDfcX* d = new TDfcX; |
|
1416 TEST_OOM(d); |
|
1417 d->iId = aId; |
|
1418 d->iFlags = aFlags; |
|
1419 d->iS = this; |
|
1420 |
|
1421 d->iDfcQ = (aFlags & TDfcX::EFlag_DFC) ? iDfcQ[aDfcQ] : 0; |
|
1422 d->iXTied = (aFlags & TDfcX::EFlag_Tied) ? aTied : 0; |
|
1423 d->CreateDfcOrTimer(); |
|
1424 return d; |
|
1425 } |
|
1426 |
|
1427 |
|
1428 void TDfcX::CreateDfcOrTimer() |
|
1429 { |
|
1430 // volatile TUint32* xc = 0; |
|
1431 NThreadBase* t = iS->iDfcQ[0]->iThread; |
|
1432 volatile TUint32* xc = &t->iRunCount32[1]; // HACK! |
|
1433 if (!(iFlags & EFlag_Timer)) |
|
1434 { |
|
1435 TDfc* d = 0; |
|
1436 if (!(iFlags & EFlag_IDFC)) |
|
1437 { |
|
1438 d = new TDfc(&TDfcX::DfcFn, this, iDfcQ, 1); |
|
1439 xc = (volatile TUint32*)&iDfcQ->iThread->iRunCount32[1]; |
|
1440 } |
|
1441 else if (iFlags & EFlag_Tied) |
|
1442 { |
|
1443 d = new TDfc(iXTied, &TDfcX::IDfcFn, this); |
|
1444 xc = (volatile TUint32*)&iXTied->iRunCount32[1]; |
|
1445 } |
|
1446 else |
|
1447 d = new TDfc(&TDfcX::IDfcFn, this); |
|
1448 __NK_ASSERT_ALWAYS(d!=0); |
|
1449 __e32_atomic_store_rel_ptr(&iDfc, d); |
|
1450 } |
|
1451 else |
|
1452 { |
|
1453 NTimer* tmr = 0; |
|
1454 if (iFlags & EFlag_DFC) |
|
1455 { |
|
1456 tmr = new NTimer(&TDfcX::TimerDfcFn, this, iDfcQ, 1); |
|
1457 xc = (volatile TUint32*)&iDfcQ->iThread->iRunCount32[1]; |
|
1458 } |
|
1459 else if (iFlags & EFlag_Tied) |
|
1460 { |
|
1461 tmr = new NTimer(iXTied, &TDfcX::TimerIsrFn, this); |
|
1462 xc = (volatile TUint32*)&iXTied->iRunCount32[1]; |
|
1463 } |
|
1464 else |
|
1465 tmr = new NTimer(&TDfcX::TimerIsrFn, this); |
|
1466 __NK_ASSERT_ALWAYS(tmr!=0); |
|
1467 __e32_atomic_store_rel_ptr(&iTimer, tmr); |
|
1468 } |
|
1469 iExclusionCheck = xc; |
|
1470 } |
|
1471 |
|
1472 TDfcStress* TDfcStress::New(TInt aNumDfc, TInt aNumDfcQ, TBool aTimerTest) |
|
1473 { |
|
1474 TDfcStress* p = new TDfcStress; |
|
1475 TEST_OOM(p); |
|
1476 p->iTimerTest = aTimerTest; |
|
1477 p->iNumDfc = aNumDfc; |
|
1478 p->iNumDfcQ = aNumDfcQ; |
|
1479 p->Create(); |
|
1480 return p; |
|
1481 } |
|
1482 |
|
1483 void TDfcStress::Create() |
|
1484 { |
|
1485 DEBUGPRINT("TDfcStress @ %08x", this); |
|
1486 TInt i; |
|
1487 TInt num_cpus = NKern::NumberOfCpus(); |
|
1488 TInt cpu = 0; |
|
1489 iExitSem = new NFastSemaphore(0); |
|
1490 TEST_OOM(iExitSem); |
|
1491 for (i=0; i<iNumDfcQ; ++i) |
|
1492 { |
|
1493 char c[8] = "DFCQ*"; |
|
1494 c[4] = (char)('0'+i); |
|
1495 TDfcQue* q = CreateDfcQ(c, 32, cpu); |
|
1496 TEST_OOM(q); |
|
1497 iDfcQ[i] = q; |
|
1498 if (++cpu == num_cpus) |
|
1499 cpu = 0; |
|
1500 NThreadBase* t = q->iThread; |
|
1501 DEBUGPRINT("DfcQ %2d @ %08x Thread @%08x Stack %08x+%08x", i, iDfcQ[i], t, t->iStackBase, t->iStackSize); |
|
1502 } |
|
1503 iBackStopIdleDfcQ = CreateDfcQ("BackStop", 1, 0); |
|
1504 TEST_OOM(iBackStopIdleDfcQ); |
|
1505 iBackStopIdleDfc = new TDfc(&BackStopFn, this, iBackStopIdleDfcQ, 1); |
|
1506 TEST_OOM(iBackStopIdleDfc); |
|
1507 for (i=0; i<num_cpus; ++i) |
|
1508 { |
|
1509 char c[8] = "THRD*"; |
|
1510 c[4] = (char)('0'+i); |
|
1511 NThread* t = CreateUnresumedThreadSignalOnExit(c, &DoThreadFn, 11, this, 0, -1, iExitSem, i); |
|
1512 TEST_OOM(t); |
|
1513 iThread[i] = t; |
|
1514 DEBUGPRINT("Thread %2d @ %08x (Stack %08x+%08x)", i, iThread[i], t->iStackBase, t->iStackSize); |
|
1515 } |
|
1516 for (i=0; i<iNumDfc; ++i) |
|
1517 { |
|
1518 CreateDfc(i); |
|
1519 DEBUGPRINT("DfcX %2d @ %08x (DFC @ %08x)", i, iDfcX[i], iDfcX[i]->iDfc); |
|
1520 } |
|
1521 } |
|
1522 |
|
1523 void TDfcStress::CreateDfc(TUint32 aId) |
|
1524 { |
|
1525 TUint32 type = aId & 7; |
|
1526 TUint32 q = aId % iNumDfcQ; |
|
1527 TDfcX* d = 0; |
|
1528 switch (type) |
|
1529 { |
|
1530 case 0: |
|
1531 case 1: |
|
1532 case 2: |
|
1533 case 3: |
|
1534 if (iTimerTest) |
|
1535 d = NewTimer(aId, TDfcX::EFlag_Timer|TDfcX::EFlag_DFC, q, 0); |
|
1536 else |
|
1537 d = NewDfc(aId, TDfcX::EFlag_DFC, q); |
|
1538 break; |
|
1539 case 4: |
|
1540 case 5: |
|
1541 if (iTimerTest) |
|
1542 d = NewTimer(aId, TDfcX::EFlag_Timer|TDfcX::EFlag_Tied, 0, iDfcQ[iNumDfcQ-1-(type&1)]->iThread); |
|
1543 else |
|
1544 { |
|
1545 if (aId>=16 && aId<32 && iNumDfcQ>2) |
|
1546 d = NewIDfc(aId, TDfcX::EFlag_IDFC|TDfcX::EFlag_Tied, iDfcQ[2]->iThread); |
|
1547 else |
|
1548 d = NewIDfc(aId, TDfcX::EFlag_IDFC); |
|
1549 } |
|
1550 break; |
|
1551 case 6: |
|
1552 case 7: |
|
1553 if (iTimerTest) |
|
1554 d = NewTimer(aId, TDfcX::EFlag_Timer, 0, 0); |
|
1555 else |
|
1556 d = NewDfc(aId, TDfcX::EFlag_DFC|TDfcX::EFlag_IdleDFC, q); |
|
1557 break; |
|
1558 }; |
|
1559 __e32_atomic_store_rel_ptr(&iDfcX[aId], d); |
|
1560 } |
|
1561 |
|
1562 void TDfcStress::Close() |
|
1563 { |
|
1564 TInt i; |
|
1565 |
|
1566 // delete DFCs before the DFC queues they might be on |
|
1567 for (i=0; i<iNumDfc; ++i) |
|
1568 { |
|
1569 TDfcX* d = iDfcX[i]; |
|
1570 delete d; |
|
1571 } |
|
1572 delete iBackStopIdleDfc; |
|
1573 |
|
1574 for (i=0; i<iNumDfcQ; ++i) |
|
1575 DestroyDfcQ(iDfcQ[i]); |
|
1576 DestroyDfcQ(iBackStopIdleDfcQ); |
|
1577 |
|
1578 delete iExitSem; |
|
1579 delete this; |
|
1580 } |
|
1581 |
|
1582 void TDfcStress::DoThreadFn(TAny* a) |
|
1583 { |
|
1584 ((TDfcStress*)a)->ThreadFn(); |
|
1585 } |
|
1586 |
|
1587 void append(char*& a, const char* s) |
|
1588 { |
|
1589 while(*s) |
|
1590 *a++ = *s++; |
|
1591 *a=0; |
|
1592 } |
|
1593 |
|
1594 void TDfcStress::GetModeText(char* a) |
|
1595 { |
|
1596 memclr(a,128); |
|
1597 if (iMode==0) |
|
1598 { |
|
1599 append(a, "Add only"); |
|
1600 return; |
|
1601 } |
|
1602 if (iMode & EMode_Wait) |
|
1603 append(a, "Wait "); |
|
1604 if (iMode & EMode_AllowCancel) |
|
1605 append(a, "Cancel "); |
|
1606 if (iMode & EMode_AllowIdle) |
|
1607 append(a, "Idle "); |
|
1608 if (iMode & EMode_AllowEnque) |
|
1609 append(a, "Enque "); |
|
1610 if (iMode & EMode_Recycle) |
|
1611 append(a, "Recycle "); |
|
1612 if (iMode & EMode_Migrate) |
|
1613 append(a, "Migrate "); |
|
1614 if (iMode & EMode_SelfMigrate) |
|
1615 append(a, "SelfMigrate "); |
|
1616 } |
|
1617 |
|
1618 /* |
|
1619 Test Mode: |
|
1620 |
|
1621 Bit 31 If set causes thread to exit |
|
1622 Bit 0 If set does random wait after each operation |
|
1623 Bit 1 Allows Cancel operations if set |
|
1624 Bit 2 Allows idle operations if set |
|
1625 Bit 3 Test Enque() as well as Add() |
|
1626 Bit 4 Use SafeXXX operations |
|
1627 Bit 5 Use tied IDFCs |
|
1628 Bit 6 Migrate threads with things tied to them |
|
1629 Bit 7 Threads with things tied to them migrate themselves during execution |
|
1630 |
|
1631 */ |
|
1632 void TDfcStress::ThreadFn() |
|
1633 { |
|
1634 TBool finish = FALSE; |
|
1635 TUint32 seed[2]; |
|
1636 seed[0] = NKern::CurrentCpu() ^ 0xddb3d743; |
|
1637 seed[1] = 0; |
|
1638 FOREVER |
|
1639 { |
|
1640 if (iStop) |
|
1641 { |
|
1642 __e32_atomic_add_ord32(&iRunning, (TUint32)(-1)); |
|
1643 while (iStop) |
|
1644 { |
|
1645 if (iMode<0) |
|
1646 { |
|
1647 finish = TRUE; |
|
1648 break; |
|
1649 } |
|
1650 } |
|
1651 if (finish) |
|
1652 break; |
|
1653 else |
|
1654 __e32_atomic_add_ord32(&iRunning, 1); |
|
1655 } |
|
1656 if (iMode & EMode_Wait) |
|
1657 { |
|
1658 TUint32 wait = random(seed); |
|
1659 wait %= iRandomTimeLimit; |
|
1660 wait += 1; |
|
1661 fcfspin(wait); |
|
1662 } |
|
1663 TUint32 action = random(seed); |
|
1664 TUint32 action2 = random(seed); |
|
1665 if (action & 0xff000000) |
|
1666 { |
|
1667 // queue or cancel a DFC or timer |
|
1668 TBool cancel = action2 & 2; |
|
1669 TUint32 id = action % iNumDfc; |
|
1670 TDfcX* d = iDfcX[id]; |
|
1671 if (iMode & EMode_Recycle) |
|
1672 { |
|
1673 TBool isIDFC = d->IsIDFC(); |
|
1674 TBool isIdler = d->IsIdler(); |
|
1675 if (cancel) |
|
1676 d->SafeCancel(); |
|
1677 else if (isIdler) |
|
1678 d->SafeQueueOnIdle(); |
|
1679 else if ((iMode & EMode_AllowEnque) && (action2 & 1) && !isIDFC) |
|
1680 d->SafeEnque(); |
|
1681 else |
|
1682 { |
|
1683 NKern::Lock(); |
|
1684 d->SafeAdd(); |
|
1685 NKern::Unlock(); |
|
1686 } |
|
1687 } |
|
1688 else |
|
1689 { |
|
1690 if (cancel && (iMode & EMode_AllowCancel)) |
|
1691 { |
|
1692 d->Cancel(); |
|
1693 } |
|
1694 else if (!d->IsIdler()) |
|
1695 { |
|
1696 if ((iMode & EMode_AllowEnque) && (action2 & 1) && !d->IsIDFC()) |
|
1697 { |
|
1698 d->Enque(); |
|
1699 } |
|
1700 else |
|
1701 { |
|
1702 NKern::Lock(); |
|
1703 d->Add(); |
|
1704 NKern::Unlock(); |
|
1705 } |
|
1706 } |
|
1707 else |
|
1708 { |
|
1709 d->QueueOnIdle(); |
|
1710 } |
|
1711 } |
|
1712 continue; |
|
1713 } |
|
1714 if (iMode & EMode_AllowIdle) |
|
1715 { |
|
1716 iBackStopIdleDfc->QueueOnIdle(); |
|
1717 NKern::WaitForAnyRequest(); |
|
1718 } |
|
1719 } |
|
1720 } |
|
1721 |
|
1722 void StopTimeout(TAny*) |
|
1723 { |
|
1724 __crash(); |
|
1725 } |
|
1726 |
|
1727 void TDfcStress::DoTestPhase(TInt aMode, TInt aTime, TInt aCount) |
|
1728 { |
|
1729 char mode_text[128]; |
|
1730 TInt i; |
|
1731 TUint32 maxavg = 0; |
|
1732 TInt n; |
|
1733 iMode = aMode; |
|
1734 iStop = FALSE; |
|
1735 GetModeText(mode_text); |
|
1736 TEST_PRINT1("Testing with: %s", mode_text); |
|
1737 for (i=0; i<aCount; ++i) |
|
1738 { |
|
1739 NKern::Sleep(aTime); |
|
1740 DebugPrint(".",1); |
|
1741 } |
|
1742 DebugPrint("\r\n",2); |
|
1743 TEST_PRINT("Stopping ..."); |
|
1744 iStop = TRUE; |
|
1745 NTimer timer(&StopTimeout, 0); |
|
1746 timer.OneShot(2000); |
|
1747 BackStopFn(this); |
|
1748 n = 0; |
|
1749 while (iRunning && ++n<=100) |
|
1750 NKern::Sleep(10); |
|
1751 if (iRunning) |
|
1752 { |
|
1753 __crash(); |
|
1754 } |
|
1755 iBackStopIdleDfc->Cancel(); |
|
1756 timer.Cancel(); |
|
1757 TEST_PRINT("Threads stopped"); |
|
1758 for (i=0; i<iNumDfcQ; ++i) |
|
1759 { |
|
1760 TUint32 ev = iDfcQ[i]->iThread->iEventState; |
|
1761 DEBUGPRINT("DfcThread %d EventState = %08x", i, ev); |
|
1762 TEST_RESULT(!(ev & NSchedulable::EEventCountMask), ""); |
|
1763 } |
|
1764 for (i=0; i<NKern::NumberOfCpus(); ++i) |
|
1765 { |
|
1766 TUint32 ev = iThread[i]->iEventState; |
|
1767 DEBUGPRINT("Thread %d EventState = %08x", i, ev); |
|
1768 TEST_RESULT(!(ev & NSchedulable::EEventCountMask), ""); |
|
1769 } |
|
1770 NKern::Sleep(10); |
|
1771 for (i=0; i<iNumDfc; ++i) |
|
1772 { |
|
1773 TDfcX* d = iDfcX[i]; |
|
1774 d->Cancel(); |
|
1775 TUint32 qc = d->iQueueCount; |
|
1776 TUint32* rc = d->iRunCount; |
|
1777 TUint32 totrc = rc[0] + rc[1] + rc[2] + rc[3] + rc[4] + rc[5] + rc[6] + rc[7]; |
|
1778 TUint32 cc = d->iCancelCount; |
|
1779 TUint32 f = d->iFlags; |
|
1780 // TUint32 imm = d->IsIDFC()?1:0; |
|
1781 TUint32 max = d->iMaxTime; |
|
1782 TUint32 avg = 0; |
|
1783 TUint32 xfc = d->iExclusionFailCount; |
|
1784 if (totrc) |
|
1785 avg = TUint32(d->iSumTime / TUint64(totrc)); |
|
1786 if (avg > maxavg) |
|
1787 maxavg = avg; |
|
1788 char desc[16]; |
|
1789 memclr(desc,16); |
|
1790 d->GetDesc(desc); |
|
1791 DEBUGPRINT("%2d: %s QC %9d RC %9d CC %9d MAX %9d AVG %9d XFC %9d RC %9d %9d %9d %9d %9d %9d %9d %9d", i, desc, qc, totrc, cc, max, avg, xfc, rc[0], rc[1], rc[2], rc[3], rc[4], rc[5], rc[6], rc[7]); |
|
1792 TInt diff = (TInt)(qc - (totrc+cc)); |
|
1793 TEST_RESULT1(diff==0, "Counts mismatched, diff=%d", diff); |
|
1794 TEST_RESULT(!(f&TDfcX::EFlag_Tied) || xfc==0, "Exclusion Failure!"); |
|
1795 d->iQueueCount = 0; |
|
1796 memclr(d->iRunCount, sizeof(d->iRunCount)); |
|
1797 d->iCancelCount = 0; |
|
1798 d->iMaxTime = 0; |
|
1799 d->iSumTime = 0; |
|
1800 } |
|
1801 if (!iRandomTimeLimit) |
|
1802 iRandomTimeLimit = maxavg + (maxavg>>1); |
|
1803 } |
|
1804 |
|
1805 void TDfcStress::Run() |
|
1806 { |
|
1807 TInt i; |
|
1808 NThread* t; |
|
1809 iStop = FALSE; |
|
1810 iMode = 0; |
|
1811 TInt num_cpus = NKern::NumberOfCpus(); |
|
1812 iRunning = num_cpus; |
|
1813 for (i=0; i<KMaxCpus; ++i) |
|
1814 { |
|
1815 t = iThread[i]; |
|
1816 if (t) |
|
1817 NKern::ThreadResume(t); |
|
1818 } |
|
1819 TEST_PRINT("Threads resumed"); |
|
1820 |
|
1821 |
|
1822 DoTestPhase(0x00, 10000, 1); |
|
1823 if (iTimerTest) |
|
1824 { |
|
1825 const TInt N = 20; |
|
1826 DoTestPhase(EMode_AllowCancel|EMode_AllowEnque|EMode_Recycle, 10000, N); |
|
1827 DoTestPhase(EMode_AllowCancel|EMode_AllowEnque|EMode_Wait|EMode_Recycle, 10000, N); |
|
1828 DoTestPhase(EMode_AllowCancel|EMode_AllowEnque|EMode_Recycle|EMode_SelfMigrate, 10000, N); |
|
1829 DoTestPhase(EMode_AllowCancel|EMode_AllowEnque|EMode_Wait|EMode_Recycle|EMode_SelfMigrate, 10000, N); |
|
1830 DoTestPhase(EMode_AllowCancel|EMode_AllowEnque, 10000, N); |
|
1831 DoTestPhase(EMode_AllowCancel|EMode_AllowEnque|EMode_Wait, 10000, N); |
|
1832 DoTestPhase(EMode_AllowCancel|EMode_AllowEnque|EMode_SelfMigrate, 10000, N); |
|
1833 DoTestPhase(EMode_AllowCancel|EMode_AllowEnque|EMode_Wait|EMode_SelfMigrate, 10000, N); |
|
1834 } |
|
1835 else |
|
1836 { |
|
1837 DoTestPhase(EMode_AllowCancel|EMode_AllowEnque, 10000, 20); |
|
1838 DoTestPhase(EMode_AllowCancel|EMode_AllowIdle|EMode_AllowEnque, 10000, 20); |
|
1839 DoTestPhase(EMode_AllowIdle|EMode_AllowEnque, 10000, 20); |
|
1840 DoTestPhase(EMode_AllowCancel|EMode_AllowIdle, 10000, 20); |
|
1841 DoTestPhase(EMode_AllowCancel|EMode_Wait, 10000, 20); |
|
1842 DoTestPhase(EMode_AllowCancel, 10000, 20); |
|
1843 DoTestPhase(EMode_AllowCancel|EMode_AllowIdle|EMode_AllowEnque|EMode_Recycle, 10000, 20); |
|
1844 } |
|
1845 |
|
1846 iMode = EMode_Exit; |
|
1847 TEST_PRINT("Terminating threads"); |
|
1848 for (i=0; i<num_cpus; ++i) |
|
1849 NKern::FSWait(iExitSem); |
|
1850 TEST_PRINT("Done"); |
|
1851 } |
|
1852 |
|
1853 void DoStressTest(TBool aTimerTest) |
|
1854 { |
|
1855 TEST_PRINT("Stress test..."); |
|
1856 TInt ndfcs=0; |
|
1857 TInt ndfcq=0; |
|
1858 switch (NKern::NumberOfCpus()) |
|
1859 { |
|
1860 case 1: ndfcs=16; ndfcq=2; break; |
|
1861 case 2: ndfcs=16; ndfcq=2; break; |
|
1862 case 3: ndfcs=24; ndfcq=2; break; |
|
1863 case 4: ndfcs=32; ndfcq=3; break; |
|
1864 case 5: ndfcs=32; ndfcq=3; break; |
|
1865 case 6: ndfcs=48; ndfcq=4; break; |
|
1866 case 7: ndfcs=48; ndfcq=4; break; |
|
1867 case 8: ndfcs=48; ndfcq=4; break; |
|
1868 default: |
|
1869 __NK_ASSERT_ALWAYS(0); |
|
1870 break; |
|
1871 } |
|
1872 TDfcStress* ds = TDfcStress::New(ndfcs, ndfcq, aTimerTest); |
|
1873 ds->Run(); |
|
1874 ds->Close(); |
|
1875 } |
|
1876 |
|
1877 #endif |
|
1878 |
|
1879 void TestDFCs() |
|
1880 { |
|
1881 TEST_PRINT("Testing DFCs..."); |
|
1882 |
|
1883 TTestDfc::Buffer = CircBuf::New(TTestDfc::EBufferSlots); |
|
1884 TInt cpu; |
|
1885 (void)cpu; |
|
1886 #ifdef __SMP__ |
|
1887 DoStressTest(TRUE); |
|
1888 #endif |
|
1889 |
|
1890 DoDFCTest1(); |
|
1891 DoDFCTest2(); |
|
1892 for_each_cpu(cpu) |
|
1893 { |
|
1894 DoDFCTest3(cpu); |
|
1895 } |
|
1896 DoIDFCTest1(); |
|
1897 for_each_cpu(cpu) |
|
1898 { |
|
1899 DoIdleDFCTest1(cpu); |
|
1900 } |
|
1901 DoIdleDFCTest2(); |
|
1902 |
|
1903 #ifdef __SMP__ |
|
1904 DoStressTest(FALSE); |
|
1905 #endif |
|
1906 |
|
1907 delete TTestDfc::Buffer; |
|
1908 TTestDfc::Buffer = 0; |
|
1909 } |