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