kerneltest/e32test/nkernsa/threadbasic.cpp
changeset 0 a41df078684a
child 90 947f0dc9f7a8
child 256 c1f20ce4abcf
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\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 	}