os/kernelhwsrv/kerneltest/e32test/system/t_condvar2.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     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