diff -r 000000000000 -r a41df078684a kerneltest/e32test/prime/t_semutx2.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kerneltest/e32test/prime/t_semutx2.cpp Mon Oct 19 15:55:17 2009 +0100 @@ -0,0 +1,1414 @@ +// Copyright (c) 1995-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// e32test\prime\t_semutx2.cpp +// Test RSemaphore and RMutex +// Overview: +// Tests the RSemaphore and RMutex +// API Information: +// RSemaphore, RMutex +// Details: +// - Test and verify that thread priorities work as expected. +// - Test and verify that signalling an RMutex from the wrong +// thread fails as expected. +// - Test and verify that mutex priority inheritance works as +// expected. +// - Perform an exhaustive state transition test using mutexs +// and up to ten threads. Verify priorities, order of execution, +// mutex signalling, suspend, resume, kill and close. Verify +// results are as expected. +// - Test semaphore speed by counting how many Wait/Signal +// operations can be completed in one second. +// Platforms/Drives/Compatibility: +// All. +// Assumptions/Requirement/Pre-requisites: +// Failures and causes: +// Base Port information: +// +// + +#include + +RMutex M1; +RMutex M2; +RSemaphore S; + +const TInt KBufferSize=4096; +TUint ThreadId[KBufferSize]; +TInt PutIx; +TInt GetIx; +TInt Count; +RThread Main; + + +RTest test(_L("T_SEMUTX2")); + +/***************************************************************************** + * Utility functions / macros + *****************************************************************************/ +#define TRACE_ON User::SetDebugMask(0xffdfffff); +#define TRACE_OFF User::SetDebugMask(0x80000000); + +//#define MCOUNT(m,c) test((m).Count() ==(c)) +// mutex count value is not visible for user any more +#define MCOUNT(m,c) (void)(1) +#define IDCHECK(x) test(GetNextId()==(x)) +#define NUMCHECK(x) test(NumIdsPending()==(x)) + +#define id0 id[0] +#define id1 id[1] +#define id2 id[2] +#define id3 id[3] +#define id4 id[4] +#define id5 id[5] +#define id6 id[6] +#define id7 id[7] +#define id8 id[8] +#define id9 id[9] +#define id10 id[10] + +TBool Exists(const TDesC& aName) + { + TFullName n(RProcess().Name()); + n+=_L("::"); + n+=aName; + TFindThread ft(n); + TFullName fn; + return ft.Next(fn)==KErrNone; + } + +TBool Exists(TInt aNum) + { + TBuf<4> b; + b.Num(aNum); + return Exists(b); + } + +void BusyWait(TInt aMicroseconds) + { + TTime begin; + begin.HomeTime(); + FOREVER + { + TTime now; + now.HomeTime(); + TTimeIntervalMicroSeconds iv=now.MicroSecondsFrom(begin); + if (iv.Int64()>=TInt64(aMicroseconds)) + return; + } + } + +void Kick(RThread& t) + { + TRequestStatus s; + TRequestStatus* pS=&s; + t.RequestComplete(pS,0); + } + +TUint GetNextId() + { + if (GetIx b; + b.Num(n); + TInt r=t.Create(b,ThreadFunction,0x1000,NULL,aPtr); + test(r==KErrNone); + t.Resume(); + TUint id=t.Id(); + test.Printf(_L("id=%d\n"),id); + return id; + } + +/* +Possible thread relationships with mutex: + Holding + Waiting + Waiting + suspended + Hold Pending + +Need to verify correct behaviour when the following actions occur for each of these states: + Suspend thread + Resume thread + Change thread priority + Thread exits + Thread is killed + Mutex deleted +*/ + +PFV HoldExtra; +void KickMain() + { + RThread me; + Kick(Main); + User::WaitForAnyRequest(); + me.SetPriority(EPriorityMuchMore); + MutexSignal(); // this should wake up t8 + MutexWait(); + MutexSignal(); // this should wake up t9 + MutexWait(); + Kick(Main); + User::WaitForAnyRequest(); + if (HoldExtra) + HoldExtra(); + } + +void RackEmUp(RThread* t, PFV* f, TUint* id) + { + // set up t4 holding + // t1, t2, t5, t10 waiting + // t3, t6, t7 waiting+suspended + // t8, t9 pending + MCOUNT(M1,1); // check mutex free + Kick(t[4]); + f[4]=&KickMain; + User::WaitForAnyRequest(); + MCOUNT(M1,0); // check mutex now held + TInt i; + for (i=1; i<=10; ++i) + if (i!=4) + Kick(t[i]); // wake up threads + User::After(50000); // let threads wait + MCOUNT(M1,-9); // check 9 threads waiting + Kick(t[4]); + User::WaitForAnyRequest(); + MCOUNT(M1,-7); // check 7 threads waiting + NUMCHECK(3); + IDCHECK(id4); // from the initial wait + IDCHECK(id4); // now have t8, t9 pending, t4 holding, rest waiting + IDCHECK(id4); // now have t8, t9 pending, t4 holding, rest waiting + t[4].SetPriority(EPriorityNormal); + t[7].Resume(); // test resume when not suspended + MCOUNT(M1,-7); // check 7 threads waiting + t[3].Suspend(); + t[6].Suspend(); + t[7].Suspend(); // now have required state + t[3].Suspend(); // suspend and resume t3 again for good measure + t[3].Resume(); + MCOUNT(M1,-7); // check 7 threads waiting + HoldExtra=NULL; + } + +void SimpleCheck(TInt n, const TUint* id, ...) + { + VA_LIST list; + VA_START(list,id); + User::After(50000); // let stuff happen + NUMCHECK(n); + TInt i; + for (i=0; i b; + b.Num(n); + TInt r=t.Create(b,SemThreadFunction,0x1000,NULL,aPtr); + test(r==KErrNone); + t.Resume(); + TUint id=t.Id(); + return id; + } + +/* +Possible thread relationships with semaphore: + Waiting + Waiting + suspended + +Need to verify correct behaviour when the following actions occur for each of these states: + Suspend thread + Resume thread + Change thread priority + Thread exits + Thread is killed + Semaphore deleted +*/ + +void RackEmUp2(RThread* t, PFV* f, TUint* id) + { + // set up + // t1, t2, t4, t5, t6, t8, t9 waiting + // t3, t7, t10 waiting+suspended + (void)f; + MCOUNT(S,2); // check semaphore level = 2 + SemWait(); + SemWait(); + MCOUNT(S,0); // check semaphore level = 0 + NUMCHECK(2); + IDCHECK(id0); + IDCHECK(id0); + TInt i; + for (i=1; i<=10; ++i) + Kick(t[i]); // wake up threads + User::After(50000); // let threads wait + MCOUNT(S,-10); // check 10 threads waiting + t[7].Resume(); // test resume when not suspended + MCOUNT(S,-10); // check 7 threads waiting + t[3].Suspend(); + t[7].Suspend(); + t[10].Suspend(); // now have required state + t[3].Suspend(); // suspend and resume t3 again for good measure + t[3].Resume(); + MCOUNT(S,-7); // check 7 threads waiting + } + +void Resurrect2(TInt n, TThreadPriority aPriority, RThread* t, PFV* f, TUint* id) + { + f[n]=NULL; + id[n]=CreateSemThread(t[n],n,f+n); + t[n].SetPriority(EPriorityRealTime); + t[n].SetPriority(aPriority); + NUMCHECK(1); + IDCHECK(id[n]); + } + +/***************************************************************************** + * Semaphore exhaustive state transition test + *****************************************************************************/ +void TestSemaphore() + { + test.Start(_L("Test semaphore state transitions")); + RThread t[11]; + TUint id[11]; + PFV f[11]={NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}; + id[0]=(TUint)RThread().Id(); + PutIx=0; + GetIx=0; + Count=0; + test.Next(_L("Create semaphore")); + TInt r=S.CreateLocal(2); + test(r==KErrNone); + MCOUNT(S,2); + SemWait(); + MCOUNT(S,1); + SemSignal(); + MCOUNT(S,2); + SemWait(); + SemWait(); + MCOUNT(S,0); + S.Signal(2); + MCOUNT(S,2); + NUMCHECK(3); + IDCHECK(id0); + IDCHECK(id0); + IDCHECK(id0); + test.Next(_L("Create threads")); + TInt i; + for (i=1; i<=10; ++i) + { + id[i]=CreateSemThread(t[i],i,f+i); + f[i]=&Wait; + } + t[8].SetPriority(EPriorityMore); // t1-t3=less, t4-t7=normal, t8-t10 more, t0 much more + t[9].SetPriority(EPriorityMore); + t[10].SetPriority(EPriorityMore); + t[1].SetPriority(EPriorityLess); + t[2].SetPriority(EPriorityLess); + t[3].SetPriority(EPriorityLess); + User::After(50000); + MCOUNT(S,-8); // check 8 waiting + NUMCHECK(2); + IDCHECK(id8); + IDCHECK(id9); // check t8,t9 got through + t[8].SetPriority(EPriorityRealTime); + Kick(t[8]); // let t8 run and signal + t[8].SetPriority(EPriorityMore); + MCOUNT(S,-7); // check 7 waiting + User::After(50000); // let next thread obtain semaphore + MCOUNT(S,-7); // check 7 waiting + NUMCHECK(1); + IDCHECK(id10); // check t10 got it + Kick(t[10]); // let t10 run and signal + User::After(50000); // let next thread obtain semaphore + MCOUNT(S,-6); // check 6 waiting + NUMCHECK(1); + IDCHECK(id4); // check t4 got it + t[1].SetPriority(EPriorityRealTime); // boost t1 + MCOUNT(S,-6); // check 6 still waiting + User::After(50000); // let next thread obtain semaphore + MCOUNT(S,-6); // check 6 still waiting + NUMCHECK(0); + Kick(t[9]); // make t9 ready to run and signal + MCOUNT(S,-6); // check 6 still waiting + User::After(50000); // let next thread obtain semaphore + MCOUNT(S,-5); // check 5 waiting + NUMCHECK(1); + IDCHECK(id1); // check t1 got it + t[1].SetPriority(EPriorityLess); + Kick(t[1]); // kick all remaining threads + Kick(t[2]); + Kick(t[3]); + Kick(t[4]); + Kick(t[5]); + Kick(t[6]); + Kick(t[7]); + User::After(50000); // let them run and obtain/signal the semaphore + MCOUNT(S,2); // check semaphore now back to initial level + SimpleCheck(5,id,5,6,7,2,3); + + for (i=1; i<=10; ++i) + f[i]=NULL; + RackEmUp2(t,f,id); // set up threads waiting on semaphore again + S.Signal(); + SimpleCheck(7,id,8,9,4,5,6,1,2); // let them go + MCOUNT(S,1); + S.Wait(); + t[3].SetPriority(EPriorityRealTime); // change suspended thread priority + t[7].Resume(); + SimpleCheck(0,id); // t7 should wait for signal + S.Signal(); + SimpleCheck(1,id,7); + MCOUNT(S,1); + t[3].Resume(); + t[10].Resume(); + NUMCHECK(1); + IDCHECK(id3); // t3 should have grabbed semaphore as soon as we resumed it + SimpleCheck(1,id,10); + t[3].SetPriority(EPriorityLess); + S.Signal(); // put level back to 2 + + RackEmUp2(t,f,id); // set up threads waiting on semaphore again + S.Signal(); + SimpleCheck(7,id,8,9,4,5,6,1,2); // let them go + MCOUNT(S,1); + S.Wait(); + t[3].SetPriority(EPriorityRealTime); // change suspended thread priority + t[7].Resume(); + SimpleCheck(0,id); // t7 should wait for signal + S.Signal(); + SimpleCheck(1,id,7); + MCOUNT(S,1); + t[10].Resume(); + t[3].Resume(); // t3 not woken up here since t10 has already been given the semaphore + NUMCHECK(0); + SimpleCheck(2,id,10,3); + t[3].SetPriority(EPriorityLess); + S.Signal(); // put level back to 2 + + RackEmUp2(t,f,id); // set up threads waiting on semaphore again + S.Signal(); + SimpleCheck(7,id,8,9,4,5,6,1,2); // let them go + MCOUNT(S,1); + S.Wait(); + t[3].SetPriority(EPriorityRealTime); // change suspended thread priority + t[7].Resume(); + SimpleCheck(0,id); // t7 should wait for signal + S.Signal(); + S.Signal(); // put level back to 2 + SimpleCheck(1,id,7); + MCOUNT(S,2); + t[10].Resume(); + t[3].Resume(); // t3 and t10 both woken up here, t3 should run and signal + MCOUNT(S,1); + NUMCHECK(1); + IDCHECK(id3); + SimpleCheck(1,id,10); + t[3].SetPriority(EPriorityLess); + + RackEmUp2(t,f,id); // set up threads waiting on semaphore again + t[9].Kill(0); // kill waiting thread + t[9].Close(); + test(!Exists(9)); + t[10].Kill(0); // kill suspended thread + t[10].Close(); + test(!Exists(10)); + MCOUNT(S,-6); + f[5]=&Exit; // get t5 to exit after acquiring semaphore + S.Signal(); + SimpleCheck(3,id,8,4,5); // let them go + MCOUNT(S,-3); // check one signal has been lost due to t5 exiting + t[5].Close(); + test(!Exists(5)); + t[3].Resume(); + t[7].Resume(); + MCOUNT(S,-5); + S.Signal(); + SimpleCheck(5,id,6,7,1,2,3); // let them go + MCOUNT(S,1); + Resurrect2(9,EPriorityMore,t,f,id); + Resurrect2(10,EPriorityMore,t,f,id); + Resurrect2(5,EPriorityNormal,t,f,id); + S.Signal(); + + RackEmUp2(t,f,id); // set up threads waiting on semaphore again + f[5]=&Exit; // get t5 to exit after acquiring semaphore + S.Close(); // close semaphore - threads should panic except for 5 + + TBool jit = User::JustInTime(); + User::SetJustInTime(EFalse); + User::After(1000000); + User::SetJustInTime(jit); + for (i=1; i<=10; ++i) + { + if (i==3 || i==7 || i==10) + { + test(t[i].ExitType()==EExitPending); + } + else if (i!=5) + { + test(t[i].ExitType()==EExitPanic); + test(t[i].ExitReason()==EBadHandle); + test(t[i].ExitCategory()==_L("KERN-EXEC")); + t[i].Close(); + test(!Exists(i)); + } + else + { + test(t[i].ExitType()==EExitKill); + test(t[i].ExitReason()==0); + t[i].Close(); + test(!Exists(i)); + } + } + t[3].Resume(); + t[7].Resume(); + t[10].Resume(); + User::SetJustInTime(EFalse); + User::After(1000000); + User::SetJustInTime(jit); + for (i=1; i<=10; ++i) + { + if (i==3 || i==7 || i==10) + { + test(t[i].ExitType()==EExitPanic); + test(t[i].ExitReason()==EBadHandle); + test(t[i].ExitCategory()==_L("KERN-EXEC")); + t[i].Close(); + test(!Exists(i)); + } + } + + test.End(); + } + +/***************************************************************************** + * Semaphore benchmarks + *****************************************************************************/ +TInt SemSpeed(TAny* aPtr) + { + TInt& count=*(TInt*)aPtr; + RThread().SetPriority(EPriorityMore); + FOREVER + { + S.Wait(); + S.Signal(); + ++count; + } + } + +void TestSemSpeed() + { + test.Start(_L("Test semaphore speed")); + TInt count=0; + TInt r=S.CreateLocal(1); + test(r==KErrNone); + + RThread t; + r=t.Create(_L("SemSpeed"),SemSpeed,0x1000,NULL,&count); + test(r==KErrNone); + t.SetPriority(EPriorityRealTime); + t.Resume(); + User::AfterHighRes(1000000); + t.Kill(0); + t.Close(); + test(!Exists(_L("SemSpeed"))); + test.Printf(_L("%d wait/signal in 1 second\n"),count); + + S.Close(); + test.End(); + } + + +GLDEF_C TInt E32Main() + { + test.Title(); + + test.Start(_L("Test mutexes and semaphores")); + RThread().SetPriority(EPriorityMuchMore); + TInt r=Main.Duplicate(RThread()); + test(r==KErrNone); + + Test0(); + Test1(); + TestMutex1(); + TestMutex2(); + TestSemaphore(); + + TestMutexSpeed(); + TestSemSpeed(); + + Main.Close(); + test.End(); + return KErrNone; + } +