kerneltest/e32test/system/t_condvar2.cpp
changeset 9 96e5fb8b040d
equal deleted inserted replaced
-1:000000000000 9:96e5fb8b040d
       
     1 // Copyright (c) 1995-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".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // e32test\misc\t_condvar2.cpp
       
    15 // 
       
    16 //
       
    17 
       
    18 #define __E32TEST_EXTENSION__
       
    19 
       
    20 #include <e32base.h>
       
    21 #include <e32base_private.h>
       
    22 #include <e32test.h>
       
    23 #include <e32svr.h>
       
    24 #include "u32std.h"
       
    25 #include "../misc/prbs.h"
       
    26 #include "../mmu/freeram.h"
       
    27 
       
    28 const TInt KStackSize=0x1000;
       
    29 
       
    30 RTest test(_L("T_CONDVAR2"));
       
    31 
       
    32 const TInt KPacketSize = 1024;
       
    33 const TInt KCrcSize = KPacketSize;
       
    34 struct SMessage
       
    35 	{
       
    36 	TDblQueLink iLink;
       
    37 	TUint	iSeq;
       
    38 	TUint	iData[KPacketSize/4];
       
    39 	TUint	iCrc;
       
    40 	};
       
    41 
       
    42 TDblQue<SMessage> Queue(0);
       
    43 TUint PSeq;
       
    44 TUint CSeq;
       
    45 RHeap* SharedHeap;
       
    46 RMutex Mutex;
       
    47 RCondVar CV;
       
    48 TInt NThreads;
       
    49 
       
    50 class CThread : public CActive
       
    51 	{
       
    52 public:
       
    53 	CThread(TInt aPriority);
       
    54 	~CThread();
       
    55 	virtual void RunL();
       
    56 	virtual void DoCancel();
       
    57 	virtual void DisplayStats()=0;
       
    58 	TInt Start();
       
    59 public:
       
    60 	static TInt ThreadFunc(TAny* aPtr);
       
    61 public:
       
    62 	virtual TInt StartThread()=0;
       
    63 	virtual TInt RunThread()=0;
       
    64 public:
       
    65 	RThread iThread;
       
    66 	TInt iInnerCount;
       
    67 	TInt iOuterCount;
       
    68 	TInt iSuspendCount;
       
    69 	TInt iExitCount;
       
    70 	TInt iTerminateCount;
       
    71 	TInt iCvCloseCount;
       
    72 	TBool iProducer;
       
    73 	TInt iId;
       
    74 	TBool iCritical;
       
    75 	TAny* iTempAlloc;
       
    76 	};
       
    77 
       
    78 class CProducerThread : public CThread
       
    79 	{
       
    80 public:
       
    81 	static void NewL(TInt aId);
       
    82 	CProducerThread(TInt aId);
       
    83 	virtual TInt StartThread();
       
    84 	virtual TInt RunThread();
       
    85 	virtual void DisplayStats();
       
    86 	};
       
    87 
       
    88 class CConsumerThread : public CThread
       
    89 	{
       
    90 public:
       
    91 	static void NewL(TInt aId);
       
    92 	CConsumerThread(TInt aId);
       
    93 	virtual TInt StartThread();
       
    94 	virtual TInt RunThread();
       
    95 	virtual void DisplayStats();
       
    96 	};
       
    97 
       
    98 class CRandomTimer : public CActive
       
    99 	{
       
   100 public:
       
   101 	static void NewL();
       
   102 	CRandomTimer(TInt aPriority);
       
   103 	~CRandomTimer();
       
   104 	virtual void RunL();
       
   105 	virtual void DoCancel();
       
   106 	void Start();
       
   107 public:
       
   108 	RTimer iTimer;
       
   109 	TUint iSeed[2];
       
   110 	TInt iCount;
       
   111 	TInt iBackOff;
       
   112 	TInt iZeroHandle;
       
   113 	CThread* iSuspended;
       
   114 	};
       
   115 
       
   116 class CStatsTimer : public CActive
       
   117 	{
       
   118 public:
       
   119 	static void NewL();
       
   120 	CStatsTimer(TInt aPriority);
       
   121 	~CStatsTimer();
       
   122 	virtual void RunL();
       
   123 	virtual void DoCancel();
       
   124 	void Start();
       
   125 public:
       
   126 	RTimer iTimer;
       
   127 	TInt iInitFreeRam;
       
   128 	TInt iMaxDelta;
       
   129 	TInt iCount;
       
   130 	};
       
   131 
       
   132 const TInt KNumProducers=4;
       
   133 CProducerThread* TheProducers[KNumProducers];
       
   134 const TInt KNumConsumers=4;
       
   135 CConsumerThread* TheConsumers[KNumConsumers];
       
   136 CRandomTimer* TheRandomTimer;
       
   137 
       
   138 CThread::CThread(TInt aPriority)
       
   139 	: CActive(aPriority)
       
   140 	{
       
   141 	}
       
   142 
       
   143 CThread::~CThread()
       
   144 	{
       
   145 	Cancel();
       
   146 	iThread.Kill(0);
       
   147 	iThread.Close();
       
   148 	}
       
   149 
       
   150 TInt StartAllThreads()
       
   151 	{
       
   152 	TInt i;
       
   153 	TInt r = CV.CreateLocal();
       
   154 	if (r!=KErrNone)
       
   155 		return r;
       
   156 	for (i=0; i<KNumConsumers; ++i)
       
   157 		{
       
   158 		r = TheConsumers[i]->Start();
       
   159 		if (r!=KErrNone)
       
   160 			return r;
       
   161 		}
       
   162 	for (i=0; i<KNumProducers; ++i)
       
   163 		{
       
   164 		r = TheProducers[i]->Start();
       
   165 		if (r!=KErrNone)
       
   166 			return r;
       
   167 		}
       
   168 	return KErrNone;
       
   169 	}
       
   170 
       
   171 void CThread::RunL()
       
   172 	{
       
   173 	TExitType exitType = iThread.ExitType();
       
   174 	TInt exitReason = iThread.ExitReason();
       
   175 	const TDesC& exitCat = iThread.ExitCategory();
       
   176 	TBool bad=EFalse;
       
   177 	if (exitType==EExitKill)
       
   178 		{
       
   179 		if (exitReason!=KErrNone && exitReason!=KErrGeneral)
       
   180 			bad=ETrue;
       
   181 		}
       
   182 	else if (exitType==EExitPanic)
       
   183 		{
       
   184 		if (exitCat!=_L("KERN-EXEC") || exitReason!=0 || CV.Handle()!=0)
       
   185 			bad=ETrue;
       
   186 		else
       
   187 			++iCvCloseCount;
       
   188 		}
       
   189 	if (bad)
       
   190 		{
       
   191 		TFullName n(iThread.FullName());
       
   192 		if (iProducer)
       
   193 			test.Printf(_L("Thread %S (P%1d) exited %d,%d,%S\n"),&n,iId,exitType,exitReason,&exitCat);
       
   194 		else
       
   195 			test.Printf(_L("Thread %S (C%1d) exited %d,%d,%S\n"),&n,iId,exitType,exitReason,&exitCat);
       
   196 		CActiveScheduler::Stop();
       
   197 		return;
       
   198 		}
       
   199 	CLOSE_AND_WAIT(iThread);
       
   200 	if (exitType==EExitTerminate)
       
   201 		++iTerminateCount;
       
   202 	else if (exitType==EExitKill && exitReason==KErrNone)
       
   203 		++iExitCount;
       
   204 	else if (exitType==EExitKill && exitReason==KErrGeneral)
       
   205 		++iCvCloseCount;
       
   206 	--NThreads;
       
   207 	if (iTempAlloc)
       
   208 		{
       
   209 		SharedHeap->Free(iTempAlloc);
       
   210 		iTempAlloc = NULL;
       
   211 		}
       
   212 	TInt r;
       
   213 	if (CV.Handle()==0)
       
   214 		{
       
   215 		if (NThreads==0)
       
   216 			r = StartAllThreads();
       
   217 		else
       
   218 			return;
       
   219 		}
       
   220 	else
       
   221 		r=Start();
       
   222 	if (r!=KErrNone)
       
   223 		{
       
   224 		test.Printf(_L("Start thread error %d\n"),r);
       
   225 		CActiveScheduler::Stop();
       
   226 		}
       
   227 	}
       
   228 
       
   229 void CThread::DoCancel()
       
   230 	{
       
   231 	iThread.LogonCancel(iStatus);
       
   232 	}
       
   233 
       
   234 TInt CThread::Start()
       
   235 	{
       
   236 	TInt r;
       
   237 	FOREVER
       
   238 		{
       
   239 		r=StartThread();
       
   240 		if (r==KErrNone)
       
   241 			break;
       
   242 		if (r!=KErrAlreadyExists)
       
   243 			break;
       
   244 		User::After(100000);
       
   245 		}
       
   246 	if (r==KErrNone)
       
   247 		{
       
   248 		iThread.Logon(iStatus);
       
   249 		SetActive();
       
   250 		}
       
   251 	++NThreads;
       
   252 	return r;
       
   253 	}
       
   254 
       
   255 TInt CThread::ThreadFunc(TAny* aPtr)
       
   256 	{
       
   257 	return ((CThread*)aPtr)->RunThread();
       
   258 	}
       
   259 
       
   260 CConsumerThread::CConsumerThread(TInt aId)
       
   261 	: CThread(0)
       
   262 	{
       
   263 	iId = aId;
       
   264 	}
       
   265 
       
   266 void CConsumerThread::NewL(TInt aId)
       
   267 	{
       
   268 	CConsumerThread* pT=new (ELeave) CConsumerThread(aId);
       
   269 	TheConsumers[aId] = pT;
       
   270 	CActiveScheduler::Add(pT);
       
   271 	User::LeaveIfError(pT->Start());
       
   272 	}
       
   273 
       
   274 TInt CConsumerThread::StartThread()
       
   275 	{
       
   276 	TInt r=iThread.Create(KNullDesC(), &ThreadFunc, KStackSize, SharedHeap, this);	// use unnamed thread
       
   277 	if (r!=KErrNone)
       
   278 		return r;
       
   279 	iThread.Resume();
       
   280 	return KErrNone;
       
   281 	}
       
   282 
       
   283 void CConsumerThread::DisplayStats()
       
   284 	{
       
   285 	test.Printf(_L("C%1d: I:%9d O:%9d S:%9d T:%9d C:%9d\n"), iId, iInnerCount, iOuterCount, iSuspendCount, iTerminateCount, iCvCloseCount);
       
   286 	}
       
   287 
       
   288 TInt CConsumerThread::RunThread()
       
   289 	{
       
   290 	Mutex.Wait();
       
   291 	TInt r = KErrNone;
       
   292 	FOREVER
       
   293 		{
       
   294 		while (Queue.IsEmpty())
       
   295 			{
       
   296 			r = CV.Wait(Mutex);
       
   297 			++iInnerCount;
       
   298 			if (r!=KErrNone)
       
   299 				return r;
       
   300 			}
       
   301 		++iOuterCount;
       
   302 		iCritical = ETrue;
       
   303 		SMessage* m = Queue.First();
       
   304 		m->iLink.Deque();
       
   305 		iTempAlloc = m;
       
   306 		TBool seq_ok = (m->iSeq == CSeq++);
       
   307 		iCritical = EFalse;
       
   308 		Mutex.Signal();
       
   309 		if (!seq_ok)
       
   310 			return KErrCorrupt;
       
   311 		TUint16 crc = 0;
       
   312 		Mem::Crc(crc, m->iData, KCrcSize);
       
   313 		if (crc != m->iCrc)
       
   314 			return KErrCorrupt;
       
   315 		iCritical = ETrue;
       
   316 		iTempAlloc = NULL;
       
   317 		User::Free(m);
       
   318 		iCritical = EFalse;
       
   319 		Mutex.Wait();
       
   320 		}
       
   321 	}
       
   322 
       
   323 CProducerThread::CProducerThread(TInt aId)
       
   324 	: CThread(0)
       
   325 	{
       
   326 	iId = aId;
       
   327 	}
       
   328 
       
   329 void CProducerThread::NewL(TInt aId)
       
   330 	{
       
   331 	CProducerThread* pT=new (ELeave) CProducerThread(aId);
       
   332 	TheProducers[aId] = pT;
       
   333 	CActiveScheduler::Add(pT);
       
   334 	User::LeaveIfError(pT->Start());
       
   335 	}
       
   336 
       
   337 TInt CProducerThread::StartThread()
       
   338 	{
       
   339 	TInt r=iThread.Create(KNullDesC(), &ThreadFunc, KStackSize, SharedHeap, this);	// use unnamed thread
       
   340 	if (r!=KErrNone)
       
   341 		return r;
       
   342 	iThread.Resume();
       
   343 	return KErrNone;
       
   344 	}
       
   345 
       
   346 void CProducerThread::DisplayStats()
       
   347 	{
       
   348 	test.Printf(_L("P%1d: I:%9d O:%9d S:%9d T:%9d C:%9d\n"), iId, iInnerCount, iOuterCount, iSuspendCount, iTerminateCount, iCvCloseCount);
       
   349 	}
       
   350 
       
   351 TInt CProducerThread::RunThread()
       
   352 	{
       
   353 	TUint seed[2];
       
   354 	seed[0] = User::TickCount();
       
   355 	seed[1] = 0;
       
   356 	FOREVER
       
   357 		{
       
   358 		iCritical = ETrue;
       
   359 		SMessage* m = new SMessage;
       
   360 		iTempAlloc = m;
       
   361 		iCritical = EFalse;
       
   362 		TInt i = 0;
       
   363 		for (; i<KPacketSize/4; ++i)
       
   364 			m->iData[i] = Random(seed);
       
   365 		TUint16 crc = 0;
       
   366 		Mem::Crc(crc, m->iData, KCrcSize);
       
   367 		m->iCrc = crc;
       
   368 		Mutex.Wait();
       
   369 		iCritical = ETrue;
       
   370 		m->iSeq = PSeq++;
       
   371 		Queue.AddLast(*m);
       
   372 		iTempAlloc = NULL;
       
   373 		iCritical = EFalse;
       
   374 		CV.Signal();
       
   375 		Mutex.Signal();
       
   376 		++iOuterCount;
       
   377 		if (!(Random(seed)&1))
       
   378 			User::AfterHighRes(1000);
       
   379 		}
       
   380 	}
       
   381 
       
   382 void CRandomTimer::NewL()
       
   383 	{
       
   384 	CRandomTimer* pR=new (ELeave) CRandomTimer(20);
       
   385 	User::LeaveIfError(pR->iTimer.CreateLocal());
       
   386 	CActiveScheduler::Add(pR);
       
   387 	TheRandomTimer=pR;
       
   388 	pR->Start();
       
   389 	}
       
   390 
       
   391 CRandomTimer::CRandomTimer(TInt aPriority)
       
   392 	: CActive(aPriority)
       
   393 	{
       
   394 	iSeed[0]=User::TickCount();
       
   395 	}
       
   396 
       
   397 CRandomTimer::~CRandomTimer()
       
   398 	{
       
   399 	Cancel();
       
   400 	iTimer.Close();
       
   401 	}
       
   402 
       
   403 void CRandomTimer::RunL()
       
   404 	{
       
   405 	++iCount;
       
   406 	FOREVER
       
   407 		{
       
   408 		TUint x=Random(iSeed)&511;
       
   409 		TInt tn=(TInt)(Random(iSeed) % (KNumConsumers + KNumProducers));
       
   410 		CThread* pT = (tn>=KNumConsumers) ? (CThread*)TheProducers[tn-KNumConsumers] : (CThread*)TheConsumers[tn];
       
   411 		if (x==511)
       
   412 			{
       
   413 			CV.Close();
       
   414 			if (iSuspended)
       
   415 				{
       
   416 				if (iSuspended->iThread.Handle())
       
   417 					iSuspended->iThread.Resume();
       
   418 				iSuspended = NULL;
       
   419 				}
       
   420 			break;
       
   421 			}
       
   422 		if (pT->iThread.Handle()==0)
       
   423 			{
       
   424 			++iZeroHandle;
       
   425 			continue;
       
   426 			}
       
   427 		if (x>=500)
       
   428 			{
       
   429 			if (pT->iCritical)
       
   430 				{
       
   431 				++iBackOff;
       
   432 				continue;
       
   433 				}
       
   434 			pT->iThread.Terminate(0);
       
   435 			if (iSuspended == pT)
       
   436 				iSuspended = NULL;
       
   437 			break;
       
   438 			}
       
   439 		if (iSuspended && (x&1))
       
   440 			{
       
   441 			if (iSuspended->iThread.Handle())
       
   442 				iSuspended->iThread.Resume();
       
   443 			iSuspended = NULL;
       
   444 			}
       
   445 		if (!iSuspended && !(x&15))
       
   446 			{
       
   447 			iSuspended = pT;
       
   448 			pT->iThread.Suspend();
       
   449 			++pT->iSuspendCount;
       
   450 			}
       
   451 		TThreadPriority tp;
       
   452 		if (x>=400)
       
   453 			tp = EPriorityMuchMore;
       
   454 		else if (x>=300)
       
   455 			tp = EPriorityMore;
       
   456 		else if (x>=200)
       
   457 			tp = EPriorityNormal;
       
   458 		else if (x>=100)
       
   459 			tp = EPriorityLess;
       
   460 		else
       
   461 			tp = EPriorityMuchLess;
       
   462 		pT->iThread.SetPriority(tp);
       
   463 		break;
       
   464 		}
       
   465 	Start();
       
   466 	}
       
   467 
       
   468 void CRandomTimer::Start()
       
   469 	{
       
   470 	TUint x=Random(iSeed)&15;
       
   471 	x+=1;
       
   472 	iTimer.HighRes(iStatus, x*1000);
       
   473 	SetActive();
       
   474 	}
       
   475 
       
   476 void CRandomTimer::DoCancel()
       
   477 	{
       
   478 	iTimer.Cancel();
       
   479 	}
       
   480 
       
   481 void CStatsTimer::NewL()
       
   482 	{
       
   483 	CStatsTimer* pT=new (ELeave) CStatsTimer(-10);
       
   484 	User::LeaveIfError(pT->iTimer.CreateLocal());
       
   485 	CActiveScheduler::Add(pT);
       
   486 	pT->Start();
       
   487 	}
       
   488 
       
   489 CStatsTimer::CStatsTimer(TInt aPriority)
       
   490 	: CActive(aPriority)
       
   491 	{
       
   492 	iInitFreeRam = FreeRam();
       
   493 	}
       
   494 
       
   495 CStatsTimer::~CStatsTimer()
       
   496 	{
       
   497 	Cancel();
       
   498 	iTimer.Close();
       
   499 	}
       
   500 
       
   501 void CStatsTimer::RunL()
       
   502 	{
       
   503 	TInt i;
       
   504 	for (i=0; i<KNumProducers; i++)
       
   505 		TheProducers[i]->DisplayStats();
       
   506 	for (i=0; i<KNumConsumers; i++)
       
   507 		TheConsumers[i]->DisplayStats();
       
   508 	test.Printf(_L("RndTm: %9d BO: %9d ZH: %9d\n"), TheRandomTimer->iCount, TheRandomTimer->iBackOff, TheRandomTimer->iZeroHandle);
       
   509 	TInt free_ram = FreeRam();
       
   510 	TInt delta_ram = iInitFreeRam - free_ram;
       
   511 	if (delta_ram > iMaxDelta)
       
   512 		iMaxDelta = delta_ram;
       
   513 	if (++iCount==10)
       
   514 		{
       
   515 		test.Printf(_L("Max RAM delta %dK Free RAM %08x\n"), iMaxDelta/1024, free_ram);
       
   516 		iCount=0;
       
   517 		}
       
   518 	Start();
       
   519 	}
       
   520 
       
   521 void CStatsTimer::Start()
       
   522 	{
       
   523 	iTimer.After(iStatus, 1000000);
       
   524 	SetActive();
       
   525 	}
       
   526 
       
   527 void CStatsTimer::DoCancel()
       
   528 	{
       
   529 	iTimer.Cancel();
       
   530 	}
       
   531 
       
   532 _LIT(KSharedHeap, "SharedHeap");
       
   533 void InitialiseL()
       
   534 	{
       
   535 	PSeq = 0;
       
   536 	CSeq = 0;
       
   537 	User::LeaveIfError(Mutex.CreateLocal());
       
   538 	User::LeaveIfError(CV.CreateLocal());
       
   539 	User::LeaveIfNull(SharedHeap = UserHeap::ChunkHeap(&KSharedHeap, 0x1000, 0x01000000));
       
   540 	CActiveScheduler* pA=new (ELeave) CActiveScheduler;
       
   541 	CActiveScheduler::Install(pA);
       
   542 	TInt id;
       
   543 	for (id=0; id<KNumConsumers; ++id)
       
   544 		CConsumerThread::NewL(id);
       
   545 	for (id=0; id<KNumProducers; ++id)
       
   546 		CProducerThread::NewL(id);
       
   547 	CRandomTimer::NewL();
       
   548 	CStatsTimer::NewL();
       
   549 	}
       
   550 
       
   551 GLDEF_C TInt E32Main()
       
   552 //
       
   553 // Test timers.
       
   554 //
       
   555 	{
       
   556 
       
   557 	test.Title();
       
   558 
       
   559 	RThread().SetPriority(EPriorityAbsoluteHigh);
       
   560 
       
   561 	TRAPD(r,InitialiseL());
       
   562 	test(r==KErrNone);
       
   563 
       
   564 	User::SetJustInTime(EFalse);
       
   565 
       
   566 	CActiveScheduler::Start();
       
   567 
       
   568 	test(0);
       
   569 
       
   570 	return(0);
       
   571 	}
       
   572