os/kernelhwsrv/kerneltest/e32test/nkernsa/testdfc.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     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 	}