sl@0: // Copyright (c) 1995-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of the License "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // e32test\misc\t_condvar2.cpp sl@0: // sl@0: // sl@0: sl@0: #define __E32TEST_EXTENSION__ sl@0: sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include "u32std.h" sl@0: #include "../misc/prbs.h" sl@0: #include "../mmu/freeram.h" sl@0: sl@0: const TInt KStackSize=0x1000; sl@0: sl@0: RTest test(_L("T_CONDVAR2")); sl@0: sl@0: const TInt KPacketSize = 1024; sl@0: const TInt KCrcSize = KPacketSize; sl@0: struct SMessage sl@0: { sl@0: TDblQueLink iLink; sl@0: TUint iSeq; sl@0: TUint iData[KPacketSize/4]; sl@0: TUint iCrc; sl@0: }; sl@0: sl@0: TDblQue Queue(0); sl@0: TUint PSeq; sl@0: TUint CSeq; sl@0: RHeap* SharedHeap; sl@0: RMutex Mutex; sl@0: RCondVar CV; sl@0: TInt NThreads; sl@0: sl@0: class CThread : public CActive sl@0: { sl@0: public: sl@0: CThread(TInt aPriority); sl@0: ~CThread(); sl@0: virtual void RunL(); sl@0: virtual void DoCancel(); sl@0: virtual void DisplayStats()=0; sl@0: TInt Start(); sl@0: public: sl@0: static TInt ThreadFunc(TAny* aPtr); sl@0: public: sl@0: virtual TInt StartThread()=0; sl@0: virtual TInt RunThread()=0; sl@0: public: sl@0: RThread iThread; sl@0: TInt iInnerCount; sl@0: TInt iOuterCount; sl@0: TInt iSuspendCount; sl@0: TInt iExitCount; sl@0: TInt iTerminateCount; sl@0: TInt iCvCloseCount; sl@0: TBool iProducer; sl@0: TInt iId; sl@0: TBool iCritical; sl@0: TAny* iTempAlloc; sl@0: }; sl@0: sl@0: class CProducerThread : public CThread sl@0: { sl@0: public: sl@0: static void NewL(TInt aId); sl@0: CProducerThread(TInt aId); sl@0: virtual TInt StartThread(); sl@0: virtual TInt RunThread(); sl@0: virtual void DisplayStats(); sl@0: }; sl@0: sl@0: class CConsumerThread : public CThread sl@0: { sl@0: public: sl@0: static void NewL(TInt aId); sl@0: CConsumerThread(TInt aId); sl@0: virtual TInt StartThread(); sl@0: virtual TInt RunThread(); sl@0: virtual void DisplayStats(); sl@0: }; sl@0: sl@0: class CRandomTimer : public CActive sl@0: { sl@0: public: sl@0: static void NewL(); sl@0: CRandomTimer(TInt aPriority); sl@0: ~CRandomTimer(); sl@0: virtual void RunL(); sl@0: virtual void DoCancel(); sl@0: void Start(); sl@0: public: sl@0: RTimer iTimer; sl@0: TUint iSeed[2]; sl@0: TInt iCount; sl@0: TInt iBackOff; sl@0: TInt iZeroHandle; sl@0: CThread* iSuspended; sl@0: }; sl@0: sl@0: class CStatsTimer : public CActive sl@0: { sl@0: public: sl@0: static void NewL(); sl@0: CStatsTimer(TInt aPriority); sl@0: ~CStatsTimer(); sl@0: virtual void RunL(); sl@0: virtual void DoCancel(); sl@0: void Start(); sl@0: public: sl@0: RTimer iTimer; sl@0: TInt iInitFreeRam; sl@0: TInt iMaxDelta; sl@0: TInt iCount; sl@0: }; sl@0: sl@0: const TInt KNumProducers=4; sl@0: CProducerThread* TheProducers[KNumProducers]; sl@0: const TInt KNumConsumers=4; sl@0: CConsumerThread* TheConsumers[KNumConsumers]; sl@0: CRandomTimer* TheRandomTimer; sl@0: sl@0: CThread::CThread(TInt aPriority) sl@0: : CActive(aPriority) sl@0: { sl@0: } sl@0: sl@0: CThread::~CThread() sl@0: { sl@0: Cancel(); sl@0: iThread.Kill(0); sl@0: iThread.Close(); sl@0: } sl@0: sl@0: TInt StartAllThreads() sl@0: { sl@0: TInt i; sl@0: TInt r = CV.CreateLocal(); sl@0: if (r!=KErrNone) sl@0: return r; sl@0: for (i=0; iStart(); sl@0: if (r!=KErrNone) sl@0: return r; sl@0: } sl@0: for (i=0; iStart(); sl@0: if (r!=KErrNone) sl@0: return r; sl@0: } sl@0: return KErrNone; sl@0: } sl@0: sl@0: void CThread::RunL() sl@0: { sl@0: TExitType exitType = iThread.ExitType(); sl@0: TInt exitReason = iThread.ExitReason(); sl@0: const TDesC& exitCat = iThread.ExitCategory(); sl@0: TBool bad=EFalse; sl@0: if (exitType==EExitKill) sl@0: { sl@0: if (exitReason!=KErrNone && exitReason!=KErrGeneral) sl@0: bad=ETrue; sl@0: } sl@0: else if (exitType==EExitPanic) sl@0: { sl@0: if (exitCat!=_L("KERN-EXEC") || exitReason!=0 || CV.Handle()!=0) sl@0: bad=ETrue; sl@0: else sl@0: ++iCvCloseCount; sl@0: } sl@0: if (bad) sl@0: { sl@0: TFullName n(iThread.FullName()); sl@0: if (iProducer) sl@0: test.Printf(_L("Thread %S (P%1d) exited %d,%d,%S\n"),&n,iId,exitType,exitReason,&exitCat); sl@0: else sl@0: test.Printf(_L("Thread %S (C%1d) exited %d,%d,%S\n"),&n,iId,exitType,exitReason,&exitCat); sl@0: CActiveScheduler::Stop(); sl@0: return; sl@0: } sl@0: CLOSE_AND_WAIT(iThread); sl@0: if (exitType==EExitTerminate) sl@0: ++iTerminateCount; sl@0: else if (exitType==EExitKill && exitReason==KErrNone) sl@0: ++iExitCount; sl@0: else if (exitType==EExitKill && exitReason==KErrGeneral) sl@0: ++iCvCloseCount; sl@0: --NThreads; sl@0: if (iTempAlloc) sl@0: { sl@0: SharedHeap->Free(iTempAlloc); sl@0: iTempAlloc = NULL; sl@0: } sl@0: TInt r; sl@0: if (CV.Handle()==0) sl@0: { sl@0: if (NThreads==0) sl@0: r = StartAllThreads(); sl@0: else sl@0: return; sl@0: } sl@0: else sl@0: r=Start(); sl@0: if (r!=KErrNone) sl@0: { sl@0: test.Printf(_L("Start thread error %d\n"),r); sl@0: CActiveScheduler::Stop(); sl@0: } sl@0: } sl@0: sl@0: void CThread::DoCancel() sl@0: { sl@0: iThread.LogonCancel(iStatus); sl@0: } sl@0: sl@0: TInt CThread::Start() sl@0: { sl@0: TInt r; sl@0: FOREVER sl@0: { sl@0: r=StartThread(); sl@0: if (r==KErrNone) sl@0: break; sl@0: if (r!=KErrAlreadyExists) sl@0: break; sl@0: User::After(100000); sl@0: } sl@0: if (r==KErrNone) sl@0: { sl@0: iThread.Logon(iStatus); sl@0: SetActive(); sl@0: } sl@0: ++NThreads; sl@0: return r; sl@0: } sl@0: sl@0: TInt CThread::ThreadFunc(TAny* aPtr) sl@0: { sl@0: return ((CThread*)aPtr)->RunThread(); sl@0: } sl@0: sl@0: CConsumerThread::CConsumerThread(TInt aId) sl@0: : CThread(0) sl@0: { sl@0: iId = aId; sl@0: } sl@0: sl@0: void CConsumerThread::NewL(TInt aId) sl@0: { sl@0: CConsumerThread* pT=new (ELeave) CConsumerThread(aId); sl@0: TheConsumers[aId] = pT; sl@0: CActiveScheduler::Add(pT); sl@0: User::LeaveIfError(pT->Start()); sl@0: } sl@0: sl@0: TInt CConsumerThread::StartThread() sl@0: { sl@0: TInt r=iThread.Create(KNullDesC(), &ThreadFunc, KStackSize, SharedHeap, this); // use unnamed thread sl@0: if (r!=KErrNone) sl@0: return r; sl@0: iThread.Resume(); sl@0: return KErrNone; sl@0: } sl@0: sl@0: void CConsumerThread::DisplayStats() sl@0: { sl@0: test.Printf(_L("C%1d: I:%9d O:%9d S:%9d T:%9d C:%9d\n"), iId, iInnerCount, iOuterCount, iSuspendCount, iTerminateCount, iCvCloseCount); sl@0: } sl@0: sl@0: TInt CConsumerThread::RunThread() sl@0: { sl@0: Mutex.Wait(); sl@0: TInt r = KErrNone; sl@0: FOREVER sl@0: { sl@0: while (Queue.IsEmpty()) sl@0: { sl@0: r = CV.Wait(Mutex); sl@0: ++iInnerCount; sl@0: if (r!=KErrNone) sl@0: return r; sl@0: } sl@0: ++iOuterCount; sl@0: iCritical = ETrue; sl@0: SMessage* m = Queue.First(); sl@0: m->iLink.Deque(); sl@0: iTempAlloc = m; sl@0: TBool seq_ok = (m->iSeq == CSeq++); sl@0: iCritical = EFalse; sl@0: Mutex.Signal(); sl@0: if (!seq_ok) sl@0: return KErrCorrupt; sl@0: TUint16 crc = 0; sl@0: Mem::Crc(crc, m->iData, KCrcSize); sl@0: if (crc != m->iCrc) sl@0: return KErrCorrupt; sl@0: iCritical = ETrue; sl@0: iTempAlloc = NULL; sl@0: User::Free(m); sl@0: iCritical = EFalse; sl@0: Mutex.Wait(); sl@0: } sl@0: } sl@0: sl@0: CProducerThread::CProducerThread(TInt aId) sl@0: : CThread(0) sl@0: { sl@0: iId = aId; sl@0: } sl@0: sl@0: void CProducerThread::NewL(TInt aId) sl@0: { sl@0: CProducerThread* pT=new (ELeave) CProducerThread(aId); sl@0: TheProducers[aId] = pT; sl@0: CActiveScheduler::Add(pT); sl@0: User::LeaveIfError(pT->Start()); sl@0: } sl@0: sl@0: TInt CProducerThread::StartThread() sl@0: { sl@0: TInt r=iThread.Create(KNullDesC(), &ThreadFunc, KStackSize, SharedHeap, this); // use unnamed thread sl@0: if (r!=KErrNone) sl@0: return r; sl@0: iThread.Resume(); sl@0: return KErrNone; sl@0: } sl@0: sl@0: void CProducerThread::DisplayStats() sl@0: { sl@0: test.Printf(_L("P%1d: I:%9d O:%9d S:%9d T:%9d C:%9d\n"), iId, iInnerCount, iOuterCount, iSuspendCount, iTerminateCount, iCvCloseCount); sl@0: } sl@0: sl@0: TInt CProducerThread::RunThread() sl@0: { sl@0: TUint seed[2]; sl@0: seed[0] = User::TickCount(); sl@0: seed[1] = 0; sl@0: FOREVER sl@0: { sl@0: iCritical = ETrue; sl@0: SMessage* m = new SMessage; sl@0: iTempAlloc = m; sl@0: iCritical = EFalse; sl@0: TInt i = 0; sl@0: for (; iiData[i] = Random(seed); sl@0: TUint16 crc = 0; sl@0: Mem::Crc(crc, m->iData, KCrcSize); sl@0: m->iCrc = crc; sl@0: Mutex.Wait(); sl@0: iCritical = ETrue; sl@0: m->iSeq = PSeq++; sl@0: Queue.AddLast(*m); sl@0: iTempAlloc = NULL; sl@0: iCritical = EFalse; sl@0: CV.Signal(); sl@0: Mutex.Signal(); sl@0: ++iOuterCount; sl@0: if (!(Random(seed)&1)) sl@0: User::AfterHighRes(1000); sl@0: } sl@0: } sl@0: sl@0: void CRandomTimer::NewL() sl@0: { sl@0: CRandomTimer* pR=new (ELeave) CRandomTimer(20); sl@0: User::LeaveIfError(pR->iTimer.CreateLocal()); sl@0: CActiveScheduler::Add(pR); sl@0: TheRandomTimer=pR; sl@0: pR->Start(); sl@0: } sl@0: sl@0: CRandomTimer::CRandomTimer(TInt aPriority) sl@0: : CActive(aPriority) sl@0: { sl@0: iSeed[0]=User::TickCount(); sl@0: } sl@0: sl@0: CRandomTimer::~CRandomTimer() sl@0: { sl@0: Cancel(); sl@0: iTimer.Close(); sl@0: } sl@0: sl@0: void CRandomTimer::RunL() sl@0: { sl@0: ++iCount; sl@0: FOREVER sl@0: { sl@0: TUint x=Random(iSeed)&511; sl@0: TInt tn=(TInt)(Random(iSeed) % (KNumConsumers + KNumProducers)); sl@0: CThread* pT = (tn>=KNumConsumers) ? (CThread*)TheProducers[tn-KNumConsumers] : (CThread*)TheConsumers[tn]; sl@0: if (x==511) sl@0: { sl@0: CV.Close(); sl@0: if (iSuspended) sl@0: { sl@0: if (iSuspended->iThread.Handle()) sl@0: iSuspended->iThread.Resume(); sl@0: iSuspended = NULL; sl@0: } sl@0: break; sl@0: } sl@0: if (pT->iThread.Handle()==0) sl@0: { sl@0: ++iZeroHandle; sl@0: continue; sl@0: } sl@0: if (x>=500) sl@0: { sl@0: if (pT->iCritical) sl@0: { sl@0: ++iBackOff; sl@0: continue; sl@0: } sl@0: pT->iThread.Terminate(0); sl@0: if (iSuspended == pT) sl@0: iSuspended = NULL; sl@0: break; sl@0: } sl@0: if (iSuspended && (x&1)) sl@0: { sl@0: if (iSuspended->iThread.Handle()) sl@0: iSuspended->iThread.Resume(); sl@0: iSuspended = NULL; sl@0: } sl@0: if (!iSuspended && !(x&15)) sl@0: { sl@0: iSuspended = pT; sl@0: pT->iThread.Suspend(); sl@0: ++pT->iSuspendCount; sl@0: } sl@0: TThreadPriority tp; sl@0: if (x>=400) sl@0: tp = EPriorityMuchMore; sl@0: else if (x>=300) sl@0: tp = EPriorityMore; sl@0: else if (x>=200) sl@0: tp = EPriorityNormal; sl@0: else if (x>=100) sl@0: tp = EPriorityLess; sl@0: else sl@0: tp = EPriorityMuchLess; sl@0: pT->iThread.SetPriority(tp); sl@0: break; sl@0: } sl@0: Start(); sl@0: } sl@0: sl@0: void CRandomTimer::Start() sl@0: { sl@0: TUint x=Random(iSeed)&15; sl@0: x+=1; sl@0: iTimer.HighRes(iStatus, x*1000); sl@0: SetActive(); sl@0: } sl@0: sl@0: void CRandomTimer::DoCancel() sl@0: { sl@0: iTimer.Cancel(); sl@0: } sl@0: sl@0: void CStatsTimer::NewL() sl@0: { sl@0: CStatsTimer* pT=new (ELeave) CStatsTimer(-10); sl@0: User::LeaveIfError(pT->iTimer.CreateLocal()); sl@0: CActiveScheduler::Add(pT); sl@0: pT->Start(); sl@0: } sl@0: sl@0: CStatsTimer::CStatsTimer(TInt aPriority) sl@0: : CActive(aPriority) sl@0: { sl@0: iInitFreeRam = FreeRam(); sl@0: } sl@0: sl@0: CStatsTimer::~CStatsTimer() sl@0: { sl@0: Cancel(); sl@0: iTimer.Close(); sl@0: } sl@0: sl@0: void CStatsTimer::RunL() sl@0: { sl@0: TInt i; sl@0: for (i=0; iDisplayStats(); sl@0: for (i=0; iDisplayStats(); sl@0: test.Printf(_L("RndTm: %9d BO: %9d ZH: %9d\n"), TheRandomTimer->iCount, TheRandomTimer->iBackOff, TheRandomTimer->iZeroHandle); sl@0: TInt free_ram = FreeRam(); sl@0: TInt delta_ram = iInitFreeRam - free_ram; sl@0: if (delta_ram > iMaxDelta) sl@0: iMaxDelta = delta_ram; sl@0: if (++iCount==10) sl@0: { sl@0: test.Printf(_L("Max RAM delta %dK Free RAM %08x\n"), iMaxDelta/1024, free_ram); sl@0: iCount=0; sl@0: } sl@0: Start(); sl@0: } sl@0: sl@0: void CStatsTimer::Start() sl@0: { sl@0: iTimer.After(iStatus, 1000000); sl@0: SetActive(); sl@0: } sl@0: sl@0: void CStatsTimer::DoCancel() sl@0: { sl@0: iTimer.Cancel(); sl@0: } sl@0: sl@0: _LIT(KSharedHeap, "SharedHeap"); sl@0: void InitialiseL() sl@0: { sl@0: PSeq = 0; sl@0: CSeq = 0; sl@0: User::LeaveIfError(Mutex.CreateLocal()); sl@0: User::LeaveIfError(CV.CreateLocal()); sl@0: User::LeaveIfNull(SharedHeap = UserHeap::ChunkHeap(&KSharedHeap, 0x1000, 0x01000000)); sl@0: CActiveScheduler* pA=new (ELeave) CActiveScheduler; sl@0: CActiveScheduler::Install(pA); sl@0: TInt id; sl@0: for (id=0; id