Update contrib.
1 // Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
2 // All rights reserved.
3 // This component and the accompanying materials are made available
4 // under the terms of the License "Eclipse Public License v1.0"
5 // which accompanies this distribution, and is available
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
14 // e32test\nkernsa\threadbasic.cpp
18 #include <nktest/nkutils.h>
23 #define iNThreadBaseSpare7 iSpare7
28 volatile TInt iRunCount;
29 volatile TInt iBlockEvery;
35 TInt WaitForRun(SThreadInfo1& aI, TInt aCount)
37 TUint32 initial = NKern::TickCount();
38 TUint32 final = initial + 2;
41 if (aI.iRunCount >= aCount)
43 TUint32 x = NKern::TickCount();
44 if ((x - final) < 0x80000000u)
49 void BasicThread(TAny* a)
51 SThreadInfo1& info = *(SThreadInfo1*)a;
52 NThread* pC = NKern::CurrentThread();
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;
61 NKern::WaitForAnyRequest();
65 void BasicThread0(TAny*)
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);
72 SThreadInfo1* pI = (SThreadInfo1*)malloc(KNumPriorities * KMaxCpus * sizeof(SThreadInfo1));
74 memclr(pI, KNumPriorities * KMaxCpus * sizeof(SThreadInfo1));
75 NFastSemaphore exitSem(0);
82 for (pri = 1; pri < KNumPriorities; ++pri)
84 TInt ix = cpu * KNumPriorities + pri;
85 SThreadInfo1& info = pI[ix];
88 info.iThread = CreateUnresumedThreadSignalOnExit("Basic", &BasicThread, pri, &info, 0, -1, &exitSem, cpu);
89 TEST_OOM(info.iThread);
92 TInt c = buf->Count();
93 TEST_RESULT1(c==0, "Unexpected count %d", c); // nothing resumed yet
96 for (pri = 1; pri < KNumPriorities; ++pri)
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)
104 TEST_RESULT(r==1, "WaitForRun");
106 TEST_RESULT1(c==1, "Unexpected count %d", c); // thread should have run
107 TUint32 x = buf->Get();
109 TEST_RESULT1(c==0, "Unexpected count %d", c);
110 TEST_RESULT(x==(TUint32)info.iThread, "Wrong thread");
114 TEST_RESULT(r==KErrTimedOut, "WaitForRun");
116 TEST_RESULT1(c==0, "Unexpected count %d", c); // thread won't have run since current has priority
120 NKern::Sleep(10); // let lower priority threads run
122 TEST_RESULT1(c==my_priority, "Unexpected count %d", c);
123 for (pri = my_priority; pri >= 1; --pri)
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");
133 for (pri = 1; pri < KNumPriorities; ++pri)
135 TInt ix = cpu * KNumPriorities + pri;
136 SThreadInfo1& info = pI[ix];
138 NKern::ThreadRequestSignal(info.iThread);
139 NKern::FSWait(&exitSem);
146 void BasicThreadTest1()
148 TEST_PRINT("Testing all thread priorities without timeslice");
155 for (pri = 1; pri < KNumPriorities; ++pri)
157 TEST_PRINT2("Basic0 pri %d cpu %d", pri, cpu);
158 CreateThreadAndWaitForExit("Basic0", &BasicThread0, pri, 0, 0, -1, cpu);
170 void BasicThreadTest2()
172 TEST_PRINT("Kill an unresumed thread");
173 NFastSemaphore exitSem(0);
178 TEST_PRINT1("Thread on CPU %d", cpu);
179 NThread* t = CreateUnresumedThreadSignalOnExit("Spinner", &Spinner, 33, 0, 0, -1, &exitSem, cpu);
181 NKern::ThreadKill(t);
182 NKern::FSWait(&exitSem);
188 void TimesliceTestThread(TAny* a)
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;
198 TUint32 last_interval_begin = norm_fast_counter();
199 TUint32 last_seen_time = norm_fast_counter();
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)
207 last_interval_begin = nfc;
208 TUint32 x = (id<<24) | interval_length;
209 TInt r = buf->TryPut(x);
213 last_seen_time = nfc;
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);
224 NFastSemaphore exitSem(0);
229 NThread* t[KMaxCpus*3];
232 __microseconds_to_timeslice_ticks(20000),
233 __microseconds_to_timeslice_ticks(23000),
234 __microseconds_to_timeslice_ticks(19000)
238 __microseconds_to_norm_fast_counter(20000),
239 __microseconds_to_norm_fast_counter(23000),
240 __microseconds_to_norm_fast_counter(19000)
246 t[id] = CreateThreadSignalOnExit("Timeslice", &TimesliceTestThread, 10, buf, 0, timeslice[i], &exitSem, cpu);
248 t[id]->iNThreadBaseSpare7 = id;
251 nfcfspin(__microseconds_to_norm_fast_counter(1000));
255 NKern::FSWait(&exitSem);
256 TEST_PRINT("Thread exited");
260 TUint32 ncpus = NKern::NumberOfCpus();
261 TUint32 xcpu = (ncpus>1) ? 1 : 0;
262 while (buf->TryGet(x)==KErrNone)
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)
272 TEST_RESULT2(id==xid, "Expected id %d got id %d", xid, id);
273 TUint32 exp = expected[id%3];
274 TUint32 tol = exp/100;
277 TUint32 diff = (time > exp) ? time - exp : exp - time;
278 TEST_RESULT2(diff < tol, "Out of Tolerance: exp %d got %d", exp, time);
286 TInt Add(TUint32 aTime, TUint32 aId);
293 volatile TInt iCount;
294 volatile TUint32 iId[ENumTimes];
295 volatile TUint32 iTime[ENumTimes];
298 TInt SThreadInfo2::Add(TUint32 aTime, TUint32 aId)
300 TInt c = __e32_atomic_tas_ord32(&iCount, ENumTimes, 0, 1);
309 If Thread1 and Thread2 on different CPUs:
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
318 If Thread1 and Thread2 on same CPU, no mutex:
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
324 If Thread1 and Thread2 on same CPU, mutex:
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
333 void TimesliceTest2Thread1(TAny* a)
335 SThreadInfo2& info = *(SThreadInfo2*)a;
336 TEST_RESULT(info.Add(norm_fast_counter(),1)==KErrNone, "Add failed"); // Point A
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
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));
350 void TimesliceTest2Thread2(TAny* a)
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));
359 void DoTimesliceTest2(TInt aCpu, TInt aSpin1, TInt aSpin2, TInt aSpin3, TBool aUseMutex)
361 TEST_PRINT5("TT2: C=%1d S1=%d S2=%d S3=%d M=%1d", aCpu, aSpin1, aSpin2, aSpin3, aUseMutex);
363 TInt this_cpu = NKern::CurrentCpu();
364 NFastSemaphore exitSem(0);
368 info.iMutex = aUseMutex ? &mutex : 0;
369 info.iSpin1 = aSpin1;
370 info.iSpin2 = aSpin2;
371 info.iSpin3 = aSpin3;
374 TInt timeslice = __microseconds_to_timeslice_ticks(5000);
375 NThread* t1 = CreateUnresumedThreadSignalOnExit("Thread1", &TimesliceTest2Thread1, 10, &info, 0, timeslice, &exitSem, this_cpu);
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);
385 TUint32 pointA=0, pointB=0, pointC=0, pointD=0, pointE=0, pointF=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)
393 TUint32 id = info.iId[i];
394 TUint32 x = info.iTime[i] - info.iTime[0];
395 TEST_PRINT2("%d: %d", id, x);
400 case 1: pointA = x; break;
401 case 2: pointB = x; break;
402 case 3: pointC = x; break;
403 case 4: pointD = x; break;
410 case 1: pointE = x; break;
411 case 2: pointF = x; break;
416 TEST_RESULT(RANGE_CHECK(0, pointA, delta), "pointA");
417 if (aCpu != this_cpu)
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");
427 TEST_RESULT(RANGE_CHECK(TUint32(aSpin1), pointB, aSpin1+delta), "pointB");
428 TEST_RESULT(RANGE_CHECK(pointB+aSpin2, pointC, pointB+aSpin2+delta), "pointC");
430 TUint32 xpe = aSpin1 + aSpin2;
437 TEST_RESULT(RANGE_CHECK(xpe, pointE, xpe+delta), "pointE");
438 TEST_RESULT(RANGE_CHECK(xpd, pointD, xpd+delta), "pointD");
442 TUint32 xpb = aSpin1;
443 TUint32 xpe = aSpin1;
448 TEST_RESULT(RANGE_CHECK(xpb, pointB, xpb+delta), "pointB");
449 TEST_RESULT(RANGE_CHECK(xpe, pointE, xpe+delta), "pointE");
453 void TimesliceTest2()
456 TInt ms = __microseconds_to_norm_fast_counter(1000);
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);
486 volatile TInt iCount;
487 volatile TInt iCurrCpu;
488 volatile TBool iStop;
489 NFastSemaphore* iExitSem;
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);
498 void BasicThread3(TAny* a)
500 SThreadInfo3& info = *(SThreadInfo3*)a;
504 case SThreadInfo3::ESpin:
507 info.iCurrCpu = NKern::CurrentCpu();
510 case SThreadInfo3::ECount:
513 info.iCurrCpu = NKern::CurrentCpu();
514 __e32_atomic_add_ord32(&info.iCount, 1);
517 case SThreadInfo3::EWaitFS:
518 NKern::FSSetOwner((NFastSemaphore*)info.iObj, 0);
519 NKern::FSWait((NFastSemaphore*)info.iObj);
522 case SThreadInfo3::EWaitFM:
523 NKern::FMWait((NFastMutex*)info.iObj);
524 NKern::FMSignal((NFastMutex*)info.iObj);
527 case SThreadInfo3::EExit:
530 case SThreadInfo3::EHoldFM:
531 NKern::FMWait((NFastMutex*)info.iObj);
534 info.iCurrCpu = NKern::CurrentCpu();
535 __e32_atomic_add_ord32(&info.iCount, 1);
537 NKern::FMSignal((NFastMutex*)info.iObj);
542 void SThreadInfo3::ExitHandler(TAny* aP, NThread* aT, TInt aC)
544 SThreadInfo3& info = *(SThreadInfo3*)aP;
548 info.iExitCpu = NKern::CurrentCpu();
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");
570 NKern::FSSignal(info.iExitSem);
575 NThread* SThreadInfo3::CreateThread(const char* aName, NFastSemaphore* aExitSem)
579 NThread* t = ::CreateThread(aName, &BasicThread3, iPri, this, 0, FALSE, -1, &SThreadInfo3::ExitHandler, this, iCpu);
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)
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)
590 void DoBasicThreadTest3SemMutex(TInt aCpu, TInt aCpu2, TBool aMutex)
594 NFastSemaphore xs(0);
600 TEST_PRINT("Operations while blocked on mutex");
604 TEST_PRINT("Operations while blocked on semaphore");
607 SThreadInfo3::TTestType type = aMutex ? SThreadInfo3::EWaitFM : SThreadInfo3::EWaitFS;
608 TAny* obj = aMutex ? (TAny*)&m : (TAny*)&s;
610 info.Set(type, obj, 63, aCpu);
611 t = info.CreateThread("Single2", &xs);
613 TEST_RESULT(s.iCount==0, "Sem count");
616 NKern::ThreadResume(t); // resume thread - should wait on semaphore/mutex
617 NKern::Sleep(SLEEP_TIME);
619 TEST_RESULT(s.iCount<0, "Sem count");
620 TEST_RESULT(info.iExitCpu==-1, "Exit CPU");
622 aMutex ? NKern::FMSignal(&m) : NKern::FSSignal(&s); // signal semaphore/mutex - thread should exit
625 TEST_RESULT(s.iCount==0, "Sem count");
626 TEST_RESULT(info.iExitCpu==aCpu, "Exit CPU");
628 info.Set(type, obj, 63, aCpu);
629 t = info.CreateThread("Single3", &xs);
631 TEST_RESULT(s.iCount==0, "Sem count");
634 NKern::ThreadResume(t); // resume thread - should wait on semaphore/mutex
635 NKern::Sleep(SLEEP_TIME);
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);
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);
647 TEST_RESULT(s.iCount==0, "Sem count");
648 TEST_RESULT(info.iExitCpu==-1, "Exit CPU");
649 NKern::ThreadResume(t); // resume - should now exit
652 TEST_RESULT(s.iCount==0, "Sem count");
653 TEST_RESULT(info.iExitCpu==aCpu, "Exit CPU");
655 info.Set(type, obj, 63, aCpu);
656 t = info.CreateThread("Single4", &xs);
658 TEST_RESULT(s.iCount==0, "Sem count");
661 NKern::ThreadResume(t); // resume thread - should wait on semaphore/mutex
662 NKern::Sleep(SLEEP_TIME);
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
669 TEST_RESULT(s.iCount==0, "Sem count");
670 TEST_RESULT(info.iExitCpu==aCpu, "Exit CPU");
674 info.Set(type, obj, 63, aCpu);
675 t = info.CreateThread("Single5", &xs);
677 TEST_RESULT(s.iCount==0, "Sem count");
680 NKern::ThreadResume(t); // resume thread - should wait on semaphore/mutex
681 NKern::Sleep(SLEEP_TIME);
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);
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
693 TEST_RESULT(s.iCount==0, "Sem count");
694 TEST_RESULT(info.iExitCpu==aCpu, "Exit CPU");
700 info.Set(type, obj, 63, aCpu);
701 t = info.CreateThread("Single6", &xs);
703 TEST_RESULT(s.iCount==0, "Sem count");
706 NKern::ThreadResume(t); // resume thread - should wait on semaphore/mutex
707 NKern::Sleep(SLEEP_TIME);
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
715 TEST_RESULT(s.iCount==0, "Sem count");
716 TEST_RESULT(info.iExitCpu==aCpu2, "Exit CPU");
718 info.Set(type, obj, 63, aCpu);
719 t = info.CreateThread("Single3", &xs);
721 TEST_RESULT(s.iCount==0, "Sem count");
724 NKern::ThreadResume(t); // resume thread - should wait on semaphore/mutex
725 NKern::Sleep(SLEEP_TIME);
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);
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);
738 TEST_RESULT(s.iCount==0, "Sem count");
739 TEST_RESULT(info.iExitCpu==-1, "Exit CPU");
740 NKern::ThreadResume(t); // resume - should now exit
743 TEST_RESULT(s.iCount==0, "Sem count");
744 TEST_RESULT(info.iExitCpu==aCpu2, "Exit CPU");
746 info.Set(type, obj, 63, aCpu);
747 t = info.CreateThread("Single4", &xs);
749 TEST_RESULT(s.iCount==0, "Sem count");
752 NKern::ThreadResume(t); // resume thread - should wait on semaphore/mutex
753 NKern::Sleep(SLEEP_TIME);
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
761 TEST_RESULT(s.iCount==0, "Sem count");
762 TEST_RESULT(info.iExitCpu==aCpu2, "Exit CPU");
766 info.Set(type, obj, 63, aCpu);
767 t = info.CreateThread("Single5", &xs);
769 TEST_RESULT(s.iCount==0, "Sem count");
772 NKern::ThreadResume(t); // resume thread - should wait on semaphore/mutex
773 NKern::Sleep(SLEEP_TIME);
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);
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
786 TEST_RESULT(s.iCount==0, "Sem count");
787 TEST_RESULT(info.iExitCpu==aCpu2, "Exit CPU");
793 void DoBasicThreadTest3SemPri(TInt aCpu, TInt aCpu2)
796 TEST_PRINT("Change priority + semaphore");
797 TInt this_cpu = NKern::CurrentCpu();
798 TBool same_cpu = (aCpu == this_cpu);
803 NFastSemaphore xs(0);
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");
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);
818 NKern::ThreadSetPriority(t, 63); // change priority while blocked
819 NKern::FSSignal(&s); // signal semaphore - should run and exit immediately
821 TEST_RESULT(s.iCount==0, "Sem count");
822 TEST_RESULT(info.iExitCpu==aCpu, "Exit CPU");
823 CHECK_RUNNING(info2, aCpu);
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);
838 NKern::ThreadKill(t2);
839 CHECK_NOT_RUNNING(info2, same_cpu);
842 TEST_RESULT(info2.iExitCpu==aCpu, "Exit CPU");
843 TEST_RESULT(info.iExitCpu==aCpu, "Exit CPU");
846 void DoBasicThreadTest3MutexPri(TInt aCpu, TInt aCpu2, TBool aKill)
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);
858 NFastSemaphore xs(0);
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");
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");
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");
947 TInt xcpu = (aCpu2>=0) ? aCpu2: aCpu;
950 NKern::ThreadKill(t2); // kill t2 - t1 should lose inherited priority
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");
957 NKern::ThreadKill(t3);
960 CHECK_NOT_RUNNING(info, same_cpu);
961 TEST_RESULT(info.iExitCpu==aCpu, "Exit CPU");
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);
972 CHECK_NOT_RUNNING(info, same_cpu);
973 TEST_RESULT(info.iExitCpu==aCpu, "Exit CPU");
975 CHECK_NOT_RUNNING(info3, same_cpu);
976 TEST_RESULT(info3.iExitCpu==aCpu, "Exit CPU");
979 void DoBasicThreadTest3(TInt aCpu, TInt aCpu2)
981 TEST_PRINT2("aCpu=%d aCpu2=%d", aCpu, aCpu2);
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;
990 NFastSemaphore xs(0);
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);
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);
1047 NKern::ThreadKill(t);
1048 CHECK_NOT_RUNNING(info, same_cpux);
1050 TEST_RESULT(info.iExitCpu == ((aCpu2>=0)?aCpu2:aCpu), "Exit CPU");
1055 info.Set(SThreadInfo3::ECount, 0, 10, aCpu);
1056 t = info.CreateThread("Pair1A", &xs);
1057 CHECK_NOT_RUNNING(info, same_cpu);
1059 info2.Set(SThreadInfo3::ECount, 0, 11, aCpu);
1060 t2 = info2.CreateThread("Pair1B", &xs);
1061 CHECK_NOT_RUNNING(info2, same_cpu);
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);
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);
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);
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);
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);
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);
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);
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);
1150 NKern::ThreadKill(t2);
1151 CHECK_NOT_RUNNING(info2, same_cpux);
1152 CHECK_RUNNING(info, aCpu);
1153 NKern::ThreadKill(t);
1156 TEST_RESULT(info2.iExitCpu == ((aCpu2>=0)?aCpu2:aCpu), "Exit CPU");
1157 TEST_RESULT(info.iExitCpu == aCpu, "Exit CPU");
1159 DoBasicThreadTest3SemMutex(aCpu, aCpu2, FALSE);
1160 DoBasicThreadTest3SemMutex(aCpu, aCpu2, TRUE);
1161 DoBasicThreadTest3SemPri(aCpu, aCpu2);
1162 DoBasicThreadTest3MutexPri(aCpu, aCpu2, FALSE);
1163 DoBasicThreadTest3MutexPri(aCpu, aCpu2, TRUE);
1166 void BasicThreadTest3()
1168 TEST_PRINT("Testing miscellaneous thread operations");
1170 DoBasicThreadTest3(0,1);
1171 DoBasicThreadTest3(1,0);
1175 struct SThreadGroupTest1Info
1177 volatile TUint32* iSharedCount;
1178 volatile TUint32 iThreadCount;
1179 volatile TBool iDone;
1183 TUint32 Inc(TUint32 a)
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.
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
1199 void ThreadGroupTest1Thread(TAny* aPtr)
1201 SThreadGroupTest1Info& a = *(SThreadGroupTest1Info*)aPtr;
1203 NKern::ThreadSetPriority(NKern::CurrentThread(), 12);
1206 TUint32 x = ++a.iThreadCount;
1207 TInt irq = NKern::DisableAllInterrupts();
1208 TUint32 y = *a.iSharedCount;
1210 *a.iSharedCount = y;
1211 NKern::RestoreInterrupts(irq);
1216 NKern::WaitForAnyRequest();
1219 //////////////////////////////////////////////////////////////////////////////
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.
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.
1232 // aCount: how many threads to create
1233 // aJoin: whether to have threads join the group
1236 void ThreadGroupTest1(TInt aCount, TBool aJoin, TBool aMigrate, TBool aReJoin)
1238 TEST_PRINT4("ThreadGroupTest1 aCount=%d aJoin=%d aMigrate=%d aReJoin=%d", aCount, aJoin, aMigrate, aReJoin);
1239 NFastSemaphore exitSem(0);
1241 SThreadGroupTest1Info info[16];
1242 volatile TUint32 shared=0;
1243 memclr(t,sizeof(t));
1244 memclr(&info,sizeof(info));
1246 NThreadGroup* group = aJoin ? &TG1 : 0;
1247 SNThreadGroupCreateInfo ginfo;
1248 ginfo.iCpuAffinity = 0xffffffff;
1251 r = NKern::GroupCreate(group, ginfo);
1252 TEST_RESULT(r==KErrNone, "");
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)
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);
1268 NKern::JoinGroup(group);
1270 for (i=0; i<aCount; ++i)
1272 // Each thread starts with count KMaxTUint32
1273 TEST_RESULT(info[i].iThreadCount == KMaxTUint32, "");
1274 NKern::ThreadResume(t[i]);
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)
1285 TEST_RESULT(info[i].iThreadCount == 0, "");
1287 TEST_PRINT2("Thread %d Count=%d", i, info[i].iThreadCount);
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, "");
1300 TEST_PRINT1("SharedCount=%d", shared);
1305 TInt ncpus = NKern::NumberOfCpus();
1306 TUint32 s0 = shared - 1;
1310 for (i=0; i<aCount; ++i)
1319 NKern::ThreadSetCpuAffinity(t[aCount-1], cpu);
1322 nfcfspin(__microseconds_to_norm_fast_counter(2797));
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);
1336 for (i=0; i<aCount; ++i)
1338 NKern::ThreadRequestSignal(t[i]);
1340 for (i=0; i<aCount; ++i)
1342 NKern::FSWait(&exitSem);
1345 for (i=0; i<aCount; ++i)
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;
1351 TEST_PRINT1("SharedCount=%d", shared);
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, "");
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, "");
1369 NKern::GroupDestroy(group);
1373 void BasicThreadTests()
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);