diff -r 73ea206103e6 -r 43365a9b78a3 kerneltest/e32test/prime/t_semutx.cpp --- a/kerneltest/e32test/prime/t_semutx.cpp Wed Jun 23 19:44:53 2010 +0300 +++ b/kerneltest/e32test/prime/t_semutx.cpp Tue Jul 06 15:50:07 2010 +0300 @@ -40,7 +40,9 @@ #define __E32TEST_EXTENSION__ #include -#include +#include +#include +#include #include const TInt KMaxBufferSize=10; @@ -51,13 +53,352 @@ RTest test(_L("T_SEMUTX")); RMutex mutex; -RCriticalSection criticalSn; +RCriticalSection criticalSn; TInt thread1Count,thread2Count; TInt arrayIndex; -TInt array[KMaxArraySize]; +TInt array[KMaxArraySize]; TInt consumerArray[KNumProducerItems]; -RSemaphore slotAvailable,itemAvailable; +RSemaphore slotAvailable,itemAvailable; +TBool doCpuLocking = EFalse; + +// return num of cpus in system +TInt NumCpus() + { + TInt r = UserSvr::HalFunction(EHalGroupKernel, EKernelHalNumLogicalCpus, 0, 0); + return r; + } + + +TInt LockCurrentThreadToCpu0(TBool aCallingIsMainTestThread = EFalse) + { + if (aCallingIsMainTestThread) + { + if (NumCpus() > 1) + { + doCpuLocking = ETrue; + return UserSvr::HalFunction(EHalGroupKernel, EKernelHalLockThreadToCpu, 0, 0); + } + else + { + return KErrNone; + } + } + return UserSvr::HalFunction(EHalGroupKernel, EKernelHalLockThreadToCpu, 0, 0); + } + +TInt UnlockCurrentThreadToCpu0(TBool aCallingIsMainTestThread = EFalse) + { + if (aCallingIsMainTestThread) + { + if (NumCpus() > 1) + { + doCpuLocking = EFalse; + return UserSvr::HalFunction(EHalGroupKernel, EKernelHalLockThreadToCpu, (TAny*) 0xffffffffu, 0); + } + else + { + return KErrNone; + } + } + return UserSvr::HalFunction(EHalGroupKernel, EKernelHalLockThreadToCpu, (TAny*) 0xffffffffu, 0); + } + + +/****************************************************************************** + * Random Number Generation + ******************************************************************************/ +void Random(TUint64& a) + { + TInt i; + for (i=64; i>0; --i) + { + TUint64 x = a<<1; + TUint64 y = x<<1; + x^=y; + a = (y>>1) | (x>>63); + } + } + +// Returns 256*log2(a/2^64) +TInt Log2(TUint64 a) + { + const TUint64 KBit63 = UI64LIT(0x8000000000000000); + TInt n = __e32_find_ms1_64(a); + a <<= (63-n); + n -= 64; + TInt i; + for (i=0; i<8; ++i) + { + a >>= 32; + a *= a; + n <<= 1; + if (a & KBit63) + { + ++n; + } + else + { + a <<= 1; + } + } + return n; + } + +TUint32 ExpRV(TUint64 aU, TUint32 aMean, TUint32 aTick) + { + TInt n = -Log2(aU); + TUint64 x = TUint64(n) * TUint64(aMean); + x *= TUint64(22713); // 2^15 * ln2 + TUint64 p(aTick); + p <<= 22; + x += p; + p += p; + x /= p; + return I64LOW(x); + } + + + +/*----------------------------------------------------------------------------*/ +class MLock + { +public: + enum {EPollable=1, ETimeoutAvail=2, ENestable=4, ELimit1=8, ELooseTimeout=16}; +public: + virtual TInt Flags()=0; + virtual void Release()=0; + virtual void Wait()=0; + virtual void Signal()=0; + virtual TInt Wait(TInt aTimeout); + virtual TInt Poll(); + }; + +TInt MLock::Wait(TInt) + { return KErrNotSupported; } +TInt MLock::Poll() + { return KErrNotSupported; } + +/*----------------------------------------------------------------------------*/ +class LockS : public MLock + { +public: + LockS(); + virtual TInt Flags(); + virtual void Release(); + virtual void Wait(); + virtual void Signal(); + virtual TInt Wait(TInt aTimeout); + virtual TInt Poll(); +public: + RSemaphore iT; + }; + +LockS::LockS() + { test_KErrNone(iT.CreateLocal(1)); } +TInt LockS::Flags() + { return EPollable|ETimeoutAvail; } +void LockS::Release() + { iT.Close(); } +void LockS::Wait() + { iT.Wait(); } +void LockS::Signal() + { iT.Signal(); } +TInt LockS::Wait(TInt aTimeout) + { return iT.Wait(aTimeout); } +TInt LockS::Poll() + { return iT.Poll(); } + +/*----------------------------------------------------------------------------*/ +class LockM : public MLock + { +public: + LockM(); + virtual TInt Flags(); + virtual void Release(); + virtual void Wait(); + virtual void Signal(); + virtual TInt Wait(TInt aTimeout); + virtual TInt Poll(); +public: + RMutex iT; + }; + +LockM::LockM() + { test_KErrNone(iT.CreateLocal()); } +TInt LockM::Flags() + { return EPollable|ETimeoutAvail|ENestable|ELimit1; } +void LockM::Release() + { iT.Close(); } +void LockM::Wait() + { iT.Wait(); } +void LockM::Signal() + { iT.Signal(); } +TInt LockM::Wait(TInt aTimeout) + { return iT.Wait(aTimeout); } +TInt LockM::Poll() + { return iT.Poll(); } + +/*----------------------------------------------------------------------------*/ + +class LockFL : public MLock + { +public: + LockFL(); + virtual TInt Flags(); + virtual void Release(); + virtual void Wait(); + virtual void Signal(); + virtual TInt Wait(TInt aTimeout); + virtual TInt Poll(); +public: + RFastLock iT; + }; + +LockFL::LockFL() + { test_KErrNone(iT.CreateLocal()); } +TInt LockFL::Flags() + { return ETimeoutAvail|EPollable|ELimit1|ELooseTimeout; } +void LockFL::Release() + { iT.Close(); } +void LockFL::Wait() + { iT.Wait(); } +void LockFL::Signal() + { iT.Signal(); } +TInt LockFL::Wait(TInt aTimeout) + { return iT.Wait(aTimeout); } +TInt LockFL::Poll() + { return iT.Poll(); } + +/*----------------------------------------------------------------------------*/ +class LockCS : public MLock + { +public: + LockCS(); + virtual TInt Flags(); + virtual void Release(); + virtual void Wait(); + virtual void Signal(); +public: + RCriticalSection iT; + }; + +LockCS::LockCS() + { test_KErrNone(iT.CreateLocal()); } +TInt LockCS::Flags() + { return ELimit1; } +void LockCS::Release() + { iT.Close(); } +void LockCS::Wait() + { iT.Wait(); } +void LockCS::Signal() + { iT.Signal(); } + + +/*----------------------------------------------------------------------------*/ +class LFSR + { +public: + LFSR(TInt aBits, TInt aTap2, TInt aTap3=0, TInt aTap4=0); + ~LFSR(); + void Step(); + void Step(TInt aSteps); + TBool operator==(const LFSR& a) const; +public: + TUint32* iData; + TInt iBits; + TInt iTap2; + TInt iTap3; + TInt iTap4; + TInt iNW; + TInt iSh1; + TInt iIx2; + TInt iSh2; + TInt iIx3; + TInt iSh3; + TInt iIx4; + TInt iSh4; + }; + +LFSR::LFSR(TInt aBits, TInt aTap2, TInt aTap3, TInt aTap4) + { + iBits = aBits; + iTap2 = aTap2; + iTap3 = aTap3; + iTap4 = aTap4; + iNW = (aBits + 31) >> 5; + iData = (TUint32*)User::AllocZ(iNW*sizeof(TUint32)); + test(iData!=0); + iData[0] = 1; + iSh1 = (aBits-1)&31; + iIx2 = (iTap2-1)>>5; + iSh2 = (iTap2-1)&31; + if (iTap3) + { + iIx3 = (iTap3-1)>>5; + iSh3 = (iTap3-1)&31; + } + else + { + iIx3 = -1; + iSh3 = 0; + } + if (iTap4) + { + iIx4 = (iTap4-1)>>5; + iSh4 = (iTap4-1)&31; + } + else + { + iIx4 = -1; + iSh4 = 0; + } + } + +LFSR::~LFSR() + { + User::Free(iData); + } + +void LFSR::Step(TInt aSteps) + { + while (aSteps--) + Step(); + } + +void LFSR::Step() + { + TUint32 b = iData[iNW-1]>>iSh1; + b ^= (iData[iIx2]>>iSh2); + if (iIx3>=0) + b ^= (iData[iIx3]>>iSh3); + if (iIx4>=0) + b ^= (iData[iIx4]>>iSh4); + b &= 1; + TInt i; + for (i=0; i> 31; + iData[i] = (iData[i]<<1)|b; + b = bb; + } + iData[iNW-1] &= ((2u< 1) + { + // when the mutex is singaled, due to priority balancing, the other + // thread will be scheduled to run on a CPU other than this one. The delay + // in getting that thread to run means that this one can manage to re-claim the + // mutex before the other thread gets to run. So we add a small delay here + User::After(100); + } + } while (running); return(KErrNone); } @@ -142,6 +494,7 @@ // Mutex test thread 2 // { + TInt n = NumCpus(); thread2Count=0; TBool running=ETrue; @@ -157,6 +510,17 @@ else running=EFalse; mutex.Signal(); + + if (n > 1) + { + // when the mutex is singaled, due to priority balancing, the other + // thread will be scheduled to run on a CPU other than this one. The delay + // in getting that thread to run means that this one can manage to re-claim the + // mutex before the other thread gets to run. So we add a small delay here + User::After(100); + } + + } while (running); return(KErrNone); } @@ -209,27 +573,80 @@ return(KErrNone); } -struct SWaitSem + +/*----------------------------------------------------------------------------*/ +struct SWaitLock { - RSemaphore iSem; + enum {EDummy=-2, EPoll=-1, EInfinite=0}; + + static TInt WaitLockThread(TAny*); + void Start(RThread& aT, TThreadPriority aP=EPriorityLess); + void Wait(RThread& aT, TInt aResult); + TInt DoTest2(RThread& aT, TInt aTimeout, TInt aResult, TThreadPriority aP=EPriorityLess); + void Test2(); + void TestSignalled(); + void TestNotSignalled(); + void TestState(); + + + MLock* iLock; TInt iTimeout; }; -TInt WaitSemThread(TAny* a) +TInt SWaitLock::WaitLockThread(TAny* a) { - SWaitSem& ws = *(SWaitSem*)a; - return ws.iSem.Wait(ws.iTimeout); + + if (doCpuLocking) + { + TInt r = LockCurrentThreadToCpu0(); + if (KErrNone!=r) return r; + // Rendevous was requested + RThread::Rendezvous(KErrNone); + } + + SWaitLock& w = *(SWaitLock*)a; + TInt lfl = w.iLock->Flags(); + TBool limit1 = lfl & MLock::ELimit1; + TInt r; + switch (w.iTimeout) + { + case EDummy: + return KErrNone; + case EPoll: + r = w.iLock->Poll(); + break; + case EInfinite: + w.iLock->Wait(); + r = KErrNone; + break; + default: + r = w.iLock->Wait(w.iTimeout); + break; + } + if (limit1 && r==KErrNone) + w.iLock->Signal(); + return r; } -void StartWaitSemThread(RThread& aT, SWaitSem& aW, TThreadPriority aP=EPriorityLess) +void SWaitLock::Start(RThread& aT, TThreadPriority aP) { - TInt r = aT.Create(KNullDesC, &WaitSemThread, 0x1000, 0x1000, 0x1000, &aW); + TRequestStatus st; + TInt r = aT.Create(KNullDesC, &WaitLockThread, 0x1000, 0x1000, 0x1000, this); test_KErrNone(r); aT.SetPriority(aP); + if (doCpuLocking) + { + aT.Rendezvous(st); + } aT.Resume(); + if (doCpuLocking) + { + User::WaitForRequest(st); + test_KErrNone(st.Int()); + } } -void WaitForWaitSemThread(RThread& aT, TInt aResult) +void SWaitLock::Wait(RThread& aT, TInt aResult) { TRequestStatus s; aT.Logon(s); @@ -240,32 +657,67 @@ CLOSE_AND_WAIT(aT); } -TInt DummyThread(TAny*) +TInt SWaitLock::DoTest2(RThread& aT, TInt aTimeout, TInt aResult, TThreadPriority aP) { - return 0; + TTime initial; + TTime final; + iTimeout = aTimeout; + initial.HomeTime(); + Start(aT, aP); + Wait(aT, aResult); + final.HomeTime(); + TInt elapsed = I64INT(final.Int64()-initial.Int64()); + return elapsed; + } + +void SWaitLock::TestSignalled() + { + TInt r = iLock->Poll(); + if (r == KErrNotSupported) + r = iLock->Wait(1); + test_KErrNone(r); } -void TestSemaphore2() +void SWaitLock::TestNotSignalled() + { + TInt r = iLock->Poll(); + if (r == KErrNotSupported) + r = iLock->Wait(1); + test_Equal(KErrTimedOut, r); + } + +void SWaitLock::TestState() { - test.Start(_L("Test semaphore wait with timeout")); - SWaitSem ws; + if (iLock->Flags() & MLock::ELimit1) + TestSignalled(); // not signalled afterwards + else + TestNotSignalled(); + } + +void SWaitLock::Test2() + { + test.Start(_L("SWaitLock::Test2")); RThread t; + RThread t2; TTime initial; TTime final; - TInt elapsed=0; - TInt r = ws.iSem.CreateLocal(0); - test_KErrNone(r); + TInt elapsed = 0; + TInt r = 0; + TInt lfl = iLock->Flags(); + TBool nestable = lfl & MLock::ENestable; + TBool limit1 = lfl & MLock::ELimit1; + TBool pollable = lfl & MLock::EPollable; + TBool to = lfl & MLock::ETimeoutAvail; + TBool lto = lfl & MLock::ELooseTimeout; RThread().SetPriority(EPriorityAbsoluteVeryLow); TInt threadcount=0; + iTimeout = EDummy; initial.HomeTime(); while (elapsed<1000000) { - r = t.Create(KNullDesC, &DummyThread, 0x1000, NULL, NULL); - test_KErrNone(r); - t.SetPriority(EPriorityMore); - t.Resume(); - t.Close(); + Start(t, EPriorityMore); + Wait(t, KErrNone); ++threadcount; final.HomeTime(); elapsed = I64INT(final.Int64()-initial.Int64()); @@ -275,125 +727,735 @@ TInt overhead = 1000000/threadcount; test.Printf(_L("overhead = %dus\n"),overhead); - ws.iTimeout=1000000; - initial.HomeTime(); - StartWaitSemThread(t, ws); - WaitForWaitSemThread(t, KErrTimedOut); - final.HomeTime(); - elapsed = I64INT(final.Int64()-initial.Int64()); - test.Printf(_L("Time taken = %dus\n"), elapsed); - test(elapsed>=900000+overhead && elapsed<1500000+overhead); + iLock->Wait(); - ws.iTimeout=-1; - initial.HomeTime(); - StartWaitSemThread(t, ws); - WaitForWaitSemThread(t, KErrArgument); - final.HomeTime(); - elapsed = I64INT(final.Int64()-initial.Int64()); - test.Printf(_L("Time taken = %dus\n"), elapsed); + if (to) + { + elapsed = DoTest2(t, 1000000, KErrTimedOut); + test.Printf(_L("Time taken = %dus\n"), elapsed); + test(elapsed>=900000+overhead && elapsed<1500000+overhead); + elapsed = DoTest2(t, -99, KErrArgument); + test.Printf(_L("Time taken = %dus\n"), elapsed); + } - ws.iTimeout=2000000; - initial.HomeTime(); - StartWaitSemThread(t, ws); - User::After(1000000); - ws.iSem.Signal(); - WaitForWaitSemThread(t, KErrNone); - final.HomeTime(); - elapsed = I64INT(final.Int64()-initial.Int64()); - test.Printf(_L("Time taken = %dus\n"), elapsed); - test(elapsed>=900000+overhead && elapsed<1500000+overhead); + if (pollable) + { + test.Printf(_L("Testing Poll() function\n")); + r = iLock->Poll(); + test_Equal((nestable ? KErrNone : KErrTimedOut), r); + if (nestable) + { + iTimeout=EPoll; + r = iLock->Poll(); + test_KErrNone(r); + iLock->Signal(); + Start(t, EPriorityMore); + Wait(t, KErrTimedOut); + } + iLock->Signal(); + if (nestable) + { + iTimeout=EPoll; + r = iLock->Poll(); + test_KErrNone(r); + iLock->Signal(); + Start(t, EPriorityMore); + Wait(t, KErrTimedOut); + iLock->Signal(); + Start(t, EPriorityMore); + Wait(t, KErrNone); + } + r = iLock->Poll(); + test_KErrNone(r); + if (!nestable) + { + r = iLock->Poll(); + test_Equal(KErrTimedOut, r); + iLock->Signal(); + if (!limit1) + { + iLock->Signal(); + r = iLock->Poll(); + test_KErrNone(r); + } + r = iLock->Poll(); + test_KErrNone(r); + r = iLock->Poll(); + test_Equal(KErrTimedOut, r); + } + elapsed = DoTest2(t, EPoll, KErrTimedOut); + test.Printf(_L("Time taken = %dus\n"), elapsed); + test(elapsed<=50000+3*overhead); + iLock->Signal(); + elapsed = DoTest2(t, EPoll, KErrNone); + test.Printf(_L("Time taken = %dus\n"), elapsed); + test(elapsed<=50000+3*overhead); + TestState(); + iLock->Signal(); + r = LockCurrentThreadToCpu0(ETrue); + test_KErrNone(r); + Start(t, EPriorityMuchMore); + Start(t2, EPriorityMore); + test_Equal(EExitKill, t2.ExitType()); + test_Equal(EExitKill, t.ExitType()); + Wait(t2, limit1 ? KErrNone : KErrTimedOut); + Wait(t, KErrNone); + r = UnlockCurrentThreadToCpu0(ETrue); + test_KErrNone(r); + TestState(); + } + else + { + test.Printf(_L("Poll() function not supported\n")); + } - ws.iTimeout=100000; - StartWaitSemThread(t, ws, EPriorityMore); - t.Suspend(); - ws.iSem.Signal(); - User::After(200000); - t.Resume(); - WaitForWaitSemThread(t, KErrTimedOut); - test_KErrNone(ws.iSem.Wait(1)); + if (to) + { + iTimeout=2000000; + initial.HomeTime(); + Start(t); + User::After(1000000); + iLock->Signal(); + Wait(t, KErrNone); + final.HomeTime(); + elapsed = I64INT(final.Int64()-initial.Int64()); + test.Printf(_L("Time taken = %dus\n"), elapsed); + test(elapsed>=900000+overhead && elapsed<1500000+overhead); + TestState(); - ws.iTimeout=100000; - StartWaitSemThread(t, ws, EPriorityMore); - t.Suspend(); - ws.iSem.Signal(); - User::After(50000); - t.Resume(); - WaitForWaitSemThread(t, KErrNone); - test_Equal(KErrTimedOut, ws.iSem.Wait(1)); + r = LockCurrentThreadToCpu0(ETrue); + test_KErrNone(r); - RThread t2; - ws.iTimeout=100000; - StartWaitSemThread(t, ws, EPriorityMuchMore); - StartWaitSemThread(t2, ws, EPriorityMore); - t.Suspend(); - ws.iSem.Signal(); - test_Equal(EExitKill, t2.ExitType()); - test_Equal(EExitPending, t.ExitType()); - t.Resume(); - WaitForWaitSemThread(t, KErrTimedOut); - WaitForWaitSemThread(t2, KErrNone); - test_Equal(KErrTimedOut, ws.iSem.Wait(1)); + if (!lto) + { + iTimeout=100000; + Start(t, EPriorityMore); + t.Suspend(); + iLock->Signal(); + User::After(200000); + t.Resume(); + Wait(t, KErrTimedOut); + TestSignalled(); - ws.iTimeout=1000000; - initial.HomeTime(); - StartWaitSemThread(t2, ws, EPriorityMore); - StartWaitSemThread(t, ws, EPriorityMuchMore); - ws.iSem.Signal(); - WaitForWaitSemThread(t, KErrNone); - final.HomeTime(); - elapsed = I64INT(final.Int64()-initial.Int64()); - test.Printf(_L("Time taken = %dus\n"), elapsed); - WaitForWaitSemThread(t2, KErrTimedOut); - final.HomeTime(); - elapsed = I64INT(final.Int64()-initial.Int64()); - test.Printf(_L("Time taken = %dus\n"), elapsed); - test(elapsed>=900000+2*overhead && elapsed<1500000+2*overhead); + iTimeout=100000; + Start(t, EPriorityMore); + t.Suspend(); + iLock->Signal(); + User::After(50000); + t.Resume(); + Wait(t, KErrNone); + TestState(); + + iTimeout=100000; + Start(t, EPriorityMuchMore); + Start(t2, EPriorityMore); + t.Suspend(); + iLock->Signal(); + test_Equal(EExitKill, t2.ExitType()); + test_Equal(EExitPending, t.ExitType()); + t.Resume(); + Wait(t, limit1 ? KErrNone : KErrTimedOut); + Wait(t2, KErrNone); + TestState(); + } - ws.iTimeout=1000000; - initial.HomeTime(); - StartWaitSemThread(t2, ws, EPriorityMore); - StartWaitSemThread(t, ws, EPriorityMuchMore); - WaitForWaitSemThread(t, KErrTimedOut); - final.HomeTime(); - elapsed = I64INT(final.Int64()-initial.Int64()); - test.Printf(_L("Time taken = %dus\n"), elapsed); - WaitForWaitSemThread(t2, KErrTimedOut); - final.HomeTime(); - elapsed = I64INT(final.Int64()-initial.Int64()); - test.Printf(_L("Time taken = %dus\n"), elapsed); - test(elapsed>=900000+2*overhead && elapsed<1500000+2*overhead); + iTimeout=1000000; + initial.HomeTime(); + Start(t2, EPriorityMore); + Start(t, EPriorityMuchMore); + iLock->Signal(); + Wait(t, KErrNone); + final.HomeTime(); + elapsed = I64INT(final.Int64()-initial.Int64()); + test.Printf(_L("Time taken = %dus\n"), elapsed); + Wait(t2, limit1 ? KErrNone : KErrTimedOut); + final.HomeTime(); + elapsed = I64INT(final.Int64()-initial.Int64()); + test.Printf(_L("Time taken = %dus\n"), elapsed); + if (!limit1) + { + test(elapsed>=900000+2*overhead && elapsed<1500000+2*overhead); + } + TestState(); + + iTimeout=1000000; + initial.HomeTime(); + Start(t2, EPriorityMore); + Start(t, EPriorityMuchMore); + Wait(t, KErrTimedOut); + final.HomeTime(); + elapsed = I64INT(final.Int64()-initial.Int64()); + test.Printf(_L("Time taken = %dus\n"), elapsed); + Wait(t2, KErrTimedOut); + final.HomeTime(); + elapsed = I64INT(final.Int64()-initial.Int64()); + test.Printf(_L("Time taken = %dus\n"), elapsed); + test(elapsed>=900000+2*overhead && elapsed<1500000+2*overhead); - ws.iTimeout=1000000; - initial.HomeTime(); - StartWaitSemThread(t2, ws, EPriorityMore); - StartWaitSemThread(t, ws, EPriorityMuchMore); - t.Kill(299792458); - WaitForWaitSemThread(t2, KErrTimedOut); - WaitForWaitSemThread(t, 299792458); - final.HomeTime(); - elapsed = I64INT(final.Int64()-initial.Int64()); - test.Printf(_L("Time taken = %dus\n"), elapsed); - test(elapsed>=900000+2*overhead && elapsed<1500000+2*overhead); + iTimeout=1000000; + initial.HomeTime(); + Start(t2, EPriorityMore); + Start(t, EPriorityMuchMore); + t.Kill(299792458); + Wait(t2, KErrTimedOut); + Wait(t, 299792458); + final.HomeTime(); + elapsed = I64INT(final.Int64()-initial.Int64()); + test.Printf(_L("Time taken = %dus\n"), elapsed); + test(elapsed>=900000+2*overhead && elapsed<1500000+2*overhead); - ws.iTimeout=1000000; - initial.HomeTime(); - StartWaitSemThread(t, ws, EPriorityMore); - StartWaitSemThread(t2, ws, EPriorityMuchMore); - test_Equal(EExitPending, t.ExitType()); - test_Equal(EExitPending, t2.ExitType()); - ws.iSem.Close(); - test_Equal(EExitKill, t.ExitType()); - test_Equal(EExitKill, t2.ExitType()); - WaitForWaitSemThread(t2, KErrGeneral); - WaitForWaitSemThread(t, KErrGeneral); - final.HomeTime(); - elapsed = I64INT(final.Int64()-initial.Int64()); - test.Printf(_L("Time taken = %dus\n"), elapsed); - test(elapsed<=50000+3*overhead); - + iTimeout=1000000; + initial.HomeTime(); + Start(t, EPriorityMore); + Start(t2, EPriorityMuchMore); + test_Equal(EExitPending, t.ExitType()); + test_Equal(EExitPending, t2.ExitType()); + iLock->Release(); + test_Equal(EExitKill, t.ExitType()); + test_Equal(EExitKill, t2.ExitType()); + Wait(t2, KErrGeneral); + Wait(t, KErrGeneral); + final.HomeTime(); + elapsed = I64INT(final.Int64()-initial.Int64()); + test.Printf(_L("Time taken = %dus\n"), elapsed); + test(elapsed<=50000+3*overhead); + r = UnlockCurrentThreadToCpu0(ETrue); + test_KErrNone(r); + } + else + { + test.Printf(_L("Timed waits not supported\n")); + iLock->Release(); + } test.End(); } +volatile TBool NoRepeat = EFalse; +void TestPollTimeout() + { + SWaitLock w; + do { + test.Printf(_L("TestPollTimeout - RSemaphore\n")); + LockS ls; + w.iLock = &ls; + w.Test2(); // Release()s ls + } while(NoRepeat); + do { + test.Printf(_L("TestPollTimeout - RMutex\n")); + LockM lm; + w.iLock = &lm; + w.Test2(); // Release()s lm + } while(NoRepeat); + do { + test.Printf(_L("TestPollTimeout - RFastLock\n")); + LockFL fl; + w.iLock = &fl; + w.Test2(); // Release()s fl + } while(NoRepeat); + } + + +/*----------------------------------------------------------------------------*/ +class CMXThreadGrp; + +struct SStats + { + SStats(); + void Add(TInt aValue); + void Add(const SStats& aS); + TInt Count() const {return iN;} + TInt Min() const; + TInt Max() const; + TInt Mean() const; + + TInt64 iSum; + TInt iMin; + TInt iMax; + TInt iN; + TInt iSp; + }; + +SStats::SStats() + { + iSum = 0; + iMax = KMinTInt; + iMin = ~iMax; + iN = 0; + iSp = 0; + } + +void SStats::Add(TInt aValue) + { + TInt64 v = aValue; + iSum += v; + ++iN; + if (aValue > iMax) + iMax = aValue; + if (aValue < iMin) + iMin = aValue; + } + +void SStats::Add(const SStats& a) + { + iN += a.iN; + iSum += a.iSum; + if (a.iMax > iMax) + iMax = a.iMax; + if (a.iMin < iMin) + iMin = a.iMin; + } + +TInt SStats::Min() const + {return iN ? iMin : 0;} + +TInt SStats::Max() const + {return iN ? iMax : 0;} + +TInt SStats::Mean() const + { + if (iN==0) + return 0; + return (TInt)(iSum/TInt64(iN)); + } + +TUint32 ticks_to_us(TUint32 aTicks, TUint32 aF) + { + TUint64 x = aTicks; + TUint64 f = aF; + x *= TUint64(1000000); + x += (f>>1); + x /= f; + return I64LOW(x); + } + +class CMXThread : public CBase + { +private: + CMXThread(); + ~CMXThread(); + static CMXThread* New(CMXThreadGrp* aG, TUint32 aId, TUint32 aL, TUint32 aD); + void Start(); + void Wait(); + TInt Construct(CMXThreadGrp* aG, TUint32 aId, TUint32 aL, TUint32 aD); + TInt Steps(); + TInt Action(); + TInt Run(); + static TInt ThreadFunc(TAny*); + void PrintStats(); +private: + TUint64 iSeed; + RThread iThread; + TRequestStatus iExitStatus; + CMXThreadGrp* iG; + LFSR* iDummyLfsr; + TUint32 iId; + TUint32 iLambda; + TUint32 iDummySteps; + TInt iTotalSteps; + TInt iIterations; + TInt iPolls; + TInt iPollFails; + SStats iStats; + SStats iTimeoutStats; +private: + friend class CMXThreadGrp; + }; + +class CMXThreadGrp : public CBase + { +public: + static CMXThreadGrp* New(MLock* aLock, TInt aNThreads, TUint32 aLambda, TUint32 aDummySteps, TUint32 aTime); + CMXThreadGrp(); + ~CMXThreadGrp(); + TBool Run(); + void PrintStats(); +private: + TInt Construct(MLock* aLock, TInt aNThreads, TUint32 aLambda, TUint32 aDummySteps, TUint32 aTime); +private: + TInt iNThreads; + CMXThread** iThreads; + MLock* iLock; + LFSR* iLfsr; + LFSR* iLfsr0; + TUint32 iNTickPeriod; + TUint32 iFCF; + TUint32 iNTicks; + TInt iTotalSteps; + TInt iIterations; + TInt iPolls; + TInt iPollFails; + SStats iStats; + SStats iTimeoutStats; +private: + friend class CMXThread; + }; + +CMXThread::CMXThread() + { + iThread.SetHandle(0); + } + +CMXThread::~CMXThread() + { + delete iDummyLfsr; + if (iThread.Handle()) + { + if (iThread.ExitType() == EExitPending) + { + iThread.Kill(0); + Wait(); + } + CLOSE_AND_WAIT(iThread); + } + } + +void CMXThread::PrintStats() + { + test.Printf(_L("Thread %d:\n"), iId); + test.Printf(_L(" ST:%10d IT:%10d P:%10d PF:%10d TO:%10d\n"), iTotalSteps, iIterations, iPolls, iPollFails, iTimeoutStats.Count()); + TUint32 min, max, mean; + min = ticks_to_us(iStats.Min(), iG->iFCF); + max = ticks_to_us(iStats.Max(), iG->iFCF); + mean = ticks_to_us(iStats.Mean(), iG->iFCF); + test.Printf(_L(" Lock acquire times MIN %10d MAX %10d AVG %10d\n"), min, max, mean); + min = ticks_to_us(iTimeoutStats.Min(), iG->iFCF); + max = ticks_to_us(iTimeoutStats.Max(), iG->iFCF); + mean = ticks_to_us(iTimeoutStats.Mean(), iG->iFCF); + test.Printf(_L(" Lock timeout times MIN %10d MAX %10d AVG %10d\n"), min, max, mean); + } + +TInt CMXThread::Construct(CMXThreadGrp* aG, TUint32 aId, TUint32 aL, TUint32 aD) + { + iG = aG; + iId = aId; + iLambda = aL; + iDummySteps = aD; + iSeed = iId + 1; + iDummyLfsr = new LFSR(785,693); + if (!iDummyLfsr) + return KErrNoMemory; + TBuf<16> name = _L("TSThrd"); + name.AppendNum(iId); + TInt r = iThread.Create(name, &ThreadFunc, 0x1000, NULL, this); + if (r!=KErrNone) + return r; + iThread.Logon(iExitStatus); + if (iExitStatus != KRequestPending) + { + iThread.Kill(0); + iThread.Close(); + iThread.SetHandle(0); + return iExitStatus.Int(); + } + iThread.SetPriority(EPriorityLess); + return KErrNone; + } + +CMXThread* CMXThread::New(CMXThreadGrp* aG, TUint32 aId, TUint32 aL, TUint32 aD) + { + CMXThread* p = new CMXThread; + if (p) + { + TInt r = p->Construct(aG, aId, aL, aD); + if (r != KErrNone) + { + delete p; + p = 0; + } + } + return p; + } + +void CMXThread::Start() + { + iThread.Resume(); + } + +void CMXThread::Wait() + { + User::WaitForRequest(iExitStatus); + } + +TInt CMXThread::ThreadFunc(TAny* aPtr) + { + CMXThread& a = *(CMXThread*)aPtr; + return a.Run(); + } + +TInt CMXThread::Steps() + { + Random(iSeed); + return ExpRV(iSeed, iLambda, 1); + } + +TInt CMXThread::Action() + { + Random(iSeed); + return I64LOW(iSeed)%3; + } + +TInt CMXThread::Run() + { + MLock* lock = iG->iLock; + LFSR* lfsr = iG->iLfsr; + TInt lfl = lock->Flags(); + TBool pollable = lfl & MLock::EPollable; + TBool to = lfl & MLock::ETimeoutAvail; + TUint32 start_time = User::NTickCount(); + TInt r; + + FOREVER + { + TUint32 now = User::NTickCount(); + if (now - start_time >= iG->iNTicks) + break; + ++iIterations; + iDummyLfsr->Step(iDummySteps); + TInt action = Action(); + TInt steps = Steps(); + TUint32 initial = User::FastCounter(); + if (action==2 && to) + { + r = lock->Wait(1000); + if (r!=KErrNone) + { + TUint32 final = User::FastCounter(); + TInt elapsed = TInt(final - initial); + iTimeoutStats.Add(elapsed); + } + } + else if (action==1 && pollable) + { + ++iPolls; + r = lock->Poll(); + if (r!=KErrNone) + ++iPollFails; + } + else + { + lock->Wait(); + r = KErrNone; + } + if (r == KErrNone) + { + TUint32 final = User::FastCounter(); + lfsr->Step(steps); + lock->Signal(); + TInt elapsed = TInt(final - initial); + iTotalSteps += steps; + iStats.Add(elapsed); + } + } + + return KErrNone; + } + +CMXThreadGrp* CMXThreadGrp::New(MLock* aLock, TInt aNThreads, TUint32 aLambda, TUint32 aDummySteps, TUint32 aTime) + { + CMXThreadGrp* p = new CMXThreadGrp; + if (p) + { + TInt r = p->Construct(aLock, aNThreads, aLambda, aDummySteps, aTime); + if (r != KErrNone) + { + delete p; + p = 0; + } + } + return p; + } + +CMXThreadGrp::CMXThreadGrp() + { + } + +TInt CMXThreadGrp::Construct(MLock* aLock, TInt aNThreads, TUint32 aLambda, TUint32 aDummySteps, TUint32 aTime) + { + iNThreads = aNThreads; + iLock = aLock; + TInt r = HAL::Get(HAL::EFastCounterFrequency, (TInt&)iFCF); + if (r!=KErrNone) + return r; + r = HAL::Get(HAL::ENanoTickPeriod, (TInt&)iNTickPeriod); + if (r!=KErrNone) + return r; + iNTicks = (aTime+iNTickPeriod-1)/iNTickPeriod; + iLfsr = new LFSR(785,693); + iLfsr0 = new LFSR(785,693); + if (!iLfsr || !iLfsr0) + return KErrNoMemory; + iThreads = (CMXThread**)User::AllocZ(iNThreads*sizeof(CMXThread*)); + if (!iThreads) + return KErrNoMemory; + TInt i; + for (i=0; iiLambda, iThreads[0]->iDummySteps, iNTicks); + for (i=0; iStart(); + for (i=0; iWait(); + for (i=0; iiTotalSteps; + iIterations += iThreads[i]->iIterations; + iPolls += iThreads[i]->iPolls; + iPollFails += iThreads[i]->iPollFails; + iStats.Add(iThreads[i]->iStats); + iTimeoutStats.Add(iThreads[i]->iTimeoutStats); + } + test.Printf(_L("Total LFSR steps %d\n"), iTotalSteps); + iLfsr0->Step(iTotalSteps); + TBool ok = (*iLfsr == *iLfsr0); + return ok; + } + +void CMXThreadGrp::PrintStats() + { + TInt i; + for (i=0; iPrintStats(); + } + test.Printf(_L("TOTALS:\n")); + test.Printf(_L(" ST:%10d IT:%10d P:%10d PF:%10d TO:%10d\n"), iTotalSteps, iIterations, iPolls, iPollFails, iTimeoutStats.Count()); + TUint32 min, max, mean; + min = ticks_to_us(iStats.Min(), iFCF); + max = ticks_to_us(iStats.Max(), iFCF); + mean = ticks_to_us(iStats.Mean(), iFCF); + test.Printf(_L(" Lock acquire times MIN %10d MAX %10d AVG %10d\n"), min, max, mean); + min = ticks_to_us(iTimeoutStats.Min(), iFCF); + max = ticks_to_us(iTimeoutStats.Max(), iFCF); + mean = ticks_to_us(iTimeoutStats.Mean(), iFCF); + test.Printf(_L(" Lock timeout times MIN %10d MAX %10d AVG %10d\n"), min, max, mean); + } + +TUint32 Calibrate() + { + TUint32 fcf; + TInt r = HAL::Get(HAL::EFastCounterFrequency, (TInt&)fcf); + test_KErrNone(r); + LFSR* d = new LFSR(785,693); + test(d!=0); + TInt steps = 2; + TUint32 ticks = fcf/10; + TUint32 elapsed; + FOREVER + { + TUint32 h0 = User::FastCounter(); + d->Step(steps); + TUint32 h1 = User::FastCounter(); + elapsed = h1 - h0; + if (elapsed > ticks) + break; + steps *= 2; + } + delete d; + test.Printf(_L("%d steps in %d fast ticks\n"), steps, elapsed); + TUint64 x = elapsed; + TUint64 s = steps; + TUint64 y = fcf; + y /= x; + s *= y; // steps per second + TUint32 res = I64LOW(s); + test.Printf(_L("%d steps per second\n"), res); + return res; + } + +void DoTMX(MLock* aLock, TInt aNThreads, TUint32 aLambda, TUint32 aDummySteps, TUint32 aTime, TBool aShouldFail=EFalse) + { + CMXThreadGrp* g = CMXThreadGrp::New(aLock, aNThreads, aLambda, aDummySteps, aTime); + test(g!=0); + TBool ok = g->Run(); + if (aShouldFail) + { + test(!ok); + } + else + { + test(ok); + } + g->PrintStats(); + delete g; + } + +void DoTMX(MLock* aLock, TUint32 aLambda, TUint32 aDummySteps, TUint32 aTime) + { + TInt n; + for (n=1; n<=4; ++n) + { + TUint32 l = (n<2) ? aLambda : (aLambda/(n-1)); + DoTMX(aLock, n, l, aDummySteps, aTime); + } + aLock->Release(); + } + + +void TestMutualExclusion() + { + TInt ntp; + TInt r = HAL::Get(HAL::ENanoTickPeriod, ntp); + test_KErrNone(r); + test.Printf(_L("Nanokernel tick period = %dus\n"), ntp); + TUint32 sps = Calibrate(); + TUint32 lambda = sps/2000; + TUint32 dummy = sps/2000; + TUint32 time = 5000000; + do { + test.Printf(_L("TestMutualExclusion - RSemaphore\n")); + LockS ls; + DoTMX(&ls, lambda, dummy, time); + } while(NoRepeat); + do { + test.Printf(_L("TestMutualExclusion - RSemaphore init=2\n")); + LockS ls2; + ls2.Signal(); // count=2 + DoTMX(&ls2, 4, lambda, dummy, time, ETrue); + } while(NoRepeat); + do { + test.Printf(_L("TestMutualExclusion - RMutex\n")); + LockM lm; + DoTMX(&lm, lambda, dummy, time); + } while(NoRepeat); + do { + test.Printf(_L("TestMutualExclusion - RFastLock\n")); + LockFL fl; + DoTMX(&fl, lambda, dummy, time); + } while(NoRepeat); + do { + test.Printf(_L("TestMutualExclusion - RCriticalSection\n")); + LockCS cs; + DoTMX(&cs, lambda, dummy, time); + } while(NoRepeat); + } + + + + +/*----------------------------------------------------------------------------*/ void TestSemaphore() { /*********** TO DO ************/ @@ -417,23 +1479,23 @@ test.Next(_L("Producer/Consumer scenario")); // Test Rsemaphore with the producer/consumer scenario RThread thread1, thread2; TRequestStatus stat1, stat2; - test_KErrNone(mutex.CreateLocal()); - test_KErrNone(slotAvailable.CreateLocal(KMaxBufferSize)); - test_KErrNone(itemAvailable.CreateLocal(0)); - test_KErrNone(thread1.Create(_L("Thread1"),Producer,KDefaultStackSize,0x200,0x200,NULL)); - test_KErrNone(thread2.Create(_L("Thread2"),Consumer,KDefaultStackSize,0x200,0x200,NULL)); + test(mutex.CreateLocal()==KErrNone); + test(slotAvailable.CreateLocal(KMaxBufferSize)==KErrNone); + test(itemAvailable.CreateLocal(0)==KErrNone); + test(thread1.Create(_L("Thread1"),Producer,KDefaultStackSize,0x200,0x200,NULL)==KErrNone); + test(thread2.Create(_L("Thread2"),Consumer,KDefaultStackSize,0x200,0x200,NULL)==KErrNone); thread1.Logon(stat1); thread2.Logon(stat2); - test_Equal(KRequestPending, stat1.Int()); - test_Equal(KRequestPending, stat2.Int()); + test(stat1==KRequestPending); + test(stat2==KRequestPending); thread1.Resume(); thread2.Resume(); User::WaitForRequest(stat1); User::WaitForRequest(stat2); - test_KErrNone(stat1.Int()); - test_KErrNone(stat2.Int()); + test(stat1==KErrNone); + test(stat2==KErrNone); for(TInt jj=0;jj>1), thread1Count); + test.Printf(_L("T1 %d T1ACT %d T2 %d T2ACT %d\n"),thread1Count,thread1ActualCount,thread2Count,thread2ActualCount); + test(thread1ActualCount==thread1Count); + test(thread2ActualCount==thread2Count); + test(thread1Count==thread2Count); + test(thread1Count==(KMaxArraySize>>1)); test.Next(_L("Close")); CLOSE_AND_WAIT(thread1); @@ -524,7 +1586,7 @@ { test.Start(_L("Create")); - test_KErrNone(criticalSn.CreateLocal()); + test(criticalSn.CreateLocal()==KErrNone); /***************** TO DO *********************** @@ -553,20 +1615,21 @@ // threads think. // arrayIndex=0; + RThread thread1,thread2; - test_KErrNone(thread1.Create(_L("Thread1"),CriticalSnThreadEntryPoint1,KDefaultStackSize,0x2000,0x2000,NULL)); - test_KErrNone(thread2.Create(_L("Thread2"),CriticalSnThreadEntryPoint2,KDefaultStackSize,0x2000,0x2000,NULL)); + test(thread1.Create(_L("Thread1"),CriticalSnThreadEntryPoint1,KDefaultStackSize,0x2000,0x2000,NULL)==KErrNone); + test(thread2.Create(_L("Thread2"),CriticalSnThreadEntryPoint2,KDefaultStackSize,0x2000,0x2000,NULL)==KErrNone); TRequestStatus stat1,stat2; thread1.Logon(stat1); thread2.Logon(stat2); - test_Equal(KRequestPending, stat1.Int()); - test_Equal(KRequestPending, stat2.Int()); + test(stat1==KRequestPending); + test(stat2==KRequestPending); thread1.Resume(); thread2.Resume(); User::WaitForRequest(stat1); User::WaitForRequest(stat2); - test_KErrNone(stat1.Int()); - test_KErrNone(stat2.Int()); + test(stat1==KErrNone); + test(stat2==KErrNone); TInt thread1ActualCount=0; TInt thread2ActualCount=0; TInt ii=0; @@ -578,10 +1641,10 @@ thread2ActualCount++; ii++; } - test_Equal(thread1Count, thread1ActualCount); - test_Equal(thread2Count, thread2ActualCount); - test_Equal(thread2Count, thread1Count); - test_Equal((KMaxArraySize>>1), thread1Count); + test(thread1ActualCount==thread1Count); + test(thread2ActualCount==thread2Count); + test(thread1Count==thread2Count); + test(thread1Count==(KMaxArraySize>>1)); test.Next(_L("Close")); CLOSE_AND_WAIT(thread1); @@ -593,22 +1656,13 @@ GLDEF_C TInt E32Main() { - TInt cpus = UserSvr::HalFunction(EHalGroupKernel, EKernelHalNumLogicalCpus, 0, 0); - if (cpus != 1) - { - test(cpus>1); - // This test will require compatibility mode (and probably other changes) - // to work on SMP - it depends on explicit scheduling order. - test.Printf(_L("T_SEMUTX skipped, does not work on SMP\n")); - return KErrNone; - } - test.Title(); __UHEAP_MARK; + TestMutualExclusion(); + TestPollTimeout(); test.Start(_L("Test RSemaphore")); TestSemaphore(); - TestSemaphore2(); test.Next(_L("Test RMutex")); TestMutex(); TestMutex2();