os/kernelhwsrv/kerneltest/e32test/nkernsa/threadbasic.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\threadbasic.cpp
    15 // 
    16 //
    17 
    18 #include <nktest/nkutils.h>
    19 
    20 #define SLEEP_TIME 1
    21 
    22 #ifndef __SMP__
    23 #define iNThreadBaseSpare7 iSpare7
    24 #endif
    25 
    26 struct SThreadInfo1
    27 	{
    28 	volatile TInt iRunCount;
    29 	volatile TInt iBlockEvery;
    30 	volatile TBool iStop;
    31 	CircBuf* iBuf;
    32 	NThread* iThread;
    33 	};
    34 
    35 TInt WaitForRun(SThreadInfo1& aI, TInt aCount)
    36 	{
    37 	TUint32 initial = NKern::TickCount();
    38 	TUint32 final = initial + 2;
    39 	FOREVER
    40 		{
    41 		if (aI.iRunCount >= aCount)
    42 			return aI.iRunCount;
    43 		TUint32 x = NKern::TickCount();
    44 		if ((x - final) < 0x80000000u)
    45 			return KErrTimedOut;
    46 		}
    47 	}
    48 
    49 void BasicThread(TAny* a)
    50 	{
    51 	SThreadInfo1& info = *(SThreadInfo1*)a;
    52 	NThread* pC = NKern::CurrentThread();
    53 
    54 	while (!info.iStop)
    55 		{
    56 		TInt r = info.iBuf->TryPut((TUint32)pC);
    57 		TEST_RESULT(r==KErrNone, "Buffer full");
    58 		TInt c = (TInt)__e32_atomic_add_ord32(&info.iRunCount, 1);
    59 		TInt m = (c+1)%info.iBlockEvery;
    60 		if (!m)
    61 			NKern::WaitForAnyRequest();
    62 		}
    63 	}
    64 
    65 void BasicThread0(TAny*)
    66 	{
    67 	NThread* pC = NKern::CurrentThread();
    68 	TInt my_priority = pC->i_NThread_BasePri;
    69 	TInt this_cpu = NKern::CurrentCpu();
    70 	CircBuf* buf = CircBuf::New(KNumPriorities * KMaxCpus * 8);
    71 	TEST_OOM(buf);
    72 	SThreadInfo1* pI = (SThreadInfo1*)malloc(KNumPriorities * KMaxCpus * sizeof(SThreadInfo1));
    73 	TEST_OOM(pI);
    74 	memclr(pI, KNumPriorities * KMaxCpus * sizeof(SThreadInfo1));
    75 	NFastSemaphore exitSem(0);
    76 
    77 	TInt pri;
    78 	TInt cpu;
    79 	
    80 	for_each_cpu(cpu)
    81 		{
    82 		for (pri = 1; pri < KNumPriorities; ++pri)
    83 			{
    84 			TInt ix = cpu * KNumPriorities + pri;
    85 			SThreadInfo1& info = pI[ix];
    86 			info.iBlockEvery = 1;
    87 			info.iBuf = buf;
    88 			info.iThread = CreateUnresumedThreadSignalOnExit("Basic", &BasicThread, pri, &info, 0, -1, &exitSem, cpu);
    89 			TEST_OOM(info.iThread);
    90 			}
    91 		}
    92 	TInt c = buf->Count();
    93 	TEST_RESULT1(c==0, "Unexpected count %d", c);	// nothing resumed yet
    94 	for_each_cpu(cpu)
    95 		{
    96 		for (pri = 1; pri < KNumPriorities; ++pri)
    97 			{
    98 			TInt ix = cpu * KNumPriorities + pri;
    99 			SThreadInfo1& info = pI[ix];
   100 			NKern::ThreadResume(info.iThread);
   101 			TInt r = WaitForRun(info, 1);
   102 			if (pri>my_priority || cpu!=this_cpu)
   103 				{
   104 				TEST_RESULT(r==1, "WaitForRun");
   105 				c = buf->Count();
   106 				TEST_RESULT1(c==1, "Unexpected count %d", c);	// thread should have run
   107 				TUint32 x = buf->Get();
   108 				c = buf->Count();
   109 				TEST_RESULT1(c==0, "Unexpected count %d", c);
   110 				TEST_RESULT(x==(TUint32)info.iThread, "Wrong thread");
   111 				}
   112 			else
   113 				{
   114 				TEST_RESULT(r==KErrTimedOut, "WaitForRun");
   115 				c = buf->Count();
   116 				TEST_RESULT1(c==0, "Unexpected count %d", c);	// thread won't have run since current has priority
   117 				}
   118 			}
   119 		}
   120 	NKern::Sleep(10);	// let lower priority threads run
   121 	c = buf->Count();
   122 	TEST_RESULT1(c==my_priority, "Unexpected count %d", c);
   123 	for (pri = my_priority; pri >= 1; --pri)
   124 		{
   125 		TInt ix = this_cpu * KNumPriorities + pri;
   126 		SThreadInfo1& info = pI[ix];
   127 		TEST_RESULT(info.iRunCount==1, "Bad run count");
   128 		TUint32 x = buf->Get();
   129 		TEST_RESULT(x==(TUint32)info.iThread, "Wrong thread");
   130 		}
   131 	for_each_cpu(cpu)
   132 		{
   133 		for (pri = 1; pri < KNumPriorities; ++pri)
   134 			{
   135 			TInt ix = cpu * KNumPriorities + pri;
   136 			SThreadInfo1& info = pI[ix];
   137 			info.iStop = TRUE;
   138 			NKern::ThreadRequestSignal(info.iThread);
   139 			NKern::FSWait(&exitSem);
   140 			}
   141 		}
   142 	free(pI);
   143 	delete buf;
   144 	}
   145 
   146 void BasicThreadTest1()
   147 	{
   148 	TEST_PRINT("Testing all thread priorities without timeslice");
   149 
   150 	TInt pri;
   151 	TInt cpu;
   152 	
   153 	for_each_cpu(cpu)
   154 		{
   155 		for (pri = 1; pri < KNumPriorities; ++pri)
   156 			{
   157 			TEST_PRINT2("Basic0 pri %d cpu %d", pri, cpu);
   158 			CreateThreadAndWaitForExit("Basic0", &BasicThread0, pri, 0, 0, -1, cpu);
   159 			}
   160 		}
   161 	}
   162 
   163 void Spinner(TAny*)
   164 	{
   165 	FOREVER
   166 		{
   167 		}
   168 	}
   169 
   170 void BasicThreadTest2()
   171 	{
   172 	TEST_PRINT("Kill an unresumed thread");
   173 	NFastSemaphore exitSem(0);
   174 
   175 	TInt cpu;
   176 	for_each_cpu(cpu)
   177 		{
   178 		TEST_PRINT1("Thread on CPU %d", cpu);
   179 		NThread* t = CreateUnresumedThreadSignalOnExit("Spinner", &Spinner, 33, 0, 0, -1, &exitSem, cpu);
   180 		TEST_OOM(t);
   181 		NKern::ThreadKill(t);
   182 		NKern::FSWait(&exitSem);
   183 		TEST_PRINT("OK");
   184 		}
   185 
   186 	}
   187 
   188 void TimesliceTestThread(TAny* a)
   189 	{
   190 	NThread* pC = NKern::CurrentThread();
   191 	TUint id = pC->iNThreadBaseSpare7;
   192 	CircBuf* buf = (CircBuf*)a;
   193 	TUint32 thresh = norm_fast_counter_freq();
   194 	TUint32 thresh2 = thresh;
   195 	thresh /= 3000;
   196 	if (thresh < 10)
   197 		thresh = 10;
   198 	TUint32 last_interval_begin = norm_fast_counter();
   199 	TUint32 last_seen_time = norm_fast_counter();
   200 	FOREVER
   201 		{
   202 		TUint32 nfc = norm_fast_counter();
   203 		TUint32 delta = nfc - last_seen_time;
   204 		TUint32 interval_length = last_seen_time - last_interval_begin;
   205 		if (delta > thresh || interval_length > thresh2)
   206 			{
   207 			last_interval_begin = nfc;
   208 			TUint32 x = (id<<24) | interval_length;
   209 			TInt r = buf->TryPut(x);
   210 			if (r != KErrNone)
   211 				break;
   212 			}
   213 		last_seen_time = nfc;
   214 		}
   215 	}
   216 
   217 void TimesliceTest()
   218 	{
   219 //	NThread* pC = NKern::CurrentThread();
   220 //	TInt my_priority = pC->i_NThread_BasePri;
   221 //	TInt this_cpu = NKern::CurrentCpu();
   222 	CircBuf* buf = CircBuf::New(1024);
   223 	TEST_OOM(buf);
   224 	NFastSemaphore exitSem(0);
   225 
   226 	TInt cpu;
   227 	TInt i;
   228 	TInt id = 0;
   229 	NThread* t[KMaxCpus*3];
   230 	TInt timeslice[3] =
   231 		{
   232 		__microseconds_to_timeslice_ticks(20000),
   233 		__microseconds_to_timeslice_ticks(23000),
   234 		__microseconds_to_timeslice_ticks(19000)
   235 		};
   236 	TInt expected[3] =
   237 		{
   238 		__microseconds_to_norm_fast_counter(20000),
   239 		__microseconds_to_norm_fast_counter(23000),
   240 		__microseconds_to_norm_fast_counter(19000)
   241 		};
   242 	for_each_cpu(cpu)
   243 		{
   244 		for (i=0; i<3; ++i)
   245 			{
   246 			t[id] = CreateThreadSignalOnExit("Timeslice", &TimesliceTestThread, 10, buf, 0, timeslice[i], &exitSem, cpu);
   247 			TEST_OOM(t[id]);
   248 			t[id]->iNThreadBaseSpare7 = id;
   249 			++id;
   250 			}
   251 		nfcfspin(__microseconds_to_norm_fast_counter(1000));
   252 		}
   253 	for (i=0; i<id; ++i)
   254 		{
   255 		NKern::FSWait(&exitSem);
   256 		TEST_PRINT("Thread exited");
   257 		}
   258 	TUint32 x;
   259 	TUint32 xtype = 0;
   260 	TUint32 ncpus = NKern::NumberOfCpus();
   261 	TUint32 xcpu = (ncpus>1) ? 1 : 0;
   262 	while (buf->TryGet(x)==KErrNone)
   263 		{
   264 		TUint32 id = x>>24;
   265 		TUint32 time = x&0xffffff;
   266 		TEST_PRINT2("Id %d Time %d", id, time);
   267 		TUint32 xid = xcpu*3 + xtype;
   268 		if (xcpu==0 && ++xtype==3)
   269 			xtype=0;
   270 		if (++xcpu == ncpus)
   271 			xcpu=0;
   272 		TEST_RESULT2(id==xid, "Expected id %d got id %d", xid, id);
   273 		TUint32 exp = expected[id%3];
   274 		TUint32 tol = exp/100;
   275 		if (tol < 2)
   276 			tol = 2;
   277 		TUint32 diff = (time > exp) ? time - exp : exp - time;
   278 		TEST_RESULT2(diff < tol, "Out of Tolerance: exp %d got %d", exp, time);
   279 		}
   280 	delete buf;
   281 	}
   282 
   283 struct SThreadInfo2
   284 	{
   285 	enum {ENumTimes=8};
   286 	TInt Add(TUint32 aTime, TUint32 aId);
   287 
   288 	NFastMutex* iMutex;
   289 	TInt iSpin1;
   290 	TInt iSpin2;
   291 	TInt iSpin3;
   292 	NThread* iThread2;
   293 	volatile TInt iCount;
   294 	volatile TUint32 iId[ENumTimes];
   295 	volatile TUint32 iTime[ENumTimes];
   296 	};
   297 
   298 TInt SThreadInfo2::Add(TUint32 aTime, TUint32 aId)
   299 	{
   300 	TInt c = __e32_atomic_tas_ord32(&iCount, ENumTimes, 0, 1);
   301 	if (c>=ENumTimes)
   302 		return KErrOverflow;
   303 	iTime[c] = aTime;
   304 	iId[c] = aId;
   305 	return KErrNone;
   306 	}
   307 
   308 /*
   309 If Thread1 and Thread2 on different CPUs:
   310 	Point0
   311 	PointA	just after Point0
   312 	PointB	PointA + spin1
   313 	PointE	PointA + spin1
   314 	PointC	PointB + spin2
   315 	PointD	PointB + spin2
   316 	PointF	PointE + spin3
   317 
   318 If Thread1 and Thread2 on same CPU, no mutex:
   319 	Point0
   320 	PointA	just after Point0
   321 	PointB	PointA + spin1 or PointA + spin1 + timeslice if spin1>=timeslice
   322 	PointE	PointA + spin1 or PointA + timeslice whichever is later
   323 
   324 If Thread1 and Thread2 on same CPU, mutex:
   325 	Point0
   326 	PointA	just after Point0
   327 	PointB	PointA + spin1
   328 	PointC	PointB + spin2
   329 	PointE	PointA + spin1 +spin2 or PointA + timeslice whichever is later
   330 	PointD	PointA + spin1 + spin2 if (spin1+spin2)<timeslice, otherwise PointA + spin1 + spin2 + timeslice
   331 */
   332 
   333 void TimesliceTest2Thread1(TAny* a)
   334 	{
   335 	SThreadInfo2& info = *(SThreadInfo2*)a;
   336 	TEST_RESULT(info.Add(norm_fast_counter(),1)==KErrNone, "Add failed");		// Point A
   337 	if (info.iMutex)
   338 		NKern::FMWait(info.iMutex);
   339 	nfcfspin(info.iSpin1);
   340 	NKern::ThreadResume(info.iThread2);
   341 	TEST_RESULT(info.Add(norm_fast_counter(),1)==KErrNone, "Add failed");		// Point B
   342 	nfcfspin(info.iSpin2);
   343 	TEST_RESULT(info.Add(norm_fast_counter(),1)==KErrNone, "Add failed");		// Point C
   344 	if (info.iMutex)
   345 		NKern::FMSignal(info.iMutex);
   346 	TEST_RESULT(info.Add(norm_fast_counter(),1)==KErrNone, "Add failed");		// Point D
   347 	nfcfspin(__microseconds_to_norm_fast_counter(100000));
   348 	}
   349 
   350 void TimesliceTest2Thread2(TAny* a)
   351 	{
   352 	SThreadInfo2& info = *(SThreadInfo2*)a;
   353 	TEST_RESULT(info.Add(norm_fast_counter(),2)==KErrNone, "Add failed");		// Point E
   354 	nfcfspin(info.iSpin3);
   355 	TEST_RESULT(info.Add(norm_fast_counter(),2)==KErrNone, "Add failed");		// Point F
   356 	nfcfspin(__microseconds_to_norm_fast_counter(100000));
   357 	}
   358 
   359 void DoTimesliceTest2(TInt aCpu, TInt aSpin1, TInt aSpin2, TInt aSpin3, TBool aUseMutex)
   360 	{
   361 	TEST_PRINT5("TT2: C=%1d S1=%d S2=%d S3=%d M=%1d", aCpu, aSpin1, aSpin2, aSpin3, aUseMutex);
   362 
   363 	TInt this_cpu = NKern::CurrentCpu();
   364 	NFastSemaphore exitSem(0);
   365 	NFastMutex mutex;
   366 	SThreadInfo2 info;
   367 
   368 	info.iMutex = aUseMutex ? &mutex : 0;
   369 	info.iSpin1 = aSpin1;
   370 	info.iSpin2 = aSpin2;
   371 	info.iSpin3 = aSpin3;
   372 	info.iCount = 0;
   373 
   374 	TInt timeslice = __microseconds_to_timeslice_ticks(5000);
   375 	NThread* t1 = CreateUnresumedThreadSignalOnExit("Thread1", &TimesliceTest2Thread1, 10, &info, 0, timeslice, &exitSem, this_cpu);
   376 	TEST_OOM(t1);
   377 	info.iThread2 = CreateUnresumedThreadSignalOnExit("Thread2", &TimesliceTest2Thread2, 10, &info, 0, timeslice, &exitSem, aCpu);
   378 	TEST_OOM(info.iThread2);
   379 	NKern::ThreadResume(t1);
   380 	TEST_RESULT(info.Add(norm_fast_counter(),0)==KErrNone, "Add failed");	// Point 0
   381 	NKern::FSWait(&exitSem);
   382 	NKern::FSWait(&exitSem);
   383 	TEST_RESULT1(info.iCount==7, "Wrong count %d", info.iCount);
   384 	TInt i;
   385 	TUint32 pointA=0, pointB=0, pointC=0, pointD=0, pointE=0, pointF=0;
   386 	TInt n1=0, n2=0;
   387 	TUint32 delta = __microseconds_to_norm_fast_counter(100);
   388 	TUint32 ts = __microseconds_to_norm_fast_counter(5000);
   389 	for (i=0; i<info.iCount; ++i)
   390 		{
   391 		if (i>0)
   392 			{
   393 			TUint32 id = info.iId[i];
   394 			TUint32 x = info.iTime[i] - info.iTime[0];
   395 			TEST_PRINT2("%d: %d", id, x);
   396 			if (id==1)
   397 				{
   398 				switch(++n1)
   399 					{
   400 					case 1: pointA = x; break;
   401 					case 2: pointB = x; break;
   402 					case 3: pointC = x; break;
   403 					case 4: pointD = x; break;
   404 					}
   405 				}
   406 			else
   407 				{
   408 				switch(++n2)
   409 					{
   410 					case 1: pointE = x; break;
   411 					case 2: pointF = x; break;
   412 					}
   413 				}
   414 			}
   415 		}
   416 	TEST_RESULT(RANGE_CHECK(0, pointA, delta), "pointA");
   417 	if (aCpu != this_cpu)
   418 		{
   419 		TEST_RESULT(RANGE_CHECK(TUint32(aSpin1), pointB, TUint32(aSpin1)+delta), "pointB");
   420 		TEST_RESULT(RANGE_CHECK(TUint32(aSpin1), pointE, TUint32(aSpin1)+delta), "pointE");
   421 		TEST_RESULT(RANGE_CHECK(pointB+aSpin2, pointC, pointB+aSpin2+delta), "pointC");
   422 		TEST_RESULT(RANGE_CHECK(pointB+aSpin2, pointD, pointB+aSpin2+delta), "pointD");
   423 		TEST_RESULT(RANGE_CHECK(pointE+aSpin3, pointF, pointE+aSpin3+delta), "pointF");
   424 		}
   425 	else if (aUseMutex)
   426 		{
   427 		TEST_RESULT(RANGE_CHECK(TUint32(aSpin1), pointB, aSpin1+delta), "pointB");
   428 		TEST_RESULT(RANGE_CHECK(pointB+aSpin2, pointC, pointB+aSpin2+delta), "pointC");
   429 
   430 		TUint32 xpe = aSpin1 + aSpin2;
   431 		TUint32 xpd = xpe;
   432 		if (xpe < ts)
   433 			xpe = ts;
   434 		else
   435 			xpd += ts;
   436 
   437 		TEST_RESULT(RANGE_CHECK(xpe, pointE, xpe+delta), "pointE");
   438 		TEST_RESULT(RANGE_CHECK(xpd, pointD, xpd+delta), "pointD");
   439 		}
   440 	else
   441 		{
   442 		TUint32 xpb = aSpin1;
   443 		TUint32 xpe = aSpin1;
   444 		if (xpb >= ts)
   445 			xpb += ts;
   446 		else
   447 			xpe = ts;
   448 		TEST_RESULT(RANGE_CHECK(xpb, pointB, xpb+delta), "pointB");
   449 		TEST_RESULT(RANGE_CHECK(xpe, pointE, xpe+delta), "pointE");
   450 		}
   451 	}
   452 
   453 void TimesliceTest2()
   454 	{
   455 	TInt cpu;
   456 	TInt ms = __microseconds_to_norm_fast_counter(1000);
   457 	for_each_cpu(cpu)
   458 		{
   459 		DoTimesliceTest2(cpu, 1*ms, 10*ms, 10*ms, FALSE);
   460 		DoTimesliceTest2(cpu, 2*ms, 10*ms, 10*ms, FALSE);
   461 		DoTimesliceTest2(cpu, 7*ms, 20*ms, 20*ms, FALSE);
   462 		DoTimesliceTest2(cpu, 1*ms, 1*ms, 10*ms, TRUE);
   463 		DoTimesliceTest2(cpu, 1*ms, 2*ms, 10*ms, TRUE);
   464 		DoTimesliceTest2(cpu, 2*ms, 2*ms, 10*ms, TRUE);
   465 		DoTimesliceTest2(cpu, 7*ms, 7*ms, 10*ms, TRUE);
   466 		DoTimesliceTest2(cpu, 7*ms, 7*ms, 50*ms, TRUE);
   467 		}
   468 	}
   469 
   470 struct SThreadInfo3
   471 	{
   472 	enum TTestType
   473 		{
   474 		ESpin,
   475 		ECount,
   476 		EWaitFS,
   477 		EWaitFM,
   478 		EExit,
   479 		EHoldFM,
   480 		};
   481 
   482 	TTestType iType;
   483 	TAny* iObj;
   484 	TInt iPri;
   485 	TInt iCpu;
   486 	volatile TInt iCount;
   487 	volatile TInt iCurrCpu;
   488 	volatile TBool iStop;
   489 	NFastSemaphore* iExitSem;
   490 	TInt iExitCpu;
   491 
   492 	void Set(TTestType aType, TAny* aObj, TInt aPri, TInt aCpu)
   493 		{iType=aType; iObj=aObj; iPri=aPri; iCpu=aCpu; iCount=0; iCurrCpu=-1; iStop=FALSE; iExitSem=0; iExitCpu=-1;}
   494 	NThread* CreateThread(const char* aName, NFastSemaphore* aExitSem);
   495 	static void ExitHandler(TAny* aP, NThread* aT, TInt aC);
   496 	};
   497 
   498 void BasicThread3(TAny* a)
   499 	{
   500 	SThreadInfo3& info = *(SThreadInfo3*)a;
   501 
   502 	switch (info.iType)
   503 		{
   504 		case SThreadInfo3::ESpin:
   505 			FOREVER
   506 				{
   507 				info.iCurrCpu = NKern::CurrentCpu();
   508 				}
   509 
   510 		case SThreadInfo3::ECount:
   511 			FOREVER
   512 				{
   513 				info.iCurrCpu = NKern::CurrentCpu();
   514 				__e32_atomic_add_ord32(&info.iCount, 1);
   515 				}
   516 
   517 		case SThreadInfo3::EWaitFS:
   518 			NKern::FSSetOwner((NFastSemaphore*)info.iObj, 0);
   519 			NKern::FSWait((NFastSemaphore*)info.iObj);
   520 			break;
   521 
   522 		case SThreadInfo3::EWaitFM:
   523 			NKern::FMWait((NFastMutex*)info.iObj);
   524 			NKern::FMSignal((NFastMutex*)info.iObj);
   525 			break;
   526 
   527 		case SThreadInfo3::EExit:
   528 			break;
   529 
   530 		case SThreadInfo3::EHoldFM:
   531 			NKern::FMWait((NFastMutex*)info.iObj);
   532 			while (!info.iStop)
   533 				{
   534 				info.iCurrCpu = NKern::CurrentCpu();
   535 				__e32_atomic_add_ord32(&info.iCount, 1);
   536 				}
   537 			NKern::FMSignal((NFastMutex*)info.iObj);
   538 			break;
   539 		}
   540 	}
   541 
   542 void SThreadInfo3::ExitHandler(TAny* aP, NThread* aT, TInt aC)
   543 	{
   544 	SThreadInfo3& info = *(SThreadInfo3*)aP;
   545 	switch (aC)
   546 		{
   547 		case EInContext:
   548 			info.iExitCpu = NKern::CurrentCpu();
   549 			break;
   550 		case EBeforeFree:
   551 			{
   552 			NKern::ThreadSuspend(aT, 1);
   553 			NKern::ThreadResume(aT);
   554 			NKern::ThreadResume(aT);
   555 			NKern::ThreadSuspend(aT, 1);
   556 			NKern::ThreadSuspend(aT, 1);
   557 			NKern::ThreadSuspend(aT, 1);
   558 			NKern::ThreadResume(aT);
   559 			NKern::ThreadForceResume(aT);
   560 			NKern::ThreadKill(aT);
   561 			NKern::ThreadSetPriority(aT, 63);
   562 			TEST_RESULT(aT->iPriority == 63, "Priority change when dead");
   563 			TUint32 aff = NKern::ThreadSetCpuAffinity(aT, 0xffffffffu);
   564 			TEST_RESULT(aff==TUint32(info.iExitCpu), "CPU affinity when dead");
   565 			aff = NKern::ThreadSetCpuAffinity(aT, info.iExitCpu);
   566 			TEST_RESULT(aff==0xffffffffu, "CPU affinity when dead");
   567 			break;
   568 			}
   569 		case EAfterFree:
   570 			NKern::FSSignal(info.iExitSem);
   571 			break;
   572 		}
   573 	}
   574 
   575 NThread* SThreadInfo3::CreateThread(const char* aName, NFastSemaphore* aExitSem)
   576 	{
   577 	iExitSem = aExitSem;
   578 	iExitCpu = -1;
   579 	NThread* t = ::CreateThread(aName, &BasicThread3, iPri, this, 0, FALSE, -1, &SThreadInfo3::ExitHandler, this, iCpu);
   580 	TEST_OOM(t);
   581 	return t;
   582 	}
   583 
   584 #define CHECK_RUNNING(info, cpu)	\
   585 	do {TInt c1 = (info).iCount; NKern::Sleep(SLEEP_TIME); TEST_RESULT((info).iCount!=c1, "Not running"); TEST_RESULT((info).iCurrCpu==(cpu), "Wrong CPU"); } while(0)
   586 
   587 #define CHECK_NOT_RUNNING(info, same_cpu)	\
   588 do {if (!same_cpu) NKern::Sleep(SLEEP_TIME); TInt c1 = (info).iCount; NKern::Sleep(SLEEP_TIME); TEST_RESULT((info).iCount==c1, "Running"); } while(0)
   589 
   590 void DoBasicThreadTest3SemMutex(TInt aCpu, TInt aCpu2, TBool aMutex)
   591 	{
   592 	SThreadInfo3 info;
   593 	NThread* t;
   594 	NFastSemaphore xs(0);
   595 	NFastSemaphore s;
   596 	NFastMutex m;
   597 
   598 	if (aMutex)
   599 		{
   600 		TEST_PRINT("Operations while blocked on mutex");
   601 		}
   602 	else
   603 		{
   604 		TEST_PRINT("Operations while blocked on semaphore");
   605 		}
   606 
   607 	SThreadInfo3::TTestType type = aMutex ? SThreadInfo3::EWaitFM : SThreadInfo3::EWaitFS;
   608 	TAny* obj = aMutex ? (TAny*)&m : (TAny*)&s;
   609 
   610 	info.Set(type, obj, 63, aCpu);
   611 	t = info.CreateThread("Single2", &xs);
   612 	if (!aMutex)
   613 		TEST_RESULT(s.iCount==0, "Sem count");
   614 	if (aMutex)
   615 		NKern::FMWait(&m);
   616 	NKern::ThreadResume(t);			// resume thread - should wait on semaphore/mutex
   617 	NKern::Sleep(SLEEP_TIME);
   618 	if (!aMutex)
   619 		TEST_RESULT(s.iCount<0, "Sem count");
   620 	TEST_RESULT(info.iExitCpu==-1, "Exit CPU");
   621 
   622 	aMutex ? NKern::FMSignal(&m) : NKern::FSSignal(&s);	// signal semaphore/mutex - thread should exit
   623 	NKern::FSWait(&xs);
   624 	if (!aMutex)
   625 		TEST_RESULT(s.iCount==0, "Sem count");
   626 	TEST_RESULT(info.iExitCpu==aCpu, "Exit CPU");
   627 
   628 	info.Set(type, obj, 63, aCpu);
   629 	t = info.CreateThread("Single3", &xs);
   630 	if (!aMutex)
   631 		TEST_RESULT(s.iCount==0, "Sem count");
   632 	if (aMutex)
   633 		NKern::FMWait(&m);
   634 	NKern::ThreadResume(t);			// resume thread - should wait on semaphore/mutex
   635 	NKern::Sleep(SLEEP_TIME);
   636 	if (!aMutex)
   637 		TEST_RESULT(s.iCount<0, "Sem count");
   638 	TEST_RESULT(info.iExitCpu==-1, "Exit CPU");
   639 	NKern::ThreadSuspend(t, 1);		// suspend thread while waiting on semaphore/mutex
   640 	NKern::Sleep(SLEEP_TIME);
   641 	if (!aMutex)
   642 		TEST_RESULT(s.iCount<0, "Sem count");
   643 	TEST_RESULT(info.iExitCpu==-1, "Exit CPU");
   644 	aMutex ? NKern::FMSignal(&m) : NKern::FSSignal(&s);	// signal semaphore/mutex - still suspended
   645 	NKern::Sleep(SLEEP_TIME);
   646 	if (!aMutex)
   647 		TEST_RESULT(s.iCount==0, "Sem count");
   648 	TEST_RESULT(info.iExitCpu==-1, "Exit CPU");
   649 	NKern::ThreadResume(t);			// resume - should now exit
   650 	NKern::FSWait(&xs);
   651 	if (!aMutex)
   652 		TEST_RESULT(s.iCount==0, "Sem count");
   653 	TEST_RESULT(info.iExitCpu==aCpu, "Exit CPU");
   654 
   655 	info.Set(type, obj, 63, aCpu);
   656 	t = info.CreateThread("Single4", &xs);
   657 	if (!aMutex)
   658 		TEST_RESULT(s.iCount==0, "Sem count");
   659 	if (aMutex)
   660 		NKern::FMWait(&m);
   661 	NKern::ThreadResume(t);			// resume thread - should wait on semaphore/mutex
   662 	NKern::Sleep(SLEEP_TIME);
   663 	if (!aMutex)
   664 		TEST_RESULT(s.iCount<0, "Sem count");
   665 	TEST_RESULT(info.iExitCpu==-1, "Exit CPU");
   666 	NKern::ThreadKill(t);			// kill thread while blocked on semaphore/mutex
   667 	NKern::FSWait(&xs);
   668 	if (!aMutex)
   669 		TEST_RESULT(s.iCount==0, "Sem count");
   670 	TEST_RESULT(info.iExitCpu==aCpu, "Exit CPU");
   671 	if (aMutex)
   672 		NKern::FMSignal(&m);
   673 
   674 	info.Set(type, obj, 63, aCpu);
   675 	t = info.CreateThread("Single5", &xs);
   676 	if (!aMutex)
   677 		TEST_RESULT(s.iCount==0, "Sem count");
   678 	if (aMutex)
   679 		NKern::FMWait(&m);
   680 	NKern::ThreadResume(t);			// resume thread - should wait on semaphore/mutex
   681 	NKern::Sleep(SLEEP_TIME);
   682 	if (!aMutex)
   683 		TEST_RESULT(s.iCount<0, "Sem count");
   684 	TEST_RESULT(info.iExitCpu==-1, "Exit CPU");
   685 	NKern::ThreadSuspend(t, 1);		// suspend thread while waiting on semaphore/mutex
   686 	NKern::Sleep(SLEEP_TIME);
   687 	if (!aMutex)
   688 		TEST_RESULT(s.iCount<0, "Sem count");
   689 	TEST_RESULT(info.iExitCpu==-1, "Exit CPU");
   690 	NKern::ThreadKill(t);			// kill thread while blocked on semaphore/mutex and suspended
   691 	NKern::FSWait(&xs);
   692 	if (!aMutex)
   693 		TEST_RESULT(s.iCount==0, "Sem count");
   694 	TEST_RESULT(info.iExitCpu==aCpu, "Exit CPU");
   695 	if (aMutex)
   696 		NKern::FMSignal(&m);
   697 
   698 	if (aCpu2>=0)
   699 		{
   700 		info.Set(type, obj, 63, aCpu);
   701 		t = info.CreateThread("Single6", &xs);
   702 		if (!aMutex)
   703 			TEST_RESULT(s.iCount==0, "Sem count");
   704 		if (aMutex)
   705 			NKern::FMWait(&m);
   706 		NKern::ThreadResume(t);			// resume thread - should wait on semaphore/mutex
   707 		NKern::Sleep(SLEEP_TIME);
   708 		if (!aMutex)
   709 			TEST_RESULT(s.iCount<0, "Sem count");
   710 		TEST_RESULT(info.iExitCpu==-1, "Exit CPU");
   711 		NKern::ThreadSetCpuAffinity(t, aCpu2);	// move blocked thread
   712 		aMutex ? NKern::FMSignal(&m) : NKern::FSSignal(&s);	// signal semaphore/mutex - thread should exit
   713 		NKern::FSWait(&xs);
   714 		if (!aMutex)
   715 			TEST_RESULT(s.iCount==0, "Sem count");
   716 		TEST_RESULT(info.iExitCpu==aCpu2, "Exit CPU");
   717 
   718 		info.Set(type, obj, 63, aCpu);
   719 		t = info.CreateThread("Single3", &xs);
   720 		if (!aMutex)
   721 			TEST_RESULT(s.iCount==0, "Sem count");
   722 		if (aMutex)
   723 			NKern::FMWait(&m);
   724 		NKern::ThreadResume(t);			// resume thread - should wait on semaphore/mutex
   725 		NKern::Sleep(SLEEP_TIME);
   726 		if (!aMutex)
   727 			TEST_RESULT(s.iCount<0, "Sem count");
   728 		TEST_RESULT(info.iExitCpu==-1, "Exit CPU");
   729 		NKern::ThreadSuspend(t, 1);		// suspend thread while waiting on semaphore/mutex
   730 		NKern::Sleep(SLEEP_TIME);
   731 		if (!aMutex)
   732 			TEST_RESULT(s.iCount<0, "Sem count");
   733 		TEST_RESULT(info.iExitCpu==-1, "Exit CPU");
   734 		NKern::ThreadSetCpuAffinity(t, aCpu2);	// move blocked and suspended thread
   735 		aMutex ? NKern::FMSignal(&m) : NKern::FSSignal(&s);	// signal semaphore/mutex - still suspended
   736 		NKern::Sleep(SLEEP_TIME);
   737 		if (!aMutex)
   738 			TEST_RESULT(s.iCount==0, "Sem count");
   739 		TEST_RESULT(info.iExitCpu==-1, "Exit CPU");
   740 		NKern::ThreadResume(t);			// resume - should now exit
   741 		NKern::FSWait(&xs);
   742 		if (!aMutex)
   743 			TEST_RESULT(s.iCount==0, "Sem count");
   744 		TEST_RESULT(info.iExitCpu==aCpu2, "Exit CPU");
   745 
   746 		info.Set(type, obj, 63, aCpu);
   747 		t = info.CreateThread("Single4", &xs);
   748 		if (!aMutex)
   749 			TEST_RESULT(s.iCount==0, "Sem count");
   750 		if (aMutex)
   751 			NKern::FMWait(&m);
   752 		NKern::ThreadResume(t);			// resume thread - should wait on semaphore/mutex
   753 		NKern::Sleep(SLEEP_TIME);
   754 		if (!aMutex)
   755 			TEST_RESULT(s.iCount<0, "Sem count");
   756 		TEST_RESULT(info.iExitCpu==-1, "Exit CPU");
   757 		NKern::ThreadSetCpuAffinity(t, aCpu2);	// move blocked thread
   758 		NKern::ThreadKill(t);			// kill thread while blocked on semaphore/mutex
   759 		NKern::FSWait(&xs);
   760 		if (!aMutex)
   761 			TEST_RESULT(s.iCount==0, "Sem count");
   762 		TEST_RESULT(info.iExitCpu==aCpu2, "Exit CPU");
   763 		if (aMutex)
   764 			NKern::FMSignal(&m);
   765 
   766 		info.Set(type, obj, 63, aCpu);
   767 		t = info.CreateThread("Single5", &xs);
   768 		if (!aMutex)
   769 			TEST_RESULT(s.iCount==0, "Sem count");
   770 		if (aMutex)
   771 			NKern::FMWait(&m);
   772 		NKern::ThreadResume(t);			// resume thread - should wait on semaphore/mutex
   773 		NKern::Sleep(SLEEP_TIME);
   774 		if (!aMutex)
   775 			TEST_RESULT(s.iCount<0, "Sem count");
   776 		TEST_RESULT(info.iExitCpu==-1, "Exit CPU");
   777 		NKern::ThreadSuspend(t, 1);		// suspend thread while waiting on semaphore/mutex
   778 		NKern::Sleep(SLEEP_TIME);
   779 		if (!aMutex)
   780 			TEST_RESULT(s.iCount<0, "Sem count");
   781 		TEST_RESULT(info.iExitCpu==-1, "Exit CPU");
   782 		NKern::ThreadSetCpuAffinity(t, aCpu2);	// move blocked and suspended thread
   783 		NKern::ThreadKill(t);			// kill thread while blocked on semaphore/mutex and suspended
   784 		NKern::FSWait(&xs);
   785 		if (!aMutex)
   786 			TEST_RESULT(s.iCount==0, "Sem count");
   787 		TEST_RESULT(info.iExitCpu==aCpu2, "Exit CPU");
   788 		if (aMutex)
   789 			NKern::FMSignal(&m);
   790 		}
   791 	}
   792 
   793 void DoBasicThreadTest3SemPri(TInt aCpu, TInt aCpu2)
   794 	{
   795 	(void)aCpu2;
   796 	TEST_PRINT("Change priority + semaphore");
   797 	TInt this_cpu = NKern::CurrentCpu();
   798 	TBool same_cpu = (aCpu == this_cpu);
   799 	SThreadInfo3 info;
   800 	NThread* t;
   801 	SThreadInfo3 info2;
   802 	NThread* t2;
   803 	NFastSemaphore xs(0);
   804 	NFastSemaphore s;
   805 
   806 	info.Set(SThreadInfo3::EWaitFS, &s, 10, aCpu);
   807 	t = info.CreateThread("SemPri1A", &xs);
   808 	NKern::ThreadResume(t);			// resume thread - should wait on semaphore
   809 	NKern::Sleep(SLEEP_TIME);
   810 	TEST_RESULT(s.iCount<0, "Sem count");
   811 	TEST_RESULT(info.iExitCpu==-1, "Exit CPU");
   812 
   813 	info2.Set(SThreadInfo3::ECount, 0, 11, aCpu);
   814 	t2 = info2.CreateThread("SemPri1B", &xs);
   815 	NKern::ThreadResume(t2);		// resume thread - should run in preference to first thread
   816 	CHECK_RUNNING(info2, aCpu);
   817 
   818 	NKern::ThreadSetPriority(t, 63);	// change priority while blocked
   819 	NKern::FSSignal(&s);			// signal semaphore - should run and exit immediately
   820 	NKern::FSWait(&xs);
   821 	TEST_RESULT(s.iCount==0, "Sem count");
   822 	TEST_RESULT(info.iExitCpu==aCpu, "Exit CPU");
   823 	CHECK_RUNNING(info2, aCpu);
   824 
   825 	info.Set(SThreadInfo3::EWaitFS, &s, 63, aCpu);
   826 	t = info.CreateThread("SemPri1C", &xs);
   827 	NKern::ThreadResume(t);			// resume thread - should wait on semaphore
   828 	NKern::Sleep(SLEEP_TIME);
   829 	TEST_RESULT(s.iCount<0, "Sem count");
   830 	TEST_RESULT(info.iExitCpu==-1, "Exit CPU");
   831 	NKern::ThreadSetPriority(t, 1);	// change priority while blocked
   832 	NKern::FSSignal(&s);			// signal semaphore - shouldn't run because priority lower than 1B
   833 	NKern::Sleep(SLEEP_TIME);
   834 	TEST_RESULT(s.iCount==0, "Sem count");
   835 	TEST_RESULT(info.iExitCpu==-1, "Exit CPU");
   836 	CHECK_RUNNING(info2, aCpu);
   837 
   838 	NKern::ThreadKill(t2);
   839 	CHECK_NOT_RUNNING(info2, same_cpu);
   840 	NKern::FSWait(&xs);
   841 	NKern::FSWait(&xs);
   842 	TEST_RESULT(info2.iExitCpu==aCpu, "Exit CPU");
   843 	TEST_RESULT(info.iExitCpu==aCpu, "Exit CPU");
   844 	}
   845 
   846 void DoBasicThreadTest3MutexPri(TInt aCpu, TInt aCpu2, TBool aKill)
   847 	{
   848 	TEST_PRINT1("Change priority + mutex ... kill=%d", aKill);
   849 	TInt this_cpu = NKern::CurrentCpu();
   850 	TBool same_cpu = (aCpu == this_cpu);
   851 //	TBool same_cpu2 = (aCpu2 == this_cpu);
   852 	SThreadInfo3 info;
   853 	NThread* t;
   854 	SThreadInfo3 info2;
   855 	NThread* t2;
   856 	SThreadInfo3 info3;
   857 	NThread* t3;
   858 	NFastSemaphore xs(0);
   859 	NFastMutex m;
   860 
   861 	info.Set(SThreadInfo3::EHoldFM, &m, 10, aCpu);
   862 	t = info.CreateThread("MutexPri1A", &xs);
   863 	NKern::ThreadResume(t);		// start first thread - it should grab mutex then spin
   864 	CHECK_RUNNING(info, aCpu);
   865 	TEST_RESULT(t->iPriority==10, "Priority");
   866 	info2.Set(SThreadInfo3::EWaitFM, &m, 12, aCpu);
   867 	t2 = info2.CreateThread("MutexPri1B", &xs);
   868 	info3.Set(SThreadInfo3::ECount, 0, 11, aCpu);
   869 	t3 = info3.CreateThread("MutexPri1C", &xs);
   870 	NKern::ThreadResume(t3);	// start t3 - should preempt t1
   871 	CHECK_RUNNING(info3, aCpu);
   872 	CHECK_NOT_RUNNING(info, same_cpu);
   873 	NKern::ThreadResume(t2);	// start t2 - should wait on mutex, increasing t1's priority in the process
   874 	CHECK_RUNNING(info, aCpu);
   875 	CHECK_NOT_RUNNING(info3, same_cpu);
   876 	TEST_RESULT(info2.iExitCpu==-1, "Exit CPU");
   877 	TEST_RESULT(t->iPriority==12, "Priority");
   878 	NKern::ThreadSetPriority(t2, 9);	// lower t2's priority - should lower t1's as well so t1 stops running
   879 	CHECK_RUNNING(info3, aCpu);
   880 	CHECK_NOT_RUNNING(info, same_cpu);
   881 	TEST_RESULT(t->iPriority==10, "Priority");
   882 	NKern::ThreadSetPriority(t2, 15);	// increase t2's priority - should increase t1's as well
   883 	CHECK_RUNNING(info, aCpu);
   884 	CHECK_NOT_RUNNING(info3, same_cpu);
   885 	TEST_RESULT(t->iPriority==15, "Priority");
   886 	NKern::ThreadSuspend(t2, 1);		// suspend t2 - t1 should now lose inherited priority
   887 	CHECK_RUNNING(info3, aCpu);
   888 	CHECK_NOT_RUNNING(info, same_cpu);
   889 	TEST_RESULT(t->iPriority==10, "Priority");
   890 	NKern::ThreadResume(t2);			// resume t2 - t1 should now regain inherited priority
   891 	CHECK_RUNNING(info, aCpu);
   892 	CHECK_NOT_RUNNING(info3, same_cpu);
   893 	TEST_RESULT(t->iPriority==15, "Priority");
   894 	TEST_RESULT(info2.iExitCpu==-1, "Exit CPU");
   895 
   896 	NKern::ThreadSuspend(t2, 1);		// suspend t2 - t1 should now lose inherited priority
   897 	CHECK_RUNNING(info3, aCpu);
   898 	CHECK_NOT_RUNNING(info, same_cpu);
   899 	TEST_RESULT(t->iPriority==10, "Priority");
   900 	NKern::ThreadSetPriority(t2, 9);	// lower t2's priority - should have no effect on t1
   901 	CHECK_RUNNING(info3, aCpu);
   902 	CHECK_NOT_RUNNING(info, same_cpu);
   903 	TEST_RESULT(t->iPriority==10, "Priority");
   904 	NKern::ThreadSetPriority(t2, 15);	// raise t2's priority - should have no effect on t1
   905 	CHECK_RUNNING(info3, aCpu);
   906 	CHECK_NOT_RUNNING(info, same_cpu);
   907 	TEST_RESULT(t->iPriority==10, "Priority");
   908 	NKern::ThreadSetPriority(t2, 9);	// lower t2's priority - should have no effect on t1
   909 	CHECK_RUNNING(info3, aCpu);
   910 	CHECK_NOT_RUNNING(info, same_cpu);
   911 	TEST_RESULT(t->iPriority==10, "Priority");
   912 	NKern::ThreadResume(t2);			// resume t2 - should have no effect on t1
   913 	CHECK_RUNNING(info3, aCpu);
   914 	CHECK_NOT_RUNNING(info, same_cpu);
   915 	TEST_RESULT(t->iPriority==10, "Priority");
   916 	NKern::ThreadSetPriority(t2, 15);	// increase t2's priority - should increase t1's as well
   917 	CHECK_RUNNING(info, aCpu);
   918 	CHECK_NOT_RUNNING(info3, same_cpu);
   919 	TEST_RESULT(t->iPriority==15, "Priority");
   920 	TEST_RESULT(info2.iExitCpu==-1, "Exit CPU");
   921 
   922 	if (aCpu2>=0)
   923 		{
   924 		NKern::ThreadSetCpuAffinity(t2, aCpu2);	// move t2 - should have no effect on t1
   925 		CHECK_RUNNING(info, aCpu);
   926 		CHECK_NOT_RUNNING(info3, same_cpu);
   927 		TEST_RESULT(t->iPriority==15, "Priority");
   928 		NKern::ThreadSuspend(t2, 1);		// suspend t2 - t1 should now lose inherited priority
   929 		CHECK_RUNNING(info3, aCpu);
   930 		CHECK_NOT_RUNNING(info, same_cpu);
   931 		TEST_RESULT(t->iPriority==10, "Priority");
   932 		NKern::ThreadResume(t2);			// resume t2 - t1 should now regain inherited priority
   933 		CHECK_RUNNING(info, aCpu);
   934 		CHECK_NOT_RUNNING(info3, same_cpu);
   935 		TEST_RESULT(t->iPriority==15, "Priority");
   936 		NKern::ThreadSetPriority(t2, 9);	// lower t2's priority - should lower t1's as well so t1 stops running
   937 		CHECK_RUNNING(info3, aCpu);
   938 		CHECK_NOT_RUNNING(info, same_cpu);
   939 		TEST_RESULT(t->iPriority==10, "Priority");
   940 		NKern::ThreadSetPriority(t2, 15);	// increase t2's priority - should increase t1's as well
   941 		CHECK_RUNNING(info, aCpu);
   942 		CHECK_NOT_RUNNING(info3, same_cpu);
   943 		TEST_RESULT(t->iPriority==15, "Priority");
   944 		TEST_RESULT(info2.iExitCpu==-1, "Exit CPU");
   945 		}
   946 
   947 	TInt xcpu = (aCpu2>=0) ? aCpu2: aCpu;
   948 	if (aKill)
   949 		{
   950 		NKern::ThreadKill(t2);	// kill t2 - t1 should lose inherited priority
   951 		NKern::FSWait(&xs);
   952 		CHECK_RUNNING(info3, aCpu);
   953 		CHECK_NOT_RUNNING(info, same_cpu);
   954 		TEST_RESULT(t->iPriority==10, "Priority");
   955 		TEST_RESULT(info2.iExitCpu==xcpu, "Exit CPU");
   956 		info.iStop = TRUE;
   957 		NKern::ThreadKill(t3);
   958 		NKern::FSWait(&xs);
   959 		NKern::FSWait(&xs);
   960 		CHECK_NOT_RUNNING(info, same_cpu);
   961 		TEST_RESULT(info.iExitCpu==aCpu, "Exit CPU");
   962 		}
   963 	else
   964 		{
   965 		info.iStop = TRUE;	// tell t1 to release mutex and exit
   966 		NKern::FSWait(&xs);	// t2 should also exit
   967 		TEST_RESULT(info2.iExitCpu==xcpu, "Exit CPU");
   968 		TEST_RESULT(info.iExitCpu==-1, "Exit CPU");	// t1 won't exit until we kill t3
   969 		NKern::ThreadKill(t3);
   970 		NKern::FSWait(&xs);
   971 		NKern::FSWait(&xs);
   972 		CHECK_NOT_RUNNING(info, same_cpu);
   973 		TEST_RESULT(info.iExitCpu==aCpu, "Exit CPU");
   974 		}
   975 	CHECK_NOT_RUNNING(info3, same_cpu);
   976 	TEST_RESULT(info3.iExitCpu==aCpu, "Exit CPU");
   977 	}
   978 
   979 void DoBasicThreadTest3(TInt aCpu, TInt aCpu2)
   980 	{
   981 	TEST_PRINT2("aCpu=%d aCpu2=%d", aCpu, aCpu2);
   982 
   983 	TInt this_cpu = NKern::CurrentCpu();
   984 	TBool same_cpu = (aCpu == this_cpu);
   985 	TBool same_cpu2 = (aCpu2 == this_cpu);
   986 	TBool same_cpux = (aCpu2>=0) ? same_cpu2 : same_cpu;
   987 
   988 	SThreadInfo3 info;
   989 	NThread* t;
   990 	NFastSemaphore xs(0);
   991 
   992 	info.Set(SThreadInfo3::ECount, 0, 11, aCpu);
   993 	t = info.CreateThread("Single1", &xs);
   994 	CHECK_NOT_RUNNING(info, same_cpu);
   995 	NKern::ThreadSuspend(t, 1);	// suspend newly created thread before it has been resumed
   996 	CHECK_NOT_RUNNING(info, same_cpu);
   997 	NKern::ThreadResume(t);		// resume - should still be suspended
   998 	CHECK_NOT_RUNNING(info, same_cpu);
   999 	NKern::ThreadResume(t);		// resume - now running
  1000 	CHECK_RUNNING(info, aCpu);
  1001 	NKern::ThreadResume(t);		// resume while running - should be no-op
  1002 	CHECK_RUNNING(info, aCpu);
  1003 	NKern::ThreadSuspend(t, 1);	// suspend running thread
  1004 	CHECK_NOT_RUNNING(info, same_cpu);
  1005 	NKern::ThreadResume(t);		// resume
  1006 	CHECK_RUNNING(info, aCpu);
  1007 	NKern::ThreadSuspend(t, 3);	// suspend running thread multiple times
  1008 	CHECK_NOT_RUNNING(info, same_cpu);
  1009 	NKern::ThreadResume(t);		// resume - still suspended twice
  1010 	CHECK_NOT_RUNNING(info, same_cpu);
  1011 	NKern::ThreadResume(t);		// resume - still suspended once
  1012 	CHECK_NOT_RUNNING(info, same_cpu);
  1013 	NKern::ThreadResume(t);		// resume - now running
  1014 	CHECK_RUNNING(info, aCpu);
  1015 	NKern::ThreadSuspend(t, 3);	// suspend multiple times
  1016 	CHECK_NOT_RUNNING(info, same_cpu);
  1017 	NKern::ThreadForceResume(t);	// force resume - cancel all suspensions at once
  1018 	CHECK_RUNNING(info, aCpu);
  1019 	NKern::ThreadSuspend(t, 1);	// suspend running thread
  1020 	CHECK_NOT_RUNNING(info, same_cpu);
  1021 	NKern::ThreadSuspend(t, 3);	// suspend multiple times when already suspended
  1022 	CHECK_NOT_RUNNING(info, same_cpu);
  1023 	NKern::ThreadResume(t);		// resume - still suspended three times
  1024 	CHECK_NOT_RUNNING(info, same_cpu);
  1025 	NKern::ThreadResume(t);		// resume - still suspended twice
  1026 	CHECK_NOT_RUNNING(info, same_cpu);
  1027 	NKern::ThreadResume(t);		// resume - still suspended once
  1028 	CHECK_NOT_RUNNING(info, same_cpu);
  1029 	NKern::ThreadResume(t);		// resume - now running
  1030 	CHECK_RUNNING(info, aCpu);
  1031 
  1032 	if (aCpu2>=0)
  1033 		{
  1034 		NKern::ThreadSetCpuAffinity(t, aCpu2);	// move running thread to another CPU
  1035 		CHECK_RUNNING(info, aCpu2);
  1036 		NKern::ThreadSetCpuAffinity(t, aCpu);	// move it back
  1037 		CHECK_RUNNING(info, aCpu);
  1038 		NKern::ThreadSuspend(t, 2);				// suspend
  1039 		CHECK_NOT_RUNNING(info, same_cpu);
  1040 		NKern::ThreadSetCpuAffinity(t, aCpu2);	// move suspended thread to another CPU
  1041 		CHECK_NOT_RUNNING(info, same_cpu2);
  1042 		NKern::ThreadResume(t);					// resume - still suspended
  1043 		CHECK_NOT_RUNNING(info, same_cpu2);
  1044 		NKern::ThreadResume(t);					// resume - now running on other CPU
  1045 		CHECK_RUNNING(info, aCpu2);
  1046 		}
  1047 	NKern::ThreadKill(t);
  1048 	CHECK_NOT_RUNNING(info, same_cpux);
  1049 	NKern::FSWait(&xs);
  1050 	TEST_RESULT(info.iExitCpu == ((aCpu2>=0)?aCpu2:aCpu), "Exit CPU");
  1051 
  1052 	SThreadInfo3 info2;
  1053 	NThread* t2;
  1054 
  1055 	info.Set(SThreadInfo3::ECount, 0, 10, aCpu);
  1056 	t = info.CreateThread("Pair1A", &xs);
  1057 	CHECK_NOT_RUNNING(info, same_cpu);
  1058 
  1059 	info2.Set(SThreadInfo3::ECount, 0, 11, aCpu);
  1060 	t2 = info2.CreateThread("Pair1B", &xs);
  1061 	CHECK_NOT_RUNNING(info2, same_cpu);
  1062 
  1063 	NKern::ThreadResume(t);						// resume new thread
  1064 	CHECK_RUNNING(info, aCpu);
  1065 	CHECK_NOT_RUNNING(info2, same_cpu);
  1066 	NKern::ThreadResume(t2);					// resume higher priority thread - should preempt
  1067 	CHECK_RUNNING(info2, aCpu);
  1068 	CHECK_NOT_RUNNING(info, same_cpu);
  1069 
  1070 	NKern::ThreadSetPriority(t, 12);			// increase priority of ready but not running thread - should preempt
  1071 	CHECK_RUNNING(info, aCpu);
  1072 	NKern::ThreadSetPriority(t, 10);			// lower priority of running thread - should yield
  1073 	CHECK_NOT_RUNNING(info, same_cpu);
  1074 
  1075 	NKern::ThreadSetPriority(t2, 9);			// lower priority of running thread - should yield
  1076 	CHECK_RUNNING(info, aCpu);
  1077 	NKern::ThreadSetPriority(t2, 11);			// increase priority of ready but not running thread - should preempt
  1078 	CHECK_NOT_RUNNING(info, same_cpu);
  1079 
  1080 	NKern::ThreadSetPriority(t2, 14);			// increase priority of running thread - stays running
  1081 	CHECK_NOT_RUNNING(info, same_cpu);
  1082 	NKern::ThreadSetPriority(t, 13);			// check priority increase has occurred
  1083 	CHECK_NOT_RUNNING(info, same_cpu);
  1084 	NKern::ThreadSetPriority(t2, 11);			//
  1085 	CHECK_RUNNING(info, aCpu);
  1086 	NKern::ThreadSetPriority(t, 10);			//
  1087 	CHECK_NOT_RUNNING(info, same_cpu);
  1088 
  1089 	if (aCpu2>=0)
  1090 		{
  1091 		NKern::ThreadSetCpuAffinity(t, aCpu2);	// move ready but not running thread to other CPU
  1092 		CHECK_RUNNING(info, aCpu2);
  1093 		CHECK_RUNNING(info2, aCpu);
  1094 		NKern::ThreadSetCpuAffinity(t, aCpu);	// move it back
  1095 		CHECK_RUNNING(info2, aCpu);
  1096 		CHECK_NOT_RUNNING(info, same_cpu);
  1097 		NKern::ThreadSetCpuAffinity(t2, aCpu2);	// move running thread to other CPU - let other thread run on this one
  1098 		CHECK_RUNNING(info, aCpu);
  1099 		CHECK_RUNNING(info2, aCpu2);
  1100 		NKern::ThreadSetCpuAffinity(t2, aCpu);	// move it back
  1101 		CHECK_RUNNING(info2, aCpu);
  1102 		CHECK_NOT_RUNNING(info, same_cpu);
  1103 		}
  1104 
  1105 	NKern::ThreadSuspend(t2, 1);		// suspend running thread
  1106 	CHECK_RUNNING(info, aCpu);
  1107 	CHECK_NOT_RUNNING(info2, same_cpu);
  1108 	NKern::ThreadSetPriority(t2, 9);	// lower priority while suspended
  1109 	CHECK_RUNNING(info, aCpu);
  1110 	CHECK_NOT_RUNNING(info2, same_cpu);
  1111 	NKern::ThreadResume(t2);			// resume - can't now start running again
  1112 	CHECK_RUNNING(info, aCpu);
  1113 	CHECK_NOT_RUNNING(info2, same_cpu);
  1114 	NKern::ThreadSuspend(t2, 1);		// suspend again
  1115 	CHECK_RUNNING(info, aCpu);
  1116 	CHECK_NOT_RUNNING(info2, same_cpu);
  1117 	NKern::ThreadSetPriority(t2, 11);	// increase priority while suspended
  1118 	CHECK_RUNNING(info, aCpu);
  1119 	CHECK_NOT_RUNNING(info2, same_cpu);
  1120 	NKern::ThreadResume(t2);			// resume - starts running again
  1121 	CHECK_RUNNING(info2, aCpu);
  1122 	CHECK_NOT_RUNNING(info, same_cpu);
  1123 
  1124 	NKern::ThreadSuspend(t, 1);			// suspend ready but not running thread
  1125 	CHECK_RUNNING(info2, aCpu);
  1126 	CHECK_NOT_RUNNING(info, same_cpu);
  1127 	NKern::ThreadSetPriority(t2, 1);	// lower running thread priority - stays running
  1128 	CHECK_RUNNING(info2, aCpu);
  1129 	CHECK_NOT_RUNNING(info, same_cpu);
  1130 	NKern::ThreadResume(t);				// resume other thread - now preempts
  1131 	CHECK_RUNNING(info, aCpu);
  1132 	CHECK_NOT_RUNNING(info2, same_cpu);
  1133 	NKern::ThreadSetPriority(t2, 11);	// increase other thread priority - should preempt
  1134 	CHECK_RUNNING(info2, aCpu);
  1135 	CHECK_NOT_RUNNING(info, same_cpu);
  1136 
  1137 	if (aCpu2>=0)
  1138 		{
  1139 		NKern::ThreadSuspend(t2, 1);		// suspend running thread
  1140 		CHECK_RUNNING(info, aCpu);
  1141 		CHECK_NOT_RUNNING(info2, same_cpu);
  1142 		NKern::ThreadSetCpuAffinity(t2, aCpu2);	// move suspended thread to other CPU
  1143 		CHECK_RUNNING(info, aCpu);
  1144 		CHECK_NOT_RUNNING(info2, same_cpu2);
  1145 		NKern::ThreadResume(t2);			// resume - should start running on other CPU
  1146 		CHECK_RUNNING(info, aCpu);
  1147 		CHECK_RUNNING(info2, aCpu2);
  1148 		}
  1149 
  1150 	NKern::ThreadKill(t2);
  1151 	CHECK_NOT_RUNNING(info2, same_cpux);
  1152 	CHECK_RUNNING(info, aCpu);
  1153 	NKern::ThreadKill(t);
  1154 	NKern::FSWait(&xs);
  1155 	NKern::FSWait(&xs);
  1156 	TEST_RESULT(info2.iExitCpu == ((aCpu2>=0)?aCpu2:aCpu), "Exit CPU");
  1157 	TEST_RESULT(info.iExitCpu == aCpu, "Exit CPU");
  1158 
  1159 	DoBasicThreadTest3SemMutex(aCpu, aCpu2, FALSE);
  1160 	DoBasicThreadTest3SemMutex(aCpu, aCpu2, TRUE);
  1161 	DoBasicThreadTest3SemPri(aCpu, aCpu2);
  1162 	DoBasicThreadTest3MutexPri(aCpu, aCpu2, FALSE);
  1163 	DoBasicThreadTest3MutexPri(aCpu, aCpu2, TRUE);
  1164 	}
  1165 
  1166 void BasicThreadTest3()
  1167 	{
  1168 	TEST_PRINT("Testing miscellaneous thread operations");
  1169 
  1170 	DoBasicThreadTest3(0,1);
  1171 	DoBasicThreadTest3(1,0);
  1172 	}
  1173 
  1174 #ifdef __SMP__
  1175 struct SThreadGroupTest1Info
  1176 	{
  1177 	volatile TUint32* iSharedCount;
  1178 	volatile TUint32 iThreadCount;
  1179 	volatile TBool iDone;
  1180 	TUint32 iLimit;
  1181 	};
  1182 
  1183 TUint32 Inc(TUint32 a)
  1184 	{
  1185 	return a+1;
  1186 	}
  1187 
  1188 NThreadGroup TG1;
  1189 
  1190 //////////////////////////////////////////////////////////////////////////////
  1191 // This thread function increments its iThreadCount until it reaches iLimit
  1192 // Each time around the loop it increments iSharedCount with interrupts
  1193 // disabled, but without otherwise taking any precautions to be atomic.
  1194 //
  1195 // If the thread is in the group, then this should behave the same as on a
  1196 // uniprocessor system: the increment is atomic. Otherwise, some updates will
  1197 // be lost.
  1198 
  1199 void ThreadGroupTest1Thread(TAny* aPtr)
  1200 	{
  1201 	SThreadGroupTest1Info& a = *(SThreadGroupTest1Info*)aPtr;
  1202 	a.iThreadCount = 0;
  1203 	NKern::ThreadSetPriority(NKern::CurrentThread(), 12);
  1204 	FOREVER
  1205 		{
  1206 		TUint32 x = ++a.iThreadCount;
  1207 		TInt irq = NKern::DisableAllInterrupts();
  1208 		TUint32 y = *a.iSharedCount;
  1209 		y = Inc(y);
  1210 		*a.iSharedCount = y;
  1211 		NKern::RestoreInterrupts(irq);
  1212 		if (x>=a.iLimit)
  1213 			break;
  1214 		}
  1215 	a.iDone = TRUE;
  1216 	NKern::WaitForAnyRequest();
  1217 	}
  1218 
  1219 //////////////////////////////////////////////////////////////////////////////
  1220 // ThreadGroupTest1
  1221 //
  1222 // Attempt to prove various properties of thread group scheduling by creating
  1223 // a number of copies of a thread that manipulate a shared counter.
  1224 // 
  1225 // 1) Priority scheduling is strictly observed within a group - lower priority
  1226 // threads do not run if any higher priority threads are runnable, no matter
  1227 // the number of available CPUs.
  1228 // 2) Only one thread in a group is ever running at one time, regardless of
  1229 // priorities or the number of available CPUs.
  1230 //
  1231 // Parameters:
  1232 //  aCount: how many threads to create
  1233 //  aJoin: whether to have threads join the group
  1234 
  1235 
  1236 void ThreadGroupTest1(TInt aCount, TBool aJoin, TBool aMigrate, TBool aReJoin)
  1237 	{
  1238 	TEST_PRINT4("ThreadGroupTest1 aCount=%d aJoin=%d aMigrate=%d aReJoin=%d", aCount, aJoin, aMigrate, aReJoin);
  1239 	NFastSemaphore exitSem(0);
  1240 	NThread* t[16];
  1241 	SThreadGroupTest1Info info[16];
  1242 	volatile TUint32 shared=0;
  1243 	memclr(t,sizeof(t));
  1244 	memclr(&info,sizeof(info));
  1245 	TInt i;
  1246 	NThreadGroup* group = aJoin ? &TG1 : 0;
  1247 	SNThreadGroupCreateInfo ginfo;
  1248 	ginfo.iCpuAffinity = 0xffffffff;
  1249 	TInt r = KErrNone;
  1250 	if (group)
  1251 		r = NKern::GroupCreate(group, ginfo);
  1252 	TEST_RESULT(r==KErrNone, "");
  1253 	NThreadGroup* g;
  1254 	g = NKern::LeaveGroup();
  1255 	TEST_RESULT(!g, "");
  1256 	char name[8]={0x54, 0x47, 0x54, 0x31, 0, 0, 0, 0};
  1257 	for (i=0; i<aCount; ++i)
  1258 		{
  1259 		info[i].iThreadCount = KMaxTUint32;
  1260 		info[i].iSharedCount = &shared;
  1261 		info[i].iLimit = 10000000;
  1262 		name[4] = (char)('a'+i);
  1263 		t[i] = CreateUnresumedThreadSignalOnExit(name, &ThreadGroupTest1Thread, 17, &info[i], 0, __microseconds_to_timeslice_ticks(2000), &exitSem, 0xffffffff, group);
  1264 		TEST_OOM(t[i]);
  1265 		}
  1266 	if (group)
  1267 		{
  1268 		NKern::JoinGroup(group);
  1269 		}
  1270 	for (i=0; i<aCount; ++i)
  1271 		{
  1272 		// Each thread starts with count KMaxTUint32
  1273 		TEST_RESULT(info[i].iThreadCount == KMaxTUint32, "");
  1274 		NKern::ThreadResume(t[i]);
  1275 		// Property 1:
  1276 		// After resuming, the thread is higher priority than this one.
  1277 		// It sets the count to 0 then lowers its priority to less than this.
  1278 		// Thus, if we are in a group with it, then we should get preempted while
  1279 		// it sets its count, then regain control after it does. If we were not in
  1280 		// a group, we could observe other values of iThreadCount at this point as
  1281 		// it may not have run at all (scheduled on another CPU which is busy with
  1282 		// a higher priority thread) or may have run for longer (on another CPU)
  1283 		if (group)
  1284 			{
  1285 			TEST_RESULT(info[i].iThreadCount == 0, "");
  1286 			}
  1287 		TEST_PRINT2("Thread %d Count=%d", i, info[i].iThreadCount);
  1288 		}
  1289 	if (group)
  1290 		{
  1291 		TEST_PRINT2("Group Count=%d, SharedCount=%d", group->iThreadCount, shared);
  1292 		TEST_RESULT(group->iThreadCount == aCount+1, "");
  1293 		g = NKern::LeaveGroup();
  1294 		TEST_RESULT(g==group, "");
  1295 		g = NKern::LeaveGroup();
  1296 		TEST_RESULT(!g, "");
  1297 		}
  1298 	else
  1299 		{
  1300 		TEST_PRINT1("SharedCount=%d", shared);
  1301 		}
  1302 	if (aMigrate)
  1303 		{
  1304 		TInt cpu = 0;
  1305 		TInt ncpus = NKern::NumberOfCpus();
  1306 		TUint32 s0 = shared - 1;
  1307 		FOREVER
  1308 			{
  1309 			TInt dead = 0;
  1310 			for (i=0; i<aCount; ++i)
  1311 				if (info[i].iDone)
  1312 					++dead;
  1313 			if (dead == aCount)
  1314 				break;
  1315 			if (shared != s0)
  1316 				{
  1317 				if (++cpu == ncpus)
  1318 					cpu = 1;
  1319 				NKern::ThreadSetCpuAffinity(t[aCount-1], cpu);
  1320 				s0 = shared;
  1321 				}
  1322 			nfcfspin(__microseconds_to_norm_fast_counter(2797));
  1323 			if (aReJoin)
  1324 				{
  1325 				NKern::JoinGroup(group);
  1326 				TEST_RESULT(NKern::CurrentCpu()==cpu,"");
  1327 				TUint32 s1 = shared;
  1328 				nfcfspin(__microseconds_to_norm_fast_counter(2797));
  1329 				TEST_RESULT(shared==s1,"");
  1330 				NThreadGroup* gg = NKern::LeaveGroup();
  1331 				TEST_RESULT(gg==group,"");
  1332 				NKern::ThreadSetCpuAffinity(NKern::CurrentThread(), 0xffffffff);
  1333 				}
  1334 			}
  1335 		}
  1336 	for (i=0; i<aCount; ++i)
  1337 		{
  1338 		NKern::ThreadRequestSignal(t[i]);
  1339 		}
  1340 	for (i=0; i<aCount; ++i)
  1341 		{
  1342 		NKern::FSWait(&exitSem);
  1343 		}
  1344 	TUint32 total = 0;
  1345 	for (i=0; i<aCount; ++i)
  1346 		{
  1347 		TEST_PRINT2("Thread %d Count=%d", i, info[i].iThreadCount);
  1348 		TEST_RESULT(info[i].iThreadCount == info[i].iLimit, "");
  1349 		total += info[i].iLimit;
  1350 		}
  1351 	TEST_PRINT1("SharedCount=%d", shared);
  1352 	if (aJoin)
  1353 		{
  1354 		// Property 2:
  1355 		// If the threads were all in a group, then disabling interrupts would
  1356 		// suffice to make the increment atomic, and the total count should be
  1357 		// the same as the sum of the per-thread counts
  1358 		TEST_RESULT(shared == total, "");
  1359 		}
  1360 	else
  1361 		{
  1362 		// Property 2 continued:
  1363 		// If the threads were not in a group, then disabling interrupts is not
  1364 		// enough, and it's overwhelmingly likely that at least one increment
  1365 		// will've been missed.
  1366 		TEST_RESULT(shared < total, "");
  1367 		}
  1368 	if (group)
  1369 		NKern::GroupDestroy(group);
  1370 	}
  1371 #endif
  1372 
  1373 void BasicThreadTests()
  1374 	{
  1375 	BasicThreadTest1();
  1376 	BasicThreadTest2();
  1377 	TimesliceTest();
  1378 	TimesliceTest2();
  1379 	BasicThreadTest3();
  1380 
  1381 #ifdef __SMP__
  1382 	ThreadGroupTest1(2,0,FALSE,FALSE);
  1383 	ThreadGroupTest1(2,1,FALSE,FALSE);
  1384 	ThreadGroupTest1(3,0,FALSE,FALSE);
  1385 	ThreadGroupTest1(3,1,FALSE,FALSE);
  1386 	ThreadGroupTest1(3,1,TRUE,FALSE);
  1387 	ThreadGroupTest1(3,1,TRUE,TRUE);
  1388 #endif
  1389 	}