kerneltest/e32test/nkernsa/testdfc.cpp
changeset 0 a41df078684a
child 90 947f0dc9f7a8
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     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 	}