1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/kerneltest/e32test/nkernsa/testdfc.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,1909 @@
1.4 +// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of the License "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// e32test\nkernsa\testdfc.cpp
1.18 +//
1.19 +//
1.20 +
1.21 +#include <nktest/nkutils.h>
1.22 +
1.23 +#ifndef __SMP__
1.24 +#define iNThreadBaseSpare7 iSpare7
1.25 +class NSchedulable;
1.26 +#endif
1.27 +
1.28 +extern "C" TUint32 set_bit0_if_nonnull(TUint32&);
1.29 +extern "C" void flip_bit0(TUint32&);
1.30 +extern "C" TUint32 swap_out_if_bit0_clear(TUint32&);
1.31 +
1.32 +#ifdef __SMP__
1.33 +class TAddDfc : public TGenericIPI
1.34 +#else
1.35 +class TAddDfc : public NTimer
1.36 +#endif
1.37 + {
1.38 +public:
1.39 + TAddDfc();
1.40 + TDfc* Add(TDfc* aDfc, TUint32 aCpuMask);
1.41 + static TAddDfc* New();
1.42 +#ifdef __SMP__
1.43 + static void Isr(TGenericIPI*);
1.44 +#else
1.45 + static void TimerCallBack(TAny*);
1.46 + void WaitCompletion();
1.47 +#endif
1.48 +public:
1.49 + TDfc* iDfc;
1.50 + };
1.51 +
1.52 +TAddDfc::TAddDfc()
1.53 +#ifdef __SMP__
1.54 + : iDfc(0)
1.55 +#else
1.56 + : NTimer(&TimerCallBack, this),
1.57 + iDfc(0)
1.58 +#endif
1.59 + {
1.60 + }
1.61 +
1.62 +TAddDfc* TAddDfc::New()
1.63 + {
1.64 + TAddDfc* p = new TAddDfc;
1.65 + TEST_OOM(p);
1.66 + return p;
1.67 + }
1.68 +
1.69 +#ifdef __SMP__
1.70 +void TAddDfc::Isr(TGenericIPI* a)
1.71 +#else
1.72 +void TAddDfc::TimerCallBack(TAny* a)
1.73 +#endif
1.74 + {
1.75 + TAddDfc& adder = *(TAddDfc*)a;
1.76 + TDfc* dfc = (TDfc*)__e32_atomic_swp_ord_ptr(&adder.iDfc, 0);
1.77 + if (dfc)
1.78 + dfc->Add();
1.79 + }
1.80 +
1.81 +TDfc* TAddDfc::Add(TDfc* aDfc, TUint32 aCpuMask)
1.82 + {
1.83 + TDfc* old = (TDfc*)__e32_atomic_swp_ord_ptr(&iDfc, aDfc);
1.84 +#ifdef __SMP__
1.85 + Queue(&Isr, aCpuMask);
1.86 +#else
1.87 + (void)aCpuMask;
1.88 + OneShot(1);
1.89 +#endif
1.90 + return old;
1.91 + }
1.92 +
1.93 +#ifndef __SMP__
1.94 +void TAddDfc::WaitCompletion()
1.95 + {
1.96 + while (iDfc)
1.97 + {}
1.98 + }
1.99 +#endif
1.100 +
1.101 +class TTestDfc : public TDfc
1.102 + {
1.103 +public:
1.104 + TTestDfc(TUint aId);
1.105 + TTestDfc(TUint aId, TDfcQue* aQ, TInt aPri);
1.106 + static void Run(TAny* aPtr);
1.107 +
1.108 + static void CheckEmpty(TInt aLine);
1.109 + static void CheckFirstEntry(TInt aLine, TUint32 aCpu, TUint32 aContext, TDfcQue* aQ, TUint32 aId);
1.110 +
1.111 + static CircBuf* Buffer;
1.112 + static volatile TBool Full;
1.113 + static volatile TUint32 Last;
1.114 +
1.115 + enum {EBufferSlots=1024};
1.116 + };
1.117 +
1.118 +#define CHECK_EMPTY() TTestDfc::CheckEmpty(__LINE__)
1.119 +#define CHECK_FIRST_ENTRY(cpu, ctx, q, id) TTestDfc::CheckFirstEntry(__LINE__, cpu, ctx, q, id)
1.120 +
1.121 +CircBuf* TTestDfc::Buffer;
1.122 +volatile TBool TTestDfc::Full = FALSE;
1.123 +volatile TUint32 TTestDfc::Last;
1.124 +
1.125 +TTestDfc::TTestDfc(TUint aId)
1.126 + : TDfc(&Run, (TAny*)aId)
1.127 + {
1.128 + }
1.129 +
1.130 +TTestDfc::TTestDfc(TUint aId, TDfcQue* aQ, TInt aPri)
1.131 + : TDfc(&Run, (TAny*)aId, aQ, aPri)
1.132 + {
1.133 + }
1.134 +
1.135 +void TTestDfc::Run(TAny* aPtr)
1.136 + {
1.137 + TUint32 id = (TUint32)aPtr;
1.138 + TUint32 tid = 0;
1.139 + TUint32 ctx = NKern::CurrentContext();
1.140 + TUint32 cpu = NKern::CurrentCpu();
1.141 + if (ctx == NKern::EThread)
1.142 + {
1.143 + NThread* t = NKern::CurrentThread();
1.144 + tid = t->iNThreadBaseSpare7;
1.145 + }
1.146 + TUint32 x = (cpu<<24) | (ctx<<16) | (tid<<8) | id;
1.147 + TInt r = Buffer->TryPut(x);
1.148 + if (r != KErrNone)
1.149 + Full = TRUE;
1.150 + Last = id;
1.151 + }
1.152 +
1.153 +void TTestDfc::CheckEmpty(TInt aLine)
1.154 + {
1.155 + TInt c = Buffer->Count();
1.156 + TUint32 x;
1.157 + Buffer->TryGet(x);
1.158 + if (c!=0)
1.159 + {
1.160 + TEST_PRINT3("Line %d Buffer not empty C:%d X:%08x", aLine, c, x);
1.161 + }
1.162 + }
1.163 +
1.164 +void TTestDfc::CheckFirstEntry(TInt aLine, TUint32 aCpu, TUint32 aContext, TDfcQue* aQ, TUint32 aId)
1.165 + {
1.166 + TUint32 tid = aQ ? aQ->iThread->iNThreadBaseSpare7 : 0;
1.167 + TUint32 expected = (aCpu<<24) | (aContext<<16) | (tid << 8) | aId;
1.168 + TUint32 x;
1.169 + TInt r = Buffer->TryGet(x);
1.170 + if (r!=KErrNone)
1.171 + {
1.172 + TEST_PRINT2("Line %d Buffer empty, Expected %08x", aLine, expected);
1.173 + }
1.174 + else if (x != expected)
1.175 + {
1.176 + TEST_PRINT3("Line %d Got %08x Expected %08x", aLine, x, expected);
1.177 + }
1.178 + }
1.179 +
1.180 +class TPauseIDFC : public TDfc
1.181 + {
1.182 +public:
1.183 + TPauseIDFC();
1.184 + void Pause(TInt aCpu);
1.185 + void Release();
1.186 + static void Run(TAny*);
1.187 +public:
1.188 + volatile TInt iFlag;
1.189 + };
1.190 +
1.191 +TPauseIDFC::TPauseIDFC()
1.192 + : TDfc(&Run, this),
1.193 + iFlag(-1)
1.194 + {
1.195 + }
1.196 +
1.197 +void TPauseIDFC::Pause(TInt aCpu)
1.198 + {
1.199 + TAddDfc adder;
1.200 + iFlag = -1;
1.201 + __e32_memory_barrier();
1.202 + adder.Add(this, 1u<<aCpu);
1.203 + adder.WaitCompletion();
1.204 + while (iFlag == -1)
1.205 + {}
1.206 + }
1.207 +
1.208 +void TPauseIDFC::Release()
1.209 + {
1.210 + __e32_atomic_store_ord32(&iFlag, 1);
1.211 + }
1.212 +
1.213 +void TPauseIDFC::Run(TAny* aPtr)
1.214 + {
1.215 + TPauseIDFC* p = (TPauseIDFC*)aPtr;
1.216 + __e32_atomic_store_ord32(&p->iFlag, 0);
1.217 + while (__e32_atomic_load_acq32(&p->iFlag) == 0)
1.218 + {}
1.219 + }
1.220 +
1.221 +class TPauseDFC : public TDfc
1.222 + {
1.223 +public:
1.224 + TPauseDFC(TDfcQue* aQ);
1.225 + void Pause(TInt aWait=0);
1.226 + void BusyPause();
1.227 + void Release();
1.228 + static void Run(TAny*);
1.229 +public:
1.230 + NFastSemaphore* volatile iSem;
1.231 + volatile TInt iWait;
1.232 + };
1.233 +
1.234 +TPauseDFC::TPauseDFC(TDfcQue* aQ)
1.235 + : TDfc(&Run, this, aQ, 0),
1.236 + iSem(0)
1.237 + {
1.238 + }
1.239 +
1.240 +void TPauseDFC::Pause(TInt aWait)
1.241 + {
1.242 + iWait = aWait;
1.243 + NFastSemaphore entrySem(0);
1.244 + iSem = &entrySem;
1.245 + Enque();
1.246 + NKern::FSWait(&entrySem);
1.247 + }
1.248 +
1.249 +void TPauseDFC::BusyPause()
1.250 + {
1.251 + volatile TInt& flag = (volatile TInt&)iSem;
1.252 + __e32_atomic_store_ord32(&flag, 0xfffffffe);
1.253 + Enque();
1.254 + while (__e32_atomic_load_acq32(&flag) == 0xfffffffe)
1.255 + {}
1.256 + }
1.257 +
1.258 +void TPauseDFC::Release()
1.259 + {
1.260 + NFastSemaphore* s = (NFastSemaphore*)__e32_atomic_swp_ord_ptr(&iSem, 0);
1.261 + if (((TInt)s)==-1)
1.262 + {
1.263 + volatile TInt& flag = (volatile TInt&)iSem;
1.264 + __e32_atomic_store_ord32(&flag, 0);
1.265 + }
1.266 + else
1.267 + NKern::FSSignal(s);
1.268 + }
1.269 +
1.270 +void TPauseDFC::Run(TAny* aPtr)
1.271 + {
1.272 + TPauseDFC* p = (TPauseDFC*)aPtr;
1.273 + volatile TInt& flag = (volatile TInt&)p->iSem;
1.274 + if (flag == -2)
1.275 + {
1.276 + flag = -1;
1.277 + __e32_memory_barrier();
1.278 + while (flag == -1)
1.279 + {}
1.280 + }
1.281 + else
1.282 + {
1.283 + NFastSemaphore exitSem(0);
1.284 + NFastSemaphore* s = (NFastSemaphore*)__e32_atomic_swp_ord_ptr(&p->iSem, &exitSem);
1.285 + if (p->iWait)
1.286 + {
1.287 + nfcfspin(__microseconds_to_norm_fast_counter(10000));
1.288 + NKern::Sleep(p->iWait);
1.289 + }
1.290 + NKern::FSSignal(s);
1.291 + NKern::FSWait(&exitSem);
1.292 + }
1.293 + }
1.294 +
1.295 +void DoDFCTest1()
1.296 + {
1.297 + TEST_PRINT("DFCTest1");
1.298 + TInt cpu;
1.299 + for_each_cpu(cpu)
1.300 + {
1.301 + TDfcQue* q = CreateDfcQ("DfcQ0", 1, cpu);
1.302 + DestroyDfcQ(q);
1.303 + q = CreateDfcQ("DfcQ1", 32, cpu);
1.304 + DestroyDfcQ(q);
1.305 + }
1.306 + }
1.307 +
1.308 +TBool QueueDfc(TDfc* aDfc, TInt aMode, TBool aExRet)
1.309 + {
1.310 + if (aMode==0)
1.311 + return !aExRet == !aDfc->Enque();
1.312 + else if (aMode>0)
1.313 + {
1.314 + TAddDfc adder;
1.315 + TInt cpu = aMode - 1;
1.316 + adder.Add(aDfc, 1u<<cpu);
1.317 + adder.WaitCompletion();
1.318 + nfcfspin(__microseconds_to_norm_fast_counter(10000));
1.319 + return TRUE;
1.320 + }
1.321 + else if (aMode==-1)
1.322 + {
1.323 + NKern::Lock();
1.324 + TBool ret = aDfc->Add();
1.325 + NKern::Unlock();
1.326 + return !aExRet == !ret;
1.327 + }
1.328 + return FALSE;
1.329 + }
1.330 +
1.331 +#define QUEUE_DFC(dfc, mode, exret) TEST_RESULT(QueueDfc(dfc,mode,exret),"")
1.332 +
1.333 +void DoDFCTest2()
1.334 + {
1.335 + TEST_PRINT("DFCTest2");
1.336 + TInt num_cpus = NKern::NumberOfCpus();
1.337 + TInt this_cpu = NKern::CurrentCpu();
1.338 + TDfcQue* q;
1.339 + q = CreateDfcQ("DfcQ2", 1, this_cpu);
1.340 + TEST_OOM(q);
1.341 + q->iThread->iNThreadBaseSpare7 = 1;
1.342 +
1.343 + TTestDfc* d1 = new TTestDfc(1, q, 1);
1.344 + TEST_OOM(d1);
1.345 + TEST_RESULT(!d1->IsIDFC(), "");
1.346 + TTestDfc* d2 = new TTestDfc(2, q, 2);
1.347 + TEST_OOM(d2);
1.348 + TEST_RESULT(!d2->IsIDFC(), "");
1.349 + TTestDfc* d3 = new TTestDfc(3, q, 2);
1.350 + TEST_OOM(d3);
1.351 + TEST_RESULT(!d3->IsIDFC(), "");
1.352 + TTestDfc* d4 = new TTestDfc(4, q, 3);
1.353 + TEST_OOM(d4);
1.354 + TEST_RESULT(!d4->IsIDFC(), "");
1.355 +
1.356 + TInt mode;
1.357 + for (mode=-1; mode<=num_cpus; ++mode)
1.358 + {
1.359 + TEST_PRINT1("Mode %d", mode);
1.360 + CHECK_EMPTY();
1.361 + TEST_RESULT(!d1->Queued(), "");
1.362 + QUEUE_DFC(d1, mode, TRUE);
1.363 + TEST_RESULT(d1->Queued(), "");
1.364 + QUEUE_DFC(d1, mode, FALSE);
1.365 + TEST_RESULT(d1->Queued(), "");
1.366 + QUEUE_DFC(d2, mode, TRUE);
1.367 + QUEUE_DFC(d3, mode, TRUE);
1.368 + QUEUE_DFC(d4, mode, TRUE);
1.369 + CHECK_EMPTY();
1.370 + NKern::Sleep(30);
1.371 + CHECK_FIRST_ENTRY(this_cpu, NKern::EThread, q, 4);
1.372 + CHECK_FIRST_ENTRY(this_cpu, NKern::EThread, q, 2);
1.373 + CHECK_FIRST_ENTRY(this_cpu, NKern::EThread, q, 3);
1.374 + CHECK_FIRST_ENTRY(this_cpu, NKern::EThread, q, 1);
1.375 + CHECK_EMPTY();
1.376 + QUEUE_DFC(d4, mode, TRUE);
1.377 + QUEUE_DFC(d3, mode, TRUE);
1.378 + QUEUE_DFC(d2, mode, TRUE);
1.379 + QUEUE_DFC(d1, mode, TRUE);
1.380 + CHECK_EMPTY();
1.381 + NKern::Sleep(30);
1.382 + CHECK_FIRST_ENTRY(this_cpu, NKern::EThread, q, 4);
1.383 + CHECK_FIRST_ENTRY(this_cpu, NKern::EThread, q, 3);
1.384 + CHECK_FIRST_ENTRY(this_cpu, NKern::EThread, q, 2);
1.385 + CHECK_FIRST_ENTRY(this_cpu, NKern::EThread, q, 1);
1.386 + CHECK_EMPTY();
1.387 + QUEUE_DFC(d4, mode, TRUE);
1.388 + QUEUE_DFC(d3, mode, TRUE);
1.389 + QUEUE_DFC(d2, mode, TRUE);
1.390 + QUEUE_DFC(d1, mode, TRUE);
1.391 + TEST_RESULT(d4->Queued(), "");
1.392 + TEST_RESULT(d4->Cancel(), "");
1.393 + TEST_RESULT(!d4->Cancel(), "");
1.394 + TEST_RESULT(!d4->Queued(), "");
1.395 + CHECK_EMPTY();
1.396 + NKern::Sleep(30);
1.397 + CHECK_FIRST_ENTRY(this_cpu, NKern::EThread, q, 3);
1.398 + CHECK_FIRST_ENTRY(this_cpu, NKern::EThread, q, 2);
1.399 + CHECK_FIRST_ENTRY(this_cpu, NKern::EThread, q, 1);
1.400 + CHECK_EMPTY();
1.401 + QUEUE_DFC(d4, mode, TRUE);
1.402 + QUEUE_DFC(d3, mode, TRUE);
1.403 + QUEUE_DFC(d2, mode, TRUE);
1.404 + QUEUE_DFC(d1, mode, TRUE);
1.405 + TEST_RESULT(d3->Queued(), "");
1.406 + TEST_RESULT(d3->Cancel(), "");
1.407 + TEST_RESULT(!d3->Queued(), "");
1.408 + CHECK_EMPTY();
1.409 + NKern::Sleep(30);
1.410 + CHECK_FIRST_ENTRY(this_cpu, NKern::EThread, q, 4);
1.411 + CHECK_FIRST_ENTRY(this_cpu, NKern::EThread, q, 2);
1.412 + CHECK_FIRST_ENTRY(this_cpu, NKern::EThread, q, 1);
1.413 + CHECK_EMPTY();
1.414 + QUEUE_DFC(d4, mode, TRUE);
1.415 + QUEUE_DFC(d3, mode, TRUE);
1.416 + QUEUE_DFC(d2, mode, TRUE);
1.417 + QUEUE_DFC(d1, mode, TRUE);
1.418 + TEST_RESULT(d3->Queued(), "");
1.419 + TEST_RESULT(d2->Queued(), "");
1.420 + TEST_RESULT(d3->Cancel(), "");
1.421 + TEST_RESULT(d2->Cancel(), "");
1.422 + TEST_RESULT(!d3->Queued(), "");
1.423 + TEST_RESULT(!d2->Queued(), "");
1.424 + CHECK_EMPTY();
1.425 + NKern::Sleep(30);
1.426 + CHECK_FIRST_ENTRY(this_cpu, NKern::EThread, q, 4);
1.427 + CHECK_FIRST_ENTRY(this_cpu, NKern::EThread, q, 1);
1.428 + CHECK_EMPTY();
1.429 + QUEUE_DFC(d4, mode, TRUE);
1.430 + QUEUE_DFC(d3, mode, TRUE);
1.431 + QUEUE_DFC(d2, mode, TRUE);
1.432 + QUEUE_DFC(d1, mode, TRUE);
1.433 + TEST_RESULT(d3->Cancel(), "");
1.434 + TEST_RESULT(d2->Cancel(), "");
1.435 + TEST_RESULT(d4->Cancel(), "");
1.436 + TEST_RESULT(d1->Cancel(), "");
1.437 + CHECK_EMPTY();
1.438 + NKern::Sleep(30);
1.439 + CHECK_EMPTY();
1.440 + QUEUE_DFC(d4, mode, TRUE);
1.441 + QUEUE_DFC(d3, mode, TRUE);
1.442 + QUEUE_DFC(d2, mode, TRUE);
1.443 + QUEUE_DFC(d1, mode, TRUE);
1.444 + TEST_RESULT(d1->Queued(), "");
1.445 + TEST_RESULT(d3->Cancel(), "");
1.446 + TEST_RESULT(d2->Cancel(), "");
1.447 + TEST_RESULT(d4->Cancel(), "");
1.448 + TEST_RESULT(d1->Cancel(), "");
1.449 + TEST_RESULT(!d1->Queued(), "");
1.450 + QUEUE_DFC(d1, mode, TRUE);
1.451 + TEST_RESULT(d1->Queued(), "");
1.452 + QUEUE_DFC(d1, mode, FALSE);
1.453 + TEST_RESULT(d1->Queued(), "");
1.454 + CHECK_EMPTY();
1.455 + NKern::Sleep(30);
1.456 + CHECK_FIRST_ENTRY(this_cpu, NKern::EThread, q, 1);
1.457 + CHECK_EMPTY();
1.458 + }
1.459 +
1.460 + delete d4;
1.461 + delete d3;
1.462 + delete d2;
1.463 + delete d1;
1.464 + DestroyDfcQ(q);
1.465 + }
1.466 +
1.467 +void DoDFCTest3(TInt aCpu)
1.468 + {
1.469 + TEST_PRINT1("DFCTest3 CPU %d", aCpu);
1.470 + TInt num_cpus = NKern::NumberOfCpus();
1.471 + TInt this_cpu = NKern::CurrentCpu();
1.472 + TBool same_cpu = (aCpu==this_cpu);
1.473 + TDfcQue* q;
1.474 + q = CreateDfcQ("DfcQ2", 32, aCpu);
1.475 + TEST_OOM(q);
1.476 + q->iThread->iNThreadBaseSpare7 = 1;
1.477 + TPauseDFC pauser(q);
1.478 +
1.479 + TTestDfc* d1 = new TTestDfc(1, q, 1);
1.480 + TEST_OOM(d1);
1.481 + TEST_RESULT(!d1->IsIDFC(), "");
1.482 + TTestDfc* d2 = new TTestDfc(2, q, 2);
1.483 + TEST_OOM(d2);
1.484 + TEST_RESULT(!d2->IsIDFC(), "");
1.485 + TTestDfc* d3 = new TTestDfc(3, q, 2);
1.486 + TEST_OOM(d3);
1.487 + TEST_RESULT(!d3->IsIDFC(), "");
1.488 + TTestDfc* d4 = new TTestDfc(4, q, 3);
1.489 + TEST_OOM(d4);
1.490 + TEST_RESULT(!d4->IsIDFC(), "");
1.491 +
1.492 + TInt mode;
1.493 + for (mode=-1; mode<=num_cpus; ++mode)
1.494 + {
1.495 + TEST_PRINT1("Mode %d", mode);
1.496 + CHECK_EMPTY();
1.497 + TEST_RESULT(!d1->Queued(), "");
1.498 + QUEUE_DFC(d1, mode, TRUE);
1.499 + if (!same_cpu)
1.500 + while (d1->Queued()) {}
1.501 + TEST_RESULT(!d1->Queued(), "");
1.502 + QUEUE_DFC(d1, mode, TRUE);
1.503 + if (!same_cpu)
1.504 + while (d1->Queued()) {}
1.505 + TEST_RESULT(!d1->Queued(), "");
1.506 + QUEUE_DFC(d2, mode, TRUE);
1.507 + if (!same_cpu)
1.508 + while (d2->Queued()) {}
1.509 + QUEUE_DFC(d3, mode, TRUE);
1.510 + if (!same_cpu)
1.511 + while (d3->Queued()) {}
1.512 + QUEUE_DFC(d4, mode, TRUE);
1.513 + if (!same_cpu)
1.514 + while (d4->Queued()) {}
1.515 + CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 1);
1.516 + CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 1);
1.517 + CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 2);
1.518 + CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 3);
1.519 + CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 4);
1.520 + CHECK_EMPTY();
1.521 + QUEUE_DFC(d4, mode, TRUE);
1.522 + QUEUE_DFC(d3, mode, TRUE);
1.523 + QUEUE_DFC(d2, mode, TRUE);
1.524 + QUEUE_DFC(d1, mode, TRUE);
1.525 + if (!same_cpu)
1.526 + while (d1->Queued()) {}
1.527 + CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 4);
1.528 + CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 3);
1.529 + CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 2);
1.530 + CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 1);
1.531 + CHECK_EMPTY();
1.532 + QUEUE_DFC(d4, mode, TRUE);
1.533 + QUEUE_DFC(d3, mode, TRUE);
1.534 + QUEUE_DFC(d2, mode, TRUE);
1.535 + QUEUE_DFC(d1, mode, TRUE);
1.536 + if (!same_cpu)
1.537 + while (d1->Queued()) {}
1.538 + TEST_RESULT(!d4->Queued(), "");
1.539 + TEST_RESULT(!d4->Cancel(), "");
1.540 + TEST_RESULT(!d4->Queued(), "");
1.541 + CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 4);
1.542 + CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 3);
1.543 + CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 2);
1.544 + CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 1);
1.545 + CHECK_EMPTY();
1.546 + pauser.Pause();
1.547 + CHECK_EMPTY();
1.548 + TEST_RESULT(!d1->Queued(), "");
1.549 + QUEUE_DFC(d1, mode, TRUE);
1.550 + TEST_RESULT(d1->Queued(), "");
1.551 + QUEUE_DFC(d1, mode, FALSE);
1.552 + TEST_RESULT(d1->Queued(), "");
1.553 + QUEUE_DFC(d2, mode, TRUE);
1.554 + QUEUE_DFC(d3, mode, TRUE);
1.555 + QUEUE_DFC(d4, mode, TRUE);
1.556 + QUEUE_DFC(d4, mode, FALSE);
1.557 + CHECK_EMPTY();
1.558 + pauser.Release();
1.559 + pauser.Pause();
1.560 + pauser.Release();
1.561 + CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 4);
1.562 + CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 2);
1.563 + CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 3);
1.564 + CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 1);
1.565 + CHECK_EMPTY();
1.566 + pauser.Pause();
1.567 + CHECK_EMPTY();
1.568 + TEST_RESULT(!d1->Queued(), "");
1.569 + QUEUE_DFC(d1, mode, TRUE);
1.570 + TEST_RESULT(d1->Queued(), "");
1.571 + QUEUE_DFC(d1, mode, FALSE);
1.572 + TEST_RESULT(d1->Queued(), "");
1.573 + QUEUE_DFC(d4, mode, TRUE);
1.574 + QUEUE_DFC(d3, mode, TRUE);
1.575 + QUEUE_DFC(d2, mode, TRUE);
1.576 + CHECK_EMPTY();
1.577 + pauser.Release();
1.578 + pauser.Pause();
1.579 + pauser.Release();
1.580 + CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 4);
1.581 + CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 3);
1.582 + CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 2);
1.583 + CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 1);
1.584 + CHECK_EMPTY();
1.585 + pauser.Pause();
1.586 + CHECK_EMPTY();
1.587 + TEST_RESULT(!d1->Queued(), "");
1.588 + QUEUE_DFC(d1, mode, TRUE);
1.589 + TEST_RESULT(d1->Queued(), "");
1.590 + QUEUE_DFC(d1, mode, FALSE);
1.591 + TEST_RESULT(d1->Queued(), "");
1.592 + QUEUE_DFC(d2, mode, TRUE);
1.593 + QUEUE_DFC(d3, mode, TRUE);
1.594 + QUEUE_DFC(d4, mode, TRUE);
1.595 + CHECK_EMPTY();
1.596 + TEST_RESULT(d1->Cancel(), "");
1.597 + TEST_RESULT(!d1->Queued(), "");
1.598 + pauser.Release();
1.599 + pauser.Pause();
1.600 + pauser.Release();
1.601 + CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 4);
1.602 + CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 2);
1.603 + CHECK_FIRST_ENTRY(aCpu, NKern::EThread, q, 3);
1.604 + CHECK_EMPTY();
1.605 + }
1.606 +
1.607 + delete d4;
1.608 + delete d3;
1.609 + delete d2;
1.610 + delete d1;
1.611 + DestroyDfcQ(q);
1.612 + }
1.613 +
1.614 +TBool QueueIDfc(TDfc* aDfc, TInt aMode, TBool aExRet)
1.615 + {
1.616 + if (aMode==0)
1.617 + return !aExRet == !aDfc->RawAdd();
1.618 + else if (aMode>0)
1.619 + {
1.620 + TTestDfc::Last = 0xffffffffu;
1.621 + TAddDfc adder;
1.622 + TInt cpu = (aMode&0xff) - 1;
1.623 + adder.Add(aDfc, 1u<<cpu);
1.624 + adder.WaitCompletion();
1.625 + if (!(aMode&0x100))
1.626 + {
1.627 + while (TTestDfc::Last != (TUint32)aDfc->iPtr)
1.628 + {}
1.629 + }
1.630 + return TRUE;
1.631 + }
1.632 + else if (aMode==-1)
1.633 + {
1.634 + NKern::Lock();
1.635 + TBool ret = aDfc->Add();
1.636 + NKern::Unlock();
1.637 + return !aExRet == !ret;
1.638 + }
1.639 + return FALSE;
1.640 + }
1.641 +
1.642 +#define QUEUE_IDFC(dfc, mode, exret) TEST_RESULT(QueueIDfc(dfc,mode,exret),"")
1.643 +
1.644 +void DoIDFCTest1()
1.645 + {
1.646 + TEST_PRINT("IDFCTest1");
1.647 +
1.648 + TInt num_cpus = NKern::NumberOfCpus();
1.649 + TInt this_cpu = NKern::CurrentCpu();
1.650 +
1.651 + TTestDfc* d1 = new TTestDfc(1);
1.652 + TEST_OOM(d1);
1.653 + TEST_RESULT(d1->IsIDFC(), "");
1.654 + TTestDfc* d2 = new TTestDfc(2);
1.655 + TEST_OOM(d2);
1.656 + TEST_RESULT(d2->IsIDFC(), "");
1.657 + TTestDfc* d3 = new TTestDfc(3);
1.658 + TEST_OOM(d3);
1.659 + TEST_RESULT(d3->IsIDFC(), "");
1.660 + TTestDfc* d4 = new TTestDfc(4);
1.661 + TEST_OOM(d4);
1.662 + TEST_RESULT(d4->IsIDFC(), "");
1.663 +
1.664 + TInt mode;
1.665 + for (mode=-1; mode<=num_cpus; ++mode)
1.666 + {
1.667 + TInt xcpu = (mode>0) ? (mode-1) : this_cpu;
1.668 + TEST_PRINT1("Mode %d", mode);
1.669 + CHECK_EMPTY();
1.670 + TEST_RESULT(!d1->Queued(), "");
1.671 + QUEUE_IDFC(d1, mode, TRUE);
1.672 + TEST_RESULT(!d1->Queued(), "");
1.673 + QUEUE_IDFC(d1, mode, TRUE);
1.674 + TEST_RESULT(!d1->Queued(), "");
1.675 + QUEUE_IDFC(d2, mode, TRUE);
1.676 + QUEUE_IDFC(d3, mode, TRUE);
1.677 + QUEUE_IDFC(d4, mode, TRUE);
1.678 + CHECK_FIRST_ENTRY(xcpu, NKern::EIDFC, 0, 1);
1.679 + CHECK_FIRST_ENTRY(xcpu, NKern::EIDFC, 0, 1);
1.680 + CHECK_FIRST_ENTRY(xcpu, NKern::EIDFC, 0, 2);
1.681 + CHECK_FIRST_ENTRY(xcpu, NKern::EIDFC, 0, 3);
1.682 + CHECK_FIRST_ENTRY(xcpu, NKern::EIDFC, 0, 4);
1.683 + CHECK_EMPTY();
1.684 + QUEUE_IDFC(d4, mode, TRUE);
1.685 + QUEUE_IDFC(d3, mode, TRUE);
1.686 + QUEUE_IDFC(d2, mode, TRUE);
1.687 + QUEUE_IDFC(d1, mode, TRUE);
1.688 + CHECK_FIRST_ENTRY(xcpu, NKern::EIDFC, 0, 4);
1.689 + CHECK_FIRST_ENTRY(xcpu, NKern::EIDFC, 0, 3);
1.690 + CHECK_FIRST_ENTRY(xcpu, NKern::EIDFC, 0, 2);
1.691 + CHECK_FIRST_ENTRY(xcpu, NKern::EIDFC, 0, 1);
1.692 + CHECK_EMPTY();
1.693 + }
1.694 + TInt irq = NKern::DisableAllInterrupts();
1.695 + TEST_RESULT(d1->RawAdd(), "");
1.696 + TEST_RESULT(d1->Queued(), "");
1.697 + CHECK_EMPTY();
1.698 + NKern::RestoreInterrupts(irq);
1.699 + TEST_RESULT(!d1->Queued(), "");
1.700 + CHECK_FIRST_ENTRY(this_cpu, NKern::EIDFC, 0, 1);
1.701 +
1.702 + NKern::Lock();
1.703 + TEST_RESULT(d1->Add(), "");
1.704 + TEST_RESULT(d3->Add(), "");
1.705 + TEST_RESULT(d2->Add(), "");
1.706 + TEST_RESULT(d4->Add(), "");
1.707 + TEST_RESULT(!d1->Add(), "");
1.708 + TEST_RESULT(d1->Queued(), "");
1.709 + TEST_RESULT(d2->Queued(), "");
1.710 + TEST_RESULT(d3->Queued(), "");
1.711 + TEST_RESULT(d4->Queued(), "");
1.712 + CHECK_EMPTY();
1.713 + NKern::Unlock();
1.714 + TEST_RESULT(!d1->Queued(), "");
1.715 + TEST_RESULT(!d2->Queued(), "");
1.716 + TEST_RESULT(!d3->Queued(), "");
1.717 + TEST_RESULT(!d4->Queued(), "");
1.718 + CHECK_FIRST_ENTRY(this_cpu, NKern::EIDFC, 0, 1);
1.719 + CHECK_FIRST_ENTRY(this_cpu, NKern::EIDFC, 0, 3);
1.720 + CHECK_FIRST_ENTRY(this_cpu, NKern::EIDFC, 0, 2);
1.721 + CHECK_FIRST_ENTRY(this_cpu, NKern::EIDFC, 0, 4);
1.722 + CHECK_EMPTY();
1.723 +
1.724 + NKern::Lock();
1.725 + TEST_RESULT(d1->Add(), "");
1.726 + TEST_RESULT(d3->Add(), "");
1.727 + TEST_RESULT(d2->Add(), "");
1.728 + TEST_RESULT(d4->Add(), "");
1.729 + TEST_RESULT(d1->Queued(), "");
1.730 + TEST_RESULT(d2->Queued(), "");
1.731 + TEST_RESULT(d3->Queued(), "");
1.732 + TEST_RESULT(d4->Queued(), "");
1.733 + TEST_RESULT(d3->Cancel(), "");
1.734 + TEST_RESULT(!d3->Queued(), "");
1.735 + TEST_RESULT(!d3->Cancel(), "");
1.736 + CHECK_EMPTY();
1.737 + NKern::Unlock();
1.738 + TEST_RESULT(!d1->Queued(), "");
1.739 + TEST_RESULT(!d2->Queued(), "");
1.740 + TEST_RESULT(!d4->Queued(), "");
1.741 + CHECK_FIRST_ENTRY(this_cpu, NKern::EIDFC, 0, 1);
1.742 + CHECK_FIRST_ENTRY(this_cpu, NKern::EIDFC, 0, 2);
1.743 + CHECK_FIRST_ENTRY(this_cpu, NKern::EIDFC, 0, 4);
1.744 + CHECK_EMPTY();
1.745 +
1.746 + NKern::Lock();
1.747 + TEST_RESULT(d1->Add(), "");
1.748 + TEST_RESULT(d3->Add(), "");
1.749 + TEST_RESULT(d2->Add(), "");
1.750 + TEST_RESULT(d4->Add(), "");
1.751 + TEST_RESULT(d1->Queued(), "");
1.752 + TEST_RESULT(d2->Queued(), "");
1.753 + TEST_RESULT(d3->Queued(), "");
1.754 + TEST_RESULT(d4->Queued(), "");
1.755 + TEST_RESULT(d3->Cancel(), "");
1.756 + TEST_RESULT(d1->Cancel(), "");
1.757 + TEST_RESULT(d2->Cancel(), "");
1.758 + TEST_RESULT(d4->Cancel(), "");
1.759 + TEST_RESULT(!d1->Queued(), "");
1.760 + TEST_RESULT(!d2->Queued(), "");
1.761 + TEST_RESULT(!d3->Queued(), "");
1.762 + TEST_RESULT(!d4->Queued(), "");
1.763 + CHECK_EMPTY();
1.764 + NKern::Unlock();
1.765 + CHECK_EMPTY();
1.766 +
1.767 + TPauseIDFC pauser;
1.768 + TInt cpu;
1.769 + for_each_cpu(cpu)
1.770 + {
1.771 + if (cpu == this_cpu)
1.772 + continue;
1.773 + mode = cpu + 0x101;
1.774 + TEST_PRINT1("CPU %d", cpu);
1.775 + pauser.Pause(cpu);
1.776 + CHECK_EMPTY();
1.777 + TEST_RESULT(!d1->Queued(), "");
1.778 + QUEUE_IDFC(d1, mode, TRUE);
1.779 + TEST_RESULT(d1->Queued(), "");
1.780 + QUEUE_IDFC(d1, mode, FALSE);
1.781 + TEST_RESULT(d1->Queued(), "");
1.782 + QUEUE_IDFC(d2, mode, TRUE);
1.783 + QUEUE_IDFC(d3, mode, TRUE);
1.784 + QUEUE_IDFC(d4, mode, TRUE);
1.785 + CHECK_EMPTY();
1.786 + pauser.Release();
1.787 + pauser.Pause(cpu);
1.788 + pauser.Release();
1.789 + CHECK_FIRST_ENTRY(cpu, NKern::EIDFC, 0, 1);
1.790 + CHECK_FIRST_ENTRY(cpu, NKern::EIDFC, 0, 2);
1.791 + CHECK_FIRST_ENTRY(cpu, NKern::EIDFC, 0, 3);
1.792 + CHECK_FIRST_ENTRY(cpu, NKern::EIDFC, 0, 4);
1.793 + CHECK_EMPTY();
1.794 + pauser.Pause(cpu);
1.795 + CHECK_EMPTY();
1.796 + TEST_RESULT(!d1->Queued(), "");
1.797 + QUEUE_IDFC(d1, mode, TRUE);
1.798 + TEST_RESULT(d1->Queued(), "");
1.799 + QUEUE_IDFC(d2, mode, TRUE);
1.800 + QUEUE_IDFC(d3, mode, TRUE);
1.801 + QUEUE_IDFC(d4, mode, TRUE);
1.802 + TEST_RESULT(d1->Cancel(), "");
1.803 + TEST_RESULT(!d1->Queued(), "");
1.804 + TEST_RESULT(!d1->Cancel(), "");
1.805 + CHECK_EMPTY();
1.806 + pauser.Release();
1.807 + pauser.Pause(cpu);
1.808 + pauser.Release();
1.809 + CHECK_FIRST_ENTRY(cpu, NKern::EIDFC, 0, 2);
1.810 + CHECK_FIRST_ENTRY(cpu, NKern::EIDFC, 0, 3);
1.811 + CHECK_FIRST_ENTRY(cpu, NKern::EIDFC, 0, 4);
1.812 + CHECK_EMPTY();
1.813 + pauser.Pause(cpu);
1.814 + CHECK_EMPTY();
1.815 + TEST_RESULT(!d1->Queued(), "");
1.816 + QUEUE_IDFC(d1, mode, TRUE);
1.817 + TEST_RESULT(d1->Queued(), "");
1.818 + QUEUE_IDFC(d2, mode, TRUE);
1.819 + QUEUE_IDFC(d3, mode, TRUE);
1.820 + QUEUE_IDFC(d4, mode, TRUE);
1.821 + TEST_RESULT(d1->Cancel(), "");
1.822 + TEST_RESULT(!d1->Queued(), "");
1.823 + TEST_RESULT(d4->Cancel(), "");
1.824 + TEST_RESULT(d2->Cancel(), "");
1.825 + TEST_RESULT(d3->Cancel(), "");
1.826 + CHECK_EMPTY();
1.827 + pauser.Release();
1.828 + pauser.Pause(cpu);
1.829 + pauser.Release();
1.830 + CHECK_EMPTY();
1.831 + }
1.832 +
1.833 + delete d4;
1.834 + delete d3;
1.835 + delete d2;
1.836 + delete d1;
1.837 + }
1.838 +
1.839 +void DoIdleDFCTest1(TInt aCpu)
1.840 + {
1.841 +#ifdef __SMP__
1.842 + TEST_PRINT2("IdleDFCTest1 CPU %d (%08x)", aCpu, TheScheduler.iCpusNotIdle);
1.843 +#else
1.844 + TEST_PRINT1("IdleDFCTest1 CPU %d (%08x)", aCpu);
1.845 +#endif
1.846 +// TInt num_cpus = NKern::NumberOfCpus();
1.847 + TInt this_cpu = NKern::CurrentCpu();
1.848 + TBool same_cpu = (aCpu==this_cpu);
1.849 + TDfcQue* q = 0;
1.850 + TPauseDFC* pauser = 0;
1.851 + if (!same_cpu)
1.852 + {
1.853 + q = CreateDfcQ("DfcQ3", 1, aCpu);
1.854 + TEST_OOM(q);
1.855 + pauser = new TPauseDFC(q);
1.856 + TEST_OOM(pauser);
1.857 + }
1.858 +
1.859 + TTestDfc* d1 = new TTestDfc(1);
1.860 + TEST_OOM(d1);
1.861 + TEST_RESULT(d1->IsIDFC(), "");
1.862 + TTestDfc* d2 = new TTestDfc(2);
1.863 + TEST_OOM(d2);
1.864 + TEST_RESULT(d2->IsIDFC(), "");
1.865 + TTestDfc* d3 = new TTestDfc(3);
1.866 + TEST_OOM(d3);
1.867 + TEST_RESULT(d3->IsIDFC(), "");
1.868 + TTestDfc* d4 = new TTestDfc(4);
1.869 + TEST_OOM(d4);
1.870 + TEST_RESULT(d4->IsIDFC(), "");
1.871 +
1.872 + TEST_RESULT(!d1->Queued(), "");
1.873 + TEST_RESULT(d1->QueueOnIdle(), "");
1.874 + TEST_RESULT(d1->Queued(), "");
1.875 + TEST_RESULT(!d1->QueueOnIdle(), "");
1.876 + CHECK_EMPTY();
1.877 + if (pauser)
1.878 + pauser->BusyPause();
1.879 + NKern::Sleep(1);
1.880 + if (pauser)
1.881 + TEST_RESULT(d1->Queued(), "");
1.882 + else
1.883 + {
1.884 + TEST_RESULT(!d1->Queued(), "");
1.885 + CHECK_FIRST_ENTRY(this_cpu, NKern::EIDFC, 0, 1);
1.886 + }
1.887 + CHECK_EMPTY();
1.888 + TBool ret = d1->QueueOnIdle();
1.889 + TEST_RESULT(pauser?!ret:ret, "");
1.890 + TEST_RESULT(d1->Queued(), "");
1.891 + TEST_RESULT(d1->Cancel(), "");
1.892 + TEST_RESULT(!d1->Queued(), "");
1.893 + CHECK_EMPTY();
1.894 + NKern::Sleep(1);
1.895 + CHECK_EMPTY();
1.896 + if (pauser)
1.897 + pauser->Release();
1.898 + TEST_RESULT(d4->QueueOnIdle(), "");
1.899 + TEST_RESULT(d3->QueueOnIdle(), "");
1.900 + TEST_RESULT(d1->QueueOnIdle(), "");
1.901 + TEST_RESULT(d2->QueueOnIdle(), "");
1.902 + TEST_RESULT(d3->Cancel(), "");
1.903 + CHECK_EMPTY();
1.904 + TInt xcpu = this_cpu;
1.905 + if (pauser)
1.906 + {
1.907 + xcpu = aCpu;
1.908 + pauser->Pause(1);
1.909 + pauser->Release();
1.910 + }
1.911 + else
1.912 + NKern::Sleep(1);
1.913 + CHECK_FIRST_ENTRY(xcpu, NKern::EIDFC, 0, 4);
1.914 + CHECK_FIRST_ENTRY(xcpu, NKern::EIDFC, 0, 1);
1.915 + CHECK_FIRST_ENTRY(xcpu, NKern::EIDFC, 0, 2);
1.916 + CHECK_EMPTY();
1.917 +
1.918 + delete d4;
1.919 + delete d3;
1.920 + delete d2;
1.921 + delete d1;
1.922 + delete pauser;
1.923 + if (q)
1.924 + DestroyDfcQ(q);
1.925 + }
1.926 +
1.927 +TDfc* Dfcs[6];
1.928 +NFastSemaphore* IdleDFCTest2Fs;
1.929 +
1.930 +void IdleDFCTest2Fn(TAny* a)
1.931 + {
1.932 + TUint32 id = (TUint32)a;
1.933 + if (id==1)
1.934 + {
1.935 + TEST_RESULT(Dfcs[1]->Cancel(), "");
1.936 + TEST_RESULT(Dfcs[3]->QueueOnIdle(), "");
1.937 + TEST_RESULT(Dfcs[4]->QueueOnIdle(), "");
1.938 + TEST_RESULT(Dfcs[5]->QueueOnIdle(), "");
1.939 + }
1.940 + if (id==1 || id==4)
1.941 + IdleDFCTest2Fs->Signal();
1.942 + if (id==3)
1.943 + {
1.944 + TEST_RESULT(Dfcs[5]->Cancel(), "");
1.945 + }
1.946 + TTestDfc::Run(a);
1.947 + }
1.948 +
1.949 +void DoIdleDFCTest2()
1.950 + {
1.951 + TEST_PRINT("IdleDFCTest2");
1.952 + NFastSemaphore sem(0);
1.953 + TInt this_cpu = NKern::CurrentCpu();
1.954 + TInt i;
1.955 + for (i=0; i<6; ++i)
1.956 + {
1.957 + Dfcs[i] = new TDfc(&IdleDFCTest2Fn, (TAny*)(i+1));
1.958 + TEST_OOM(Dfcs[i]);
1.959 + }
1.960 + TEST_RESULT(Dfcs[0]->QueueOnIdle(), "");
1.961 + TEST_RESULT(Dfcs[1]->QueueOnIdle(), "");
1.962 + TEST_RESULT(Dfcs[2]->QueueOnIdle(), "");
1.963 + IdleDFCTest2Fs = &sem;
1.964 + CHECK_EMPTY();
1.965 + NKern::FSWait(&sem);
1.966 + CHECK_FIRST_ENTRY(this_cpu, NKern::EIDFC, 0, 1);
1.967 + CHECK_FIRST_ENTRY(this_cpu, NKern::EIDFC, 0, 3);
1.968 + CHECK_EMPTY();
1.969 + NKern::FSWait(&sem);
1.970 + CHECK_FIRST_ENTRY(this_cpu, NKern::EIDFC, 0, 4);
1.971 + CHECK_FIRST_ENTRY(this_cpu, NKern::EIDFC, 0, 5);
1.972 + CHECK_EMPTY();
1.973 + for (i=0; i<6; ++i)
1.974 + delete Dfcs[i];
1.975 + }
1.976 +
1.977 +#ifdef __SMP__
1.978 +
1.979 +class TDfcStress;
1.980 +class TDfcX
1.981 + {
1.982 +public:
1.983 + enum
1.984 + {
1.985 + EFlag_IdleDFC=1,
1.986 + EFlag_IDFC=2,
1.987 + EFlag_DFC=4,
1.988 + EFlag_Timer=8,
1.989 + EFlag_Tied=16
1.990 + };
1.991 +public:
1.992 + TDfcX();
1.993 + ~TDfcX();
1.994 + static void IDfcFn(TAny*);
1.995 + static void DfcFn(TAny*);
1.996 + static void TimerIsrFn(TAny*);
1.997 + static void TimerDfcFn(TAny*);
1.998 + void Update();
1.999 + TBool Add(TAny* a=0);
1.1000 + TBool Cancel(TAny* a=0);
1.1001 + TBool Enque(TAny* a=0);
1.1002 + TBool QueueOnIdle(TAny* a=0);
1.1003 + TBool SafeAdd();
1.1004 + TBool SafeCancel();
1.1005 + TBool SafeEnque();
1.1006 + TBool SafeQueueOnIdle();
1.1007 + void CreateDfcOrTimer();
1.1008 + void GetDesc(char* aDesc);
1.1009 + inline TBool IsIDFC()
1.1010 + {return (iFlags & (EFlag_IDFC|EFlag_Timer)) == EFlag_IDFC;}
1.1011 + inline TBool IsIdler()
1.1012 + {return iFlags & EFlag_IdleDFC;}
1.1013 + void ThreadActivity();
1.1014 +public:
1.1015 + union
1.1016 + {
1.1017 + TDfc* volatile iDfc;
1.1018 + NTimer* volatile iTimer;
1.1019 + };
1.1020 + TDfcQue* iDfcQ;
1.1021 + TUint32 iQueueCount;
1.1022 + TUint32 iRunCount[KMaxCpus];
1.1023 + TUint32 iCancelCount;
1.1024 + TUint32 iExclusionFailCount;
1.1025 + TUint32 iId;
1.1026 + TUint32 iFlags;
1.1027 + TDfcStress* iS;
1.1028 + TUint64 iTimeQueued;
1.1029 + TUint64 iMaxTime;
1.1030 + TUint64 iSumTime;
1.1031 + TSpinLock iSpinLock;
1.1032 + NSchedulable* iXTied;
1.1033 + volatile TUint32* iExclusionCheck;
1.1034 + };
1.1035 +
1.1036 +TDfcX::TDfcX()
1.1037 + : iSpinLock(TSpinLock::EOrderGenericIrqLow1)
1.1038 + {
1.1039 + memclr(this,sizeof(TDfcX));
1.1040 + new (&iSpinLock) TSpinLock(TSpinLock::EOrderGenericIrqLow1);
1.1041 + }
1.1042 +
1.1043 +TDfcX::~TDfcX()
1.1044 + {
1.1045 + TAny* p = __e32_atomic_swp_ord_ptr(&iDfc, 0);
1.1046 + if (p)
1.1047 + {
1.1048 + if (iFlags & EFlag_Timer)
1.1049 + delete ((NTimer*)p);
1.1050 + else
1.1051 + delete ((TDfc*)p);
1.1052 + }
1.1053 + }
1.1054 +
1.1055 +class TDfcStress
1.1056 + {
1.1057 +public:
1.1058 + enum
1.1059 + {
1.1060 + EMode_Wait =0x00000001u,
1.1061 + EMode_AllowCancel =0x00000002u,
1.1062 + EMode_AllowIdle =0x00000004u,
1.1063 + EMode_AllowEnque =0x00000008u,
1.1064 + EMode_Recycle =0x00000010u,
1.1065 + EMode_UseTied =0x00000020u,
1.1066 + EMode_Migrate =0x00000040u,
1.1067 + EMode_SelfMigrate =0x00000080u,
1.1068 + EMode_Exit =0x80000000u
1.1069 + };
1.1070 +public:
1.1071 + enum {EMaxDfc=48, EMaxDfcQ=8};
1.1072 +
1.1073 + TDfcStress();
1.1074 + static TDfcStress* New(TInt aNumDfc, TInt aNumDfcQ, TBool aTimerTest);
1.1075 + void Create();
1.1076 + static void DoThreadFn(TAny*);
1.1077 + void ThreadFn();
1.1078 + static void BackStopFn(TAny*);
1.1079 + void Run();
1.1080 + void Close();
1.1081 + void DoTestPhase(TInt aMode, TInt aTime, TInt aCount);
1.1082 + void GetModeText(char* aName);
1.1083 +public:
1.1084 + TDfcX* NewDfc(TUint32 aId, TUint32 aFlags, TInt aDfcQ);
1.1085 + TDfcX* NewIDfc(TUint32 aId, TUint32 aFlags, NSchedulable* aTied=0);
1.1086 + TDfcX* NewTimer(TUint32 aId, TUint32 aFlags, TInt aDfcQ, NSchedulable* aTied);
1.1087 + void CreateDfc(TUint32 aId);
1.1088 +public:
1.1089 + TInt iNumDfc;
1.1090 + TDfcX* iDfcX[EMaxDfc];
1.1091 + TInt iNumDfcQ;
1.1092 + TBool iTimerTest;
1.1093 + TDfcQue* iDfcQ[EMaxDfcQ];
1.1094 + NThread* iThread[KMaxCpus];
1.1095 + volatile TBool iStop;
1.1096 + volatile TInt iRunning;
1.1097 + volatile TInt iMode;
1.1098 + NFastSemaphore* iExitSem;
1.1099 + TDfcX* volatile iGarbage;
1.1100 + TUint32 iRandomTimeLimit;
1.1101 + TDfc* iBackStopIdleDfc;
1.1102 + TDfcQue* iBackStopIdleDfcQ;
1.1103 + };
1.1104 +
1.1105 +void TDfcX::Update()
1.1106 + {
1.1107 + TUint32 exc0 = 0;
1.1108 + TUint32 exc1 = 0;
1.1109 + if (iExclusionCheck)
1.1110 + exc0 = *iExclusionCheck;
1.1111 + TInt cpu = NKern::CurrentCpu();
1.1112 + __e32_atomic_add_ord32(&iRunCount[cpu], 1);
1.1113 + TInt ctx = NKern::CurrentContext();
1.1114 + TBool is_idfc = IsIDFC();
1.1115 + TBool is_timer = iFlags & EFlag_Timer;
1.1116 + TBool is_tied = iFlags & EFlag_Tied;
1.1117 + if ((is_idfc||is_timer) && is_tied && !(iS->iMode & (TDfcStress::EMode_Migrate|TDfcStress::EMode_SelfMigrate)))
1.1118 + {
1.1119 + TInt cpu = NKern::CurrentCpu();
1.1120 + TInt xcpu = iXTied->iCpuAffinity;
1.1121 + if (cpu != xcpu)
1.1122 + {
1.1123 + __crash();
1.1124 + }
1.1125 + }
1.1126 + TInt irq=0;
1.1127 + if ((ctx!=NKern::EThread) && (iS->iMode & TDfcStress::EMode_AllowCancel))
1.1128 + irq = iSpinLock.LockIrqSave();
1.1129 + TUint64 now = fast_counter();
1.1130 + TUint64 delta = now - iTimeQueued;
1.1131 + if (TInt64(delta)>=0)
1.1132 + {
1.1133 + if (delta > iMaxTime)
1.1134 + iMaxTime = delta;
1.1135 + iSumTime += delta;
1.1136 + }
1.1137 + if ((ctx!=NKern::EThread) && (iS->iMode & TDfcStress::EMode_AllowCancel))
1.1138 + iSpinLock.UnlockIrqRestore(irq);
1.1139 + if (IsIdler())
1.1140 + {
1.1141 + TInt i;
1.1142 + NKern::Lock();
1.1143 + for (i=0; i<KMaxCpus; ++i)
1.1144 + {
1.1145 + NThread* t = iS->iThread[i];
1.1146 + if (t)
1.1147 + t->iRequestSemaphore.Reset();
1.1148 + }
1.1149 + NKern::Unlock();
1.1150 + iS->iBackStopIdleDfc->Cancel();
1.1151 + }
1.1152 + if (iExclusionCheck)
1.1153 + exc1 = *iExclusionCheck;
1.1154 + if (exc0!=exc1)
1.1155 + __e32_atomic_add_ord32(&iExclusionFailCount, 1);
1.1156 + }
1.1157 +
1.1158 +void TDfcStress::BackStopFn(TAny* a)
1.1159 + {
1.1160 + TDfcStress* s = (TDfcStress*)a;
1.1161 + TInt i;
1.1162 + NKern::Lock();
1.1163 + for (i=0; i<KMaxCpus; ++i)
1.1164 + {
1.1165 + NThread* t = s->iThread[i];
1.1166 + if (t)
1.1167 + t->iRequestSemaphore.Reset();
1.1168 + }
1.1169 + NKern::Unlock();
1.1170 + }
1.1171 +
1.1172 +void TDfcX::IDfcFn(TAny* a)
1.1173 + {
1.1174 + TDfcX* d = (TDfcX*)a;
1.1175 + d->Update();
1.1176 + }
1.1177 +
1.1178 +void TDfcX::DfcFn(TAny* a)
1.1179 + {
1.1180 + TDfcX* d = (TDfcX*)a;
1.1181 + d->ThreadActivity();
1.1182 + d->Update();
1.1183 + d->ThreadActivity();
1.1184 + }
1.1185 +
1.1186 +void TDfcX::TimerDfcFn(TAny* a)
1.1187 + {
1.1188 + TDfcX* d = (TDfcX*)a;
1.1189 + d->ThreadActivity();
1.1190 + d->Update();
1.1191 + d->ThreadActivity();
1.1192 + }
1.1193 +
1.1194 +void TDfcX::TimerIsrFn(TAny* a)
1.1195 + {
1.1196 + TDfcX* d = (TDfcX*)a;
1.1197 + d->Update();
1.1198 + }
1.1199 +
1.1200 +void TDfcX::ThreadActivity()
1.1201 + {
1.1202 + TInt ncpus = NKern::NumberOfCpus();
1.1203 + TInt ocpu = NKern::CurrentCpu();
1.1204 + NThread* pC = NKern::CurrentThread();
1.1205 + volatile TUint32* pX = (volatile TUint32*)&pC->iRunCount32[1]; // HACK!
1.1206 + TInt cpu = ocpu;
1.1207 + TInt i;
1.1208 + if ((iS->iMode & TDfcStress::EMode_SelfMigrate) && !pC->iEvents.IsEmpty())
1.1209 + {
1.1210 + for (i=0; i<ncpus; ++i)
1.1211 + {
1.1212 + ++*pX;
1.1213 + if (++cpu == ncpus)
1.1214 + cpu = 0;
1.1215 + NKern::ThreadSetCpuAffinity(pC, cpu);
1.1216 + }
1.1217 + }
1.1218 + else
1.1219 + {
1.1220 + ++*pX;
1.1221 + ++*pX;
1.1222 + ++*pX;
1.1223 + ++*pX;
1.1224 + ++*pX;
1.1225 + ++*pX;
1.1226 + ++*pX;
1.1227 + ++*pX;
1.1228 + }
1.1229 + ++*pX;
1.1230 + ++*pX;
1.1231 + ++*pX;
1.1232 + }
1.1233 +
1.1234 +TBool TDfcX::Add(TAny* a)
1.1235 + {
1.1236 + TBool is_timer = iFlags & EFlag_Timer;
1.1237 + if (!a)
1.1238 + a = iDfc;
1.1239 + TUint64 time = fast_counter();
1.1240 + TBool ok;
1.1241 + if (is_timer)
1.1242 + ok = ((NTimer*)a)->OneShot(1) == KErrNone;
1.1243 + else
1.1244 + ok = ((TDfc*)a)->Add();
1.1245 + if (ok)
1.1246 + {
1.1247 + iTimeQueued = time;
1.1248 + __e32_atomic_add_ord32(&iQueueCount, 1);
1.1249 + }
1.1250 + return ok;
1.1251 + }
1.1252 +
1.1253 +TBool TDfcX::Cancel(TAny* a)
1.1254 + {
1.1255 + TBool is_timer = iFlags & EFlag_Timer;
1.1256 + if (!a)
1.1257 + a = iDfc;
1.1258 + TBool ok;
1.1259 + if (is_timer)
1.1260 + ok = ((NTimer*)a)->Cancel();
1.1261 + else
1.1262 + ok = ((TDfc*)a)->Cancel();
1.1263 + if (ok)
1.1264 + __e32_atomic_add_ord32(&iCancelCount, 1);
1.1265 + return ok;
1.1266 + }
1.1267 +
1.1268 +TBool TDfcX::Enque(TAny* a)
1.1269 + {
1.1270 + TBool is_timer = iFlags & EFlag_Timer;
1.1271 + if (!a)
1.1272 + a = iDfc;
1.1273 + TUint64 time = fast_counter();
1.1274 + TBool ok;
1.1275 + if (is_timer)
1.1276 + ok = ((NTimer*)a)->Again(2) == KErrNone;
1.1277 + else
1.1278 + ok = ((TDfc*)a)->Enque();
1.1279 + if (ok)
1.1280 + {
1.1281 + iTimeQueued = time;
1.1282 + __e32_atomic_add_ord32(&iQueueCount, 1);
1.1283 + }
1.1284 + return ok;
1.1285 + }
1.1286 +
1.1287 +TBool TDfcX::QueueOnIdle(TAny* a)
1.1288 + {
1.1289 + TBool is_timer = iFlags & EFlag_Timer;
1.1290 + if (is_timer)
1.1291 + return FALSE;
1.1292 + if (!a)
1.1293 + a = iDfc;
1.1294 + TUint64 time = fast_counter();
1.1295 + TBool ok = ((TDfc*)a)->QueueOnIdle();
1.1296 + if (ok)
1.1297 + {
1.1298 + iTimeQueued = time;
1.1299 + __e32_atomic_add_ord32(&iQueueCount, 1);
1.1300 + }
1.1301 + return ok;
1.1302 + }
1.1303 +
1.1304 +TBool TDfcX::SafeAdd()
1.1305 + {
1.1306 + TBool ret = FALSE;
1.1307 + TUint32 x = set_bit0_if_nonnull((TUint32&)iDfc);
1.1308 + if (x && !(x&1))
1.1309 + {
1.1310 + TDfc* p = (TDfc*)x;
1.1311 + ret = Add(p);
1.1312 + flip_bit0((TUint32&)iDfc);
1.1313 + }
1.1314 + return ret;
1.1315 + }
1.1316 +
1.1317 +TBool TDfcX::SafeEnque()
1.1318 + {
1.1319 + TBool ret = FALSE;
1.1320 + TUint32 x = set_bit0_if_nonnull((TUint32&)iDfc);
1.1321 + if (x && !(x&1))
1.1322 + {
1.1323 + TDfc* p = (TDfc*)x;
1.1324 + ret = Enque(p);
1.1325 + flip_bit0((TUint32&)iDfc);
1.1326 + }
1.1327 + return ret;
1.1328 + }
1.1329 +
1.1330 +TBool TDfcX::SafeQueueOnIdle()
1.1331 + {
1.1332 + TBool ret = FALSE;
1.1333 + TUint32 x = set_bit0_if_nonnull((TUint32&)iDfc);
1.1334 + if (x && !(x&1))
1.1335 + {
1.1336 + TDfc* p = (TDfc*)x;
1.1337 + ret = QueueOnIdle(p);
1.1338 + flip_bit0((TUint32&)iDfc);
1.1339 + }
1.1340 + return ret;
1.1341 + }
1.1342 +
1.1343 +TBool TDfcX::SafeCancel()
1.1344 + {
1.1345 + TBool ret = FALSE;
1.1346 + TUint32 x = swap_out_if_bit0_clear((TUint32&)iDfc);
1.1347 + if (x && !(x&1))
1.1348 + {
1.1349 + if (iFlags & EFlag_Timer)
1.1350 + {
1.1351 + NTimer* p = (NTimer*)x;
1.1352 + ret = Cancel(p);
1.1353 + p->~NTimer();
1.1354 + memset(p, 0xbb, sizeof(NTimer));
1.1355 + free(p);
1.1356 + }
1.1357 + else
1.1358 + {
1.1359 + TDfc* p = (TDfc*)x;
1.1360 + ret = Cancel(p);
1.1361 + p->~TDfc();
1.1362 + memset(p, 0xbb, sizeof(TDfc));
1.1363 + free(p);
1.1364 + }
1.1365 + CreateDfcOrTimer();
1.1366 + }
1.1367 + return ret;
1.1368 + }
1.1369 +
1.1370 +void TDfcX::GetDesc(char* a)
1.1371 + {
1.1372 + memset(a, 0x20, 8);
1.1373 + if (iFlags & EFlag_Timer)
1.1374 + *a++ = 'T';
1.1375 + if (iFlags & EFlag_IDFC)
1.1376 + *a++ = 'I';
1.1377 + if (iFlags & EFlag_DFC)
1.1378 + *a++ = 'D';
1.1379 + if (iFlags & EFlag_IdleDFC)
1.1380 + *a++ = 'i';
1.1381 + if (iFlags & EFlag_Tied)
1.1382 + *a++ = 't';
1.1383 + }
1.1384 +
1.1385 +TDfcStress::TDfcStress()
1.1386 + {
1.1387 + memclr(this, sizeof(*this));
1.1388 + }
1.1389 +
1.1390 +TDfcX* TDfcStress::NewDfc(TUint32 aId, TUint32 aFlags, TInt aDfcQ)
1.1391 + {
1.1392 + TDfcX* d = new TDfcX;
1.1393 + TEST_OOM(d);
1.1394 + d->iId = aId;
1.1395 + d->iFlags = aFlags;
1.1396 + d->iS = this;
1.1397 +
1.1398 + d->iDfcQ = iDfcQ[aDfcQ];
1.1399 + d->CreateDfcOrTimer();
1.1400 + return d;
1.1401 + }
1.1402 +
1.1403 +TDfcX* TDfcStress::NewIDfc(TUint32 aId, TUint32 aFlags, NSchedulable* aTied)
1.1404 + {
1.1405 + TDfcX* d = new TDfcX;
1.1406 + TEST_OOM(d);
1.1407 + d->iId = aId;
1.1408 + d->iFlags = aFlags;
1.1409 + d->iS = this;
1.1410 +
1.1411 + d->iXTied = aTied;
1.1412 + d->CreateDfcOrTimer();
1.1413 + return d;
1.1414 + }
1.1415 +
1.1416 +TDfcX* TDfcStress::NewTimer(TUint32 aId, TUint32 aFlags, TInt aDfcQ, NSchedulable* aTied)
1.1417 + {
1.1418 + TDfcX* d = new TDfcX;
1.1419 + TEST_OOM(d);
1.1420 + d->iId = aId;
1.1421 + d->iFlags = aFlags;
1.1422 + d->iS = this;
1.1423 +
1.1424 + d->iDfcQ = (aFlags & TDfcX::EFlag_DFC) ? iDfcQ[aDfcQ] : 0;
1.1425 + d->iXTied = (aFlags & TDfcX::EFlag_Tied) ? aTied : 0;
1.1426 + d->CreateDfcOrTimer();
1.1427 + return d;
1.1428 + }
1.1429 +
1.1430 +
1.1431 +void TDfcX::CreateDfcOrTimer()
1.1432 + {
1.1433 +// volatile TUint32* xc = 0;
1.1434 + NThreadBase* t = iS->iDfcQ[0]->iThread;
1.1435 + volatile TUint32* xc = &t->iRunCount32[1]; // HACK!
1.1436 + if (!(iFlags & EFlag_Timer))
1.1437 + {
1.1438 + TDfc* d = 0;
1.1439 + if (!(iFlags & EFlag_IDFC))
1.1440 + {
1.1441 + d = new TDfc(&TDfcX::DfcFn, this, iDfcQ, 1);
1.1442 + xc = (volatile TUint32*)&iDfcQ->iThread->iRunCount32[1];
1.1443 + }
1.1444 + else if (iFlags & EFlag_Tied)
1.1445 + {
1.1446 + d = new TDfc(iXTied, &TDfcX::IDfcFn, this);
1.1447 + xc = (volatile TUint32*)&iXTied->iRunCount32[1];
1.1448 + }
1.1449 + else
1.1450 + d = new TDfc(&TDfcX::IDfcFn, this);
1.1451 + __NK_ASSERT_ALWAYS(d!=0);
1.1452 + __e32_atomic_store_rel_ptr(&iDfc, d);
1.1453 + }
1.1454 + else
1.1455 + {
1.1456 + NTimer* tmr = 0;
1.1457 + if (iFlags & EFlag_DFC)
1.1458 + {
1.1459 + tmr = new NTimer(&TDfcX::TimerDfcFn, this, iDfcQ, 1);
1.1460 + xc = (volatile TUint32*)&iDfcQ->iThread->iRunCount32[1];
1.1461 + }
1.1462 + else if (iFlags & EFlag_Tied)
1.1463 + {
1.1464 + tmr = new NTimer(iXTied, &TDfcX::TimerIsrFn, this);
1.1465 + xc = (volatile TUint32*)&iXTied->iRunCount32[1];
1.1466 + }
1.1467 + else
1.1468 + tmr = new NTimer(&TDfcX::TimerIsrFn, this);
1.1469 + __NK_ASSERT_ALWAYS(tmr!=0);
1.1470 + __e32_atomic_store_rel_ptr(&iTimer, tmr);
1.1471 + }
1.1472 + iExclusionCheck = xc;
1.1473 + }
1.1474 +
1.1475 +TDfcStress* TDfcStress::New(TInt aNumDfc, TInt aNumDfcQ, TBool aTimerTest)
1.1476 + {
1.1477 + TDfcStress* p = new TDfcStress;
1.1478 + TEST_OOM(p);
1.1479 + p->iTimerTest = aTimerTest;
1.1480 + p->iNumDfc = aNumDfc;
1.1481 + p->iNumDfcQ = aNumDfcQ;
1.1482 + p->Create();
1.1483 + return p;
1.1484 + }
1.1485 +
1.1486 +void TDfcStress::Create()
1.1487 + {
1.1488 +DEBUGPRINT("TDfcStress @ %08x", this);
1.1489 + TInt i;
1.1490 + TInt num_cpus = NKern::NumberOfCpus();
1.1491 + TInt cpu = 0;
1.1492 + iExitSem = new NFastSemaphore(0);
1.1493 + TEST_OOM(iExitSem);
1.1494 + for (i=0; i<iNumDfcQ; ++i)
1.1495 + {
1.1496 + char c[8] = "DFCQ*";
1.1497 + c[4] = (char)('0'+i);
1.1498 + TDfcQue* q = CreateDfcQ(c, 32, cpu);
1.1499 + TEST_OOM(q);
1.1500 + iDfcQ[i] = q;
1.1501 + if (++cpu == num_cpus)
1.1502 + cpu = 0;
1.1503 + NThreadBase* t = q->iThread;
1.1504 +DEBUGPRINT("DfcQ %2d @ %08x Thread @%08x Stack %08x+%08x", i, iDfcQ[i], t, t->iStackBase, t->iStackSize);
1.1505 + }
1.1506 + iBackStopIdleDfcQ = CreateDfcQ("BackStop", 1, 0);
1.1507 + TEST_OOM(iBackStopIdleDfcQ);
1.1508 + iBackStopIdleDfc = new TDfc(&BackStopFn, this, iBackStopIdleDfcQ, 1);
1.1509 + TEST_OOM(iBackStopIdleDfc);
1.1510 + for (i=0; i<num_cpus; ++i)
1.1511 + {
1.1512 + char c[8] = "THRD*";
1.1513 + c[4] = (char)('0'+i);
1.1514 + NThread* t = CreateUnresumedThreadSignalOnExit(c, &DoThreadFn, 11, this, 0, -1, iExitSem, i);
1.1515 + TEST_OOM(t);
1.1516 + iThread[i] = t;
1.1517 +DEBUGPRINT("Thread %2d @ %08x (Stack %08x+%08x)", i, iThread[i], t->iStackBase, t->iStackSize);
1.1518 + }
1.1519 + for (i=0; i<iNumDfc; ++i)
1.1520 + {
1.1521 + CreateDfc(i);
1.1522 +DEBUGPRINT("DfcX %2d @ %08x (DFC @ %08x)", i, iDfcX[i], iDfcX[i]->iDfc);
1.1523 + }
1.1524 + }
1.1525 +
1.1526 +void TDfcStress::CreateDfc(TUint32 aId)
1.1527 + {
1.1528 + TUint32 type = aId & 7;
1.1529 + TUint32 q = aId % iNumDfcQ;
1.1530 + TDfcX* d = 0;
1.1531 + switch (type)
1.1532 + {
1.1533 + case 0:
1.1534 + case 1:
1.1535 + case 2:
1.1536 + case 3:
1.1537 + if (iTimerTest)
1.1538 + d = NewTimer(aId, TDfcX::EFlag_Timer|TDfcX::EFlag_DFC, q, 0);
1.1539 + else
1.1540 + d = NewDfc(aId, TDfcX::EFlag_DFC, q);
1.1541 + break;
1.1542 + case 4:
1.1543 + case 5:
1.1544 + if (iTimerTest)
1.1545 + d = NewTimer(aId, TDfcX::EFlag_Timer|TDfcX::EFlag_Tied, 0, iDfcQ[iNumDfcQ-1-(type&1)]->iThread);
1.1546 + else
1.1547 + {
1.1548 + if (aId>=16 && aId<32 && iNumDfcQ>2)
1.1549 + d = NewIDfc(aId, TDfcX::EFlag_IDFC|TDfcX::EFlag_Tied, iDfcQ[2]->iThread);
1.1550 + else
1.1551 + d = NewIDfc(aId, TDfcX::EFlag_IDFC);
1.1552 + }
1.1553 + break;
1.1554 + case 6:
1.1555 + case 7:
1.1556 + if (iTimerTest)
1.1557 + d = NewTimer(aId, TDfcX::EFlag_Timer, 0, 0);
1.1558 + else
1.1559 + d = NewDfc(aId, TDfcX::EFlag_DFC|TDfcX::EFlag_IdleDFC, q);
1.1560 + break;
1.1561 + };
1.1562 + __e32_atomic_store_rel_ptr(&iDfcX[aId], d);
1.1563 + }
1.1564 +
1.1565 +void TDfcStress::Close()
1.1566 + {
1.1567 + TInt i;
1.1568 +
1.1569 + // delete DFCs before the DFC queues they might be on
1.1570 + for (i=0; i<iNumDfc; ++i)
1.1571 + {
1.1572 + TDfcX* d = iDfcX[i];
1.1573 + delete d;
1.1574 + }
1.1575 + delete iBackStopIdleDfc;
1.1576 +
1.1577 + for (i=0; i<iNumDfcQ; ++i)
1.1578 + DestroyDfcQ(iDfcQ[i]);
1.1579 + DestroyDfcQ(iBackStopIdleDfcQ);
1.1580 +
1.1581 + delete iExitSem;
1.1582 + delete this;
1.1583 + }
1.1584 +
1.1585 +void TDfcStress::DoThreadFn(TAny* a)
1.1586 + {
1.1587 + ((TDfcStress*)a)->ThreadFn();
1.1588 + }
1.1589 +
1.1590 +void append(char*& a, const char* s)
1.1591 + {
1.1592 + while(*s)
1.1593 + *a++ = *s++;
1.1594 + *a=0;
1.1595 + }
1.1596 +
1.1597 +void TDfcStress::GetModeText(char* a)
1.1598 + {
1.1599 + memclr(a,128);
1.1600 + if (iMode==0)
1.1601 + {
1.1602 + append(a, "Add only");
1.1603 + return;
1.1604 + }
1.1605 + if (iMode & EMode_Wait)
1.1606 + append(a, "Wait ");
1.1607 + if (iMode & EMode_AllowCancel)
1.1608 + append(a, "Cancel ");
1.1609 + if (iMode & EMode_AllowIdle)
1.1610 + append(a, "Idle ");
1.1611 + if (iMode & EMode_AllowEnque)
1.1612 + append(a, "Enque ");
1.1613 + if (iMode & EMode_Recycle)
1.1614 + append(a, "Recycle ");
1.1615 + if (iMode & EMode_Migrate)
1.1616 + append(a, "Migrate ");
1.1617 + if (iMode & EMode_SelfMigrate)
1.1618 + append(a, "SelfMigrate ");
1.1619 + }
1.1620 +
1.1621 +/*
1.1622 +Test Mode:
1.1623 +
1.1624 +Bit 31 If set causes thread to exit
1.1625 +Bit 0 If set does random wait after each operation
1.1626 +Bit 1 Allows Cancel operations if set
1.1627 +Bit 2 Allows idle operations if set
1.1628 +Bit 3 Test Enque() as well as Add()
1.1629 +Bit 4 Use SafeXXX operations
1.1630 +Bit 5 Use tied IDFCs
1.1631 +Bit 6 Migrate threads with things tied to them
1.1632 +Bit 7 Threads with things tied to them migrate themselves during execution
1.1633 +
1.1634 +*/
1.1635 +void TDfcStress::ThreadFn()
1.1636 + {
1.1637 + TBool finish = FALSE;
1.1638 + TUint32 seed[2];
1.1639 + seed[0] = NKern::CurrentCpu() ^ 0xddb3d743;
1.1640 + seed[1] = 0;
1.1641 + FOREVER
1.1642 + {
1.1643 + if (iStop)
1.1644 + {
1.1645 + __e32_atomic_add_ord32(&iRunning, (TUint32)(-1));
1.1646 + while (iStop)
1.1647 + {
1.1648 + if (iMode<0)
1.1649 + {
1.1650 + finish = TRUE;
1.1651 + break;
1.1652 + }
1.1653 + }
1.1654 + if (finish)
1.1655 + break;
1.1656 + else
1.1657 + __e32_atomic_add_ord32(&iRunning, 1);
1.1658 + }
1.1659 + if (iMode & EMode_Wait)
1.1660 + {
1.1661 + TUint32 wait = random(seed);
1.1662 + wait %= iRandomTimeLimit;
1.1663 + wait += 1;
1.1664 + fcfspin(wait);
1.1665 + }
1.1666 + TUint32 action = random(seed);
1.1667 + TUint32 action2 = random(seed);
1.1668 + if (action & 0xff000000)
1.1669 + {
1.1670 + // queue or cancel a DFC or timer
1.1671 + TBool cancel = action2 & 2;
1.1672 + TUint32 id = action % iNumDfc;
1.1673 + TDfcX* d = iDfcX[id];
1.1674 + if (iMode & EMode_Recycle)
1.1675 + {
1.1676 + TBool isIDFC = d->IsIDFC();
1.1677 + TBool isIdler = d->IsIdler();
1.1678 + if (cancel)
1.1679 + d->SafeCancel();
1.1680 + else if (isIdler)
1.1681 + d->SafeQueueOnIdle();
1.1682 + else if ((iMode & EMode_AllowEnque) && (action2 & 1) && !isIDFC)
1.1683 + d->SafeEnque();
1.1684 + else
1.1685 + {
1.1686 + NKern::Lock();
1.1687 + d->SafeAdd();
1.1688 + NKern::Unlock();
1.1689 + }
1.1690 + }
1.1691 + else
1.1692 + {
1.1693 + if (cancel && (iMode & EMode_AllowCancel))
1.1694 + {
1.1695 + d->Cancel();
1.1696 + }
1.1697 + else if (!d->IsIdler())
1.1698 + {
1.1699 + if ((iMode & EMode_AllowEnque) && (action2 & 1) && !d->IsIDFC())
1.1700 + {
1.1701 + d->Enque();
1.1702 + }
1.1703 + else
1.1704 + {
1.1705 + NKern::Lock();
1.1706 + d->Add();
1.1707 + NKern::Unlock();
1.1708 + }
1.1709 + }
1.1710 + else
1.1711 + {
1.1712 + d->QueueOnIdle();
1.1713 + }
1.1714 + }
1.1715 + continue;
1.1716 + }
1.1717 + if (iMode & EMode_AllowIdle)
1.1718 + {
1.1719 + iBackStopIdleDfc->QueueOnIdle();
1.1720 + NKern::WaitForAnyRequest();
1.1721 + }
1.1722 + }
1.1723 + }
1.1724 +
1.1725 +void StopTimeout(TAny*)
1.1726 + {
1.1727 + __crash();
1.1728 + }
1.1729 +
1.1730 +void TDfcStress::DoTestPhase(TInt aMode, TInt aTime, TInt aCount)
1.1731 + {
1.1732 + char mode_text[128];
1.1733 + TInt i;
1.1734 + TUint32 maxavg = 0;
1.1735 + TInt n;
1.1736 + iMode = aMode;
1.1737 + iStop = FALSE;
1.1738 + GetModeText(mode_text);
1.1739 + TEST_PRINT1("Testing with: %s", mode_text);
1.1740 + for (i=0; i<aCount; ++i)
1.1741 + {
1.1742 + NKern::Sleep(aTime);
1.1743 + DebugPrint(".",1);
1.1744 + }
1.1745 + DebugPrint("\r\n",2);
1.1746 + TEST_PRINT("Stopping ...");
1.1747 + iStop = TRUE;
1.1748 + NTimer timer(&StopTimeout, 0);
1.1749 + timer.OneShot(2000);
1.1750 + BackStopFn(this);
1.1751 + n = 0;
1.1752 + while (iRunning && ++n<=100)
1.1753 + NKern::Sleep(10);
1.1754 + if (iRunning)
1.1755 + {
1.1756 + __crash();
1.1757 + }
1.1758 + iBackStopIdleDfc->Cancel();
1.1759 + timer.Cancel();
1.1760 + TEST_PRINT("Threads stopped");
1.1761 + for (i=0; i<iNumDfcQ; ++i)
1.1762 + {
1.1763 + TUint32 ev = iDfcQ[i]->iThread->iEventState;
1.1764 + DEBUGPRINT("DfcThread %d EventState = %08x", i, ev);
1.1765 + TEST_RESULT(!(ev & NSchedulable::EEventCountMask), "");
1.1766 + }
1.1767 + for (i=0; i<NKern::NumberOfCpus(); ++i)
1.1768 + {
1.1769 + TUint32 ev = iThread[i]->iEventState;
1.1770 + DEBUGPRINT("Thread %d EventState = %08x", i, ev);
1.1771 + TEST_RESULT(!(ev & NSchedulable::EEventCountMask), "");
1.1772 + }
1.1773 + NKern::Sleep(10);
1.1774 + for (i=0; i<iNumDfc; ++i)
1.1775 + {
1.1776 + TDfcX* d = iDfcX[i];
1.1777 + d->Cancel();
1.1778 + TUint32 qc = d->iQueueCount;
1.1779 + TUint32* rc = d->iRunCount;
1.1780 + TUint32 totrc = rc[0] + rc[1] + rc[2] + rc[3] + rc[4] + rc[5] + rc[6] + rc[7];
1.1781 + TUint32 cc = d->iCancelCount;
1.1782 + TUint32 f = d->iFlags;
1.1783 +// TUint32 imm = d->IsIDFC()?1:0;
1.1784 + TUint32 max = d->iMaxTime;
1.1785 + TUint32 avg = 0;
1.1786 + TUint32 xfc = d->iExclusionFailCount;
1.1787 + if (totrc)
1.1788 + avg = TUint32(d->iSumTime / TUint64(totrc));
1.1789 + if (avg > maxavg)
1.1790 + maxavg = avg;
1.1791 + char desc[16];
1.1792 + memclr(desc,16);
1.1793 + d->GetDesc(desc);
1.1794 + 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]);
1.1795 + TInt diff = (TInt)(qc - (totrc+cc));
1.1796 + TEST_RESULT1(diff==0, "Counts mismatched, diff=%d", diff);
1.1797 + TEST_RESULT(!(f&TDfcX::EFlag_Tied) || xfc==0, "Exclusion Failure!");
1.1798 + d->iQueueCount = 0;
1.1799 + memclr(d->iRunCount, sizeof(d->iRunCount));
1.1800 + d->iCancelCount = 0;
1.1801 + d->iMaxTime = 0;
1.1802 + d->iSumTime = 0;
1.1803 + }
1.1804 + if (!iRandomTimeLimit)
1.1805 + iRandomTimeLimit = maxavg + (maxavg>>1);
1.1806 + }
1.1807 +
1.1808 +void TDfcStress::Run()
1.1809 + {
1.1810 + TInt i;
1.1811 + NThread* t;
1.1812 + iStop = FALSE;
1.1813 + iMode = 0;
1.1814 + TInt num_cpus = NKern::NumberOfCpus();
1.1815 + iRunning = num_cpus;
1.1816 + for (i=0; i<KMaxCpus; ++i)
1.1817 + {
1.1818 + t = iThread[i];
1.1819 + if (t)
1.1820 + NKern::ThreadResume(t);
1.1821 + }
1.1822 + TEST_PRINT("Threads resumed");
1.1823 +
1.1824 +
1.1825 + DoTestPhase(0x00, 10000, 1);
1.1826 + if (iTimerTest)
1.1827 + {
1.1828 + const TInt N = 20;
1.1829 + DoTestPhase(EMode_AllowCancel|EMode_AllowEnque|EMode_Recycle, 10000, N);
1.1830 + DoTestPhase(EMode_AllowCancel|EMode_AllowEnque|EMode_Wait|EMode_Recycle, 10000, N);
1.1831 + DoTestPhase(EMode_AllowCancel|EMode_AllowEnque|EMode_Recycle|EMode_SelfMigrate, 10000, N);
1.1832 + DoTestPhase(EMode_AllowCancel|EMode_AllowEnque|EMode_Wait|EMode_Recycle|EMode_SelfMigrate, 10000, N);
1.1833 + DoTestPhase(EMode_AllowCancel|EMode_AllowEnque, 10000, N);
1.1834 + DoTestPhase(EMode_AllowCancel|EMode_AllowEnque|EMode_Wait, 10000, N);
1.1835 + DoTestPhase(EMode_AllowCancel|EMode_AllowEnque|EMode_SelfMigrate, 10000, N);
1.1836 + DoTestPhase(EMode_AllowCancel|EMode_AllowEnque|EMode_Wait|EMode_SelfMigrate, 10000, N);
1.1837 + }
1.1838 + else
1.1839 + {
1.1840 + DoTestPhase(EMode_AllowCancel|EMode_AllowEnque, 10000, 20);
1.1841 + DoTestPhase(EMode_AllowCancel|EMode_AllowIdle|EMode_AllowEnque, 10000, 20);
1.1842 + DoTestPhase(EMode_AllowIdle|EMode_AllowEnque, 10000, 20);
1.1843 + DoTestPhase(EMode_AllowCancel|EMode_AllowIdle, 10000, 20);
1.1844 + DoTestPhase(EMode_AllowCancel|EMode_Wait, 10000, 20);
1.1845 + DoTestPhase(EMode_AllowCancel, 10000, 20);
1.1846 + DoTestPhase(EMode_AllowCancel|EMode_AllowIdle|EMode_AllowEnque|EMode_Recycle, 10000, 20);
1.1847 + }
1.1848 +
1.1849 + iMode = EMode_Exit;
1.1850 + TEST_PRINT("Terminating threads");
1.1851 + for (i=0; i<num_cpus; ++i)
1.1852 + NKern::FSWait(iExitSem);
1.1853 + TEST_PRINT("Done");
1.1854 + }
1.1855 +
1.1856 +void DoStressTest(TBool aTimerTest)
1.1857 + {
1.1858 + TEST_PRINT("Stress test...");
1.1859 + TInt ndfcs=0;
1.1860 + TInt ndfcq=0;
1.1861 + switch (NKern::NumberOfCpus())
1.1862 + {
1.1863 + case 1: ndfcs=16; ndfcq=2; break;
1.1864 + case 2: ndfcs=16; ndfcq=2; break;
1.1865 + case 3: ndfcs=24; ndfcq=2; break;
1.1866 + case 4: ndfcs=32; ndfcq=3; break;
1.1867 + case 5: ndfcs=32; ndfcq=3; break;
1.1868 + case 6: ndfcs=48; ndfcq=4; break;
1.1869 + case 7: ndfcs=48; ndfcq=4; break;
1.1870 + case 8: ndfcs=48; ndfcq=4; break;
1.1871 + default:
1.1872 + __NK_ASSERT_ALWAYS(0);
1.1873 + break;
1.1874 + }
1.1875 + TDfcStress* ds = TDfcStress::New(ndfcs, ndfcq, aTimerTest);
1.1876 + ds->Run();
1.1877 + ds->Close();
1.1878 + }
1.1879 +
1.1880 +#endif
1.1881 +
1.1882 +void TestDFCs()
1.1883 + {
1.1884 + TEST_PRINT("Testing DFCs...");
1.1885 +
1.1886 + TTestDfc::Buffer = CircBuf::New(TTestDfc::EBufferSlots);
1.1887 + TInt cpu;
1.1888 + (void)cpu;
1.1889 +#ifdef __SMP__
1.1890 + DoStressTest(TRUE);
1.1891 +#endif
1.1892 +
1.1893 + DoDFCTest1();
1.1894 + DoDFCTest2();
1.1895 + for_each_cpu(cpu)
1.1896 + {
1.1897 + DoDFCTest3(cpu);
1.1898 + }
1.1899 + DoIDFCTest1();
1.1900 + for_each_cpu(cpu)
1.1901 + {
1.1902 + DoIdleDFCTest1(cpu);
1.1903 + }
1.1904 + DoIdleDFCTest2();
1.1905 +
1.1906 +#ifdef __SMP__
1.1907 + DoStressTest(FALSE);
1.1908 +#endif
1.1909 +
1.1910 + delete TTestDfc::Buffer;
1.1911 + TTestDfc::Buffer = 0;
1.1912 + }