kerneltest/e32test/system/t_condvar.cpp
changeset 0 a41df078684a
child 117 5b5d147c7838
child 132 e4a7b1cbe40c
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     1 // Copyright (c) 1994-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\system\t_condvar.cpp
       
    15 // Overview:
       
    16 // Test the use of the RCondVar & RMutex classes.
       
    17 // API Information:
       
    18 // RCondVar, RMutex
       
    19 // Details:
       
    20 // - Create some local conditional variables and mutexes and verify results
       
    21 // are as expected.
       
    22 // - Create a test thread that waits on conditional variables and mutexes, 
       
    23 // append some items on an array, signal the conditional variable and mutex,
       
    24 // the thread then counts the number of items on the array and passes the 
       
    25 // result back to the main process. Verify results are as expected. Repeat
       
    26 // with different array data.
       
    27 // - Verify that a RCondVar::Wait() panics when the thread does not hold the
       
    28 // specified mutex (mutex not locked).
       
    29 // - Test using two mutexes with 1 conditional variable, append some items to 
       
    30 // an array, verify results from the thread are as expected. 
       
    31 // - Create a second thread with higher priority, perform tests similar to
       
    32 // above, verify results are as expected.
       
    33 // - Verify the thread timeout values are as expected.
       
    34 // - Create global conditional variables and global mutexes, using two threads
       
    35 // test the RCondVar::Signal() and RMutex::Wait() results are as expected.
       
    36 // - Test various combinations of creating a thread, suspending and killing it
       
    37 // and signalling a conditional variable and mutex. Verify results are as
       
    38 // expected.
       
    39 // - Create a secondary process along with a global chunk, conditional variable 
       
    40 // and mutex. Signal the conditional variable and verify the results are as 
       
    41 // expected.
       
    42 // - Using two threads, benchmark the number of conditional variable/mutex Signal
       
    43 // and Wait iterations that can be completed per second.
       
    44 // Platforms/Drives/Compatibility:
       
    45 // All.
       
    46 // Assumptions/Requirement/Pre-requisites:
       
    47 // Failures and causes:
       
    48 // Base Port information:
       
    49 // 
       
    50 //
       
    51 
       
    52 #include <e32std.h>
       
    53 #include <e32std_private.h>
       
    54 #include <e32svr.h>
       
    55 #include <e32test.h>
       
    56 #include <e32ldr.h>
       
    57 #include <e32def.h>
       
    58 #include <e32def_private.h>
       
    59 
       
    60 RTest test(_L("T_CONDVAR"));
       
    61 RMutex M1;
       
    62 RMutex M2;
       
    63 RCondVar CV1;
       
    64 RCondVar CV2;
       
    65 
       
    66 #define __TRACE_LINE__	test.Printf(_L("Line %d\n"),__LINE__)
       
    67 
       
    68 struct SThreadData
       
    69 	{
       
    70 	SThreadData();
       
    71 	RMutex iM;
       
    72 	RCondVar iV;
       
    73 	RArray<TInt>* iA;
       
    74 	TInt iTotal;
       
    75 	TInt iInnerLoops;
       
    76 	TInt iOuterLoops;
       
    77 	TInt iTimeoutMs;
       
    78 	TInt iTimeouts;
       
    79 	TInt iBadCount;
       
    80 	};
       
    81 
       
    82 struct SThreadData2
       
    83 	{
       
    84 	SThreadData2();
       
    85 	const TText* iMutexName;
       
    86 	const TText* iCondVarName;
       
    87 	TInt iInnerLoops;
       
    88 	};
       
    89 
       
    90 SThreadData::SThreadData()
       
    91 	{
       
    92 	memset(this, 0, sizeof(*this));
       
    93 	}
       
    94 
       
    95 SThreadData2::SThreadData2()
       
    96 	{
       
    97 	memset(this, 0, sizeof(*this));
       
    98 	}
       
    99 
       
   100 TInt Thread0(TAny*)
       
   101 	{
       
   102 	return CV1.Wait(M1);
       
   103 	}
       
   104 
       
   105 TInt Thread1(TAny* a)
       
   106 	{
       
   107 	TUint32 t1, t2;
       
   108 	SThreadData& d = *(SThreadData*)a;
       
   109 	TInt r = KErrNone;
       
   110 	TInt i = 0;
       
   111 	d.iM.Wait();
       
   112 	FOREVER
       
   113 		{
       
   114 		while (d.iA->Count()<=i && r==KErrNone)
       
   115 			{
       
   116 			t1 = User::NTickCount();
       
   117 			if (d.iTimeoutMs)
       
   118 				r = d.iV.TimedWait(d.iM, d.iTimeoutMs*1000);
       
   119 			else
       
   120 				r = d.iV.Wait(d.iM);
       
   121 			t2 = User::NTickCount();
       
   122 			++d.iInnerLoops;
       
   123 			if (r == KErrTimedOut)
       
   124 				{
       
   125 				++d.iTimeouts;
       
   126 				TInt iv = (TInt)(t2-t1);
       
   127 				if (iv<d.iTimeoutMs)
       
   128 					++d.iBadCount;
       
   129 				r = KErrNone;
       
   130 				}
       
   131 			}
       
   132 		if (r != KErrNone)
       
   133 			break;
       
   134 		++d.iOuterLoops;
       
   135 		TInt c = d.iA->Count();
       
   136 		for (; i<c; ++i)
       
   137 			d.iTotal += (*d.iA)[i];
       
   138 		}
       
   139 	return r;
       
   140 	}
       
   141 
       
   142 TInt Thread2(TAny* a)
       
   143 	{
       
   144 	TUint32 t1, t2;
       
   145 	SThreadData& d = *(SThreadData*)a;
       
   146 	TInt r = KErrNone;
       
   147 	d.iM.Wait();
       
   148 	RThread::Rendezvous(KErrNone);
       
   149 	while (r==KErrNone)
       
   150 		{
       
   151 		t1 = User::NTickCount();
       
   152 		if (d.iTimeoutMs)
       
   153 			r = d.iV.TimedWait(d.iM, d.iTimeoutMs*1000);
       
   154 		else
       
   155 			r = d.iV.Wait(d.iM);
       
   156 		t2 = User::NTickCount();
       
   157 		++d.iInnerLoops;
       
   158 		if (r == KErrTimedOut)
       
   159 			{
       
   160 			++d.iTimeouts;
       
   161 			TInt iv = (TInt)(t2-t1);
       
   162 			if (iv<d.iTimeoutMs)
       
   163 				++d.iBadCount;
       
   164 			r = KErrNone;
       
   165 			}
       
   166 		}
       
   167 	return r;
       
   168 	}
       
   169 
       
   170 TInt Thread3(TAny* a)
       
   171 	{
       
   172 	SThreadData2& d = *(SThreadData2*)a;
       
   173 	RMutex m;
       
   174 	RCondVar cv;
       
   175 	TInt r = m.OpenGlobal(TPtrC(d.iMutexName), EOwnerThread);
       
   176 	if (r!=KErrNone)
       
   177 		return r;
       
   178 	r = cv.OpenGlobal(TPtrC(d.iCondVarName), EOwnerThread);
       
   179 	if (r!=KErrNone)
       
   180 		return r;
       
   181 	m.Wait();
       
   182 	while (r==KErrNone)
       
   183 		{
       
   184 		r = cv.Wait(m);
       
   185 		++d.iInnerLoops;
       
   186 		}
       
   187 	return r;
       
   188 	}
       
   189 
       
   190 TInt Thread4(TAny* a)
       
   191 	{
       
   192 	volatile TInt& count = *(volatile TInt*)a;
       
   193 	TInt r = KErrNone;
       
   194 	M2.Wait();
       
   195 	while (r==KErrNone)
       
   196 		{
       
   197 		r = CV2.Wait(M2);
       
   198 		++count;
       
   199 		}
       
   200 	return r;
       
   201 	}
       
   202 
       
   203 TInt Thread5(TAny*)
       
   204 	{
       
   205 	FOREVER
       
   206 		{
       
   207 		M2.Wait();
       
   208 		CV2.Signal();
       
   209 		M2.Signal();
       
   210 		}
       
   211 	}
       
   212 
       
   213 void RunBench()
       
   214 	{
       
   215 	test.Next(_L("Benchmark"));
       
   216 	RThread t4, t5;
       
   217 	TInt count = 0;
       
   218 	TInt r = t4.Create(KNullDesC, &Thread4, 0x1000, 0x1000, 0x1000, &count);
       
   219 	test(r==KErrNone);
       
   220 	t4.SetPriority(EPriorityLess);
       
   221 	r = t5.Create(KNullDesC, &Thread5, 0x1000, 0x1000, 0x1000, NULL);
       
   222 	test(r==KErrNone);
       
   223 	t5.SetPriority(EPriorityMuchLess);
       
   224 	t4.Resume();
       
   225 	t5.Resume();
       
   226 	User::After(500000);
       
   227 	TInt initc = count;
       
   228 	User::After(5000000);
       
   229 	TInt finalc = count;
       
   230 	test.Printf(_L("%d iterations per second\n"), (finalc-initc)/5);
       
   231 	t4.Kill(0);
       
   232 	t5.Kill(0);
       
   233 	CLOSE_AND_WAIT(t4);
       
   234 	CLOSE_AND_WAIT(t5);
       
   235 	}
       
   236 
       
   237 void CreateThread2(RThread& aThread, SThreadData& aData, TThreadPriority aPri)
       
   238 	{
       
   239 	TInt r = aThread.Create(KNullDesC, &Thread2, 0x1000, 0x1000, 0x1000, &aData);
       
   240 	test(r==KErrNone);
       
   241 	aThread.SetPriority(aPri);
       
   242 	TRequestStatus s;
       
   243 	aThread.Rendezvous(s);
       
   244 	test(s==KRequestPending);
       
   245 	aThread.Resume();
       
   246 	User::WaitForRequest(s);
       
   247 	test(s==KErrNone);
       
   248 	test(aThread.ExitType()==EExitPending);
       
   249 	aData.iM.Wait();
       
   250 	}
       
   251 
       
   252 void KillThread2(RThread& aThread)
       
   253 	{
       
   254 	TRequestStatus s;
       
   255 	aThread.Logon(s);
       
   256 	test(s==KRequestPending);
       
   257 	aThread.Terminate(0);
       
   258 	User::WaitForRequest(s);
       
   259 	test(aThread.ExitType()==EExitTerminate);
       
   260 	test(aThread.ExitReason()==0);
       
   261 	test(s==0);
       
   262 	CLOSE_AND_WAIT(aThread);
       
   263 	}
       
   264 
       
   265 void AppendToArray(SThreadData& aD, TInt aCount, ...)
       
   266 	{
       
   267 	VA_LIST list;
       
   268 	VA_START(list,aCount);
       
   269 	aD.iM.Wait();
       
   270 	while(--aCount>=0)
       
   271 		{
       
   272 		test(aD.iA->Append(VA_ARG(list,TInt))==KErrNone);
       
   273 		}
       
   274 	aD.iV.Signal();
       
   275 	aD.iM.Signal();
       
   276 	}
       
   277 
       
   278 void AppendToArrayB(SThreadData& aD, TInt aCount, ...)
       
   279 	{
       
   280 	VA_LIST list;
       
   281 	VA_START(list,aCount);
       
   282 	aD.iM.Wait();
       
   283 	while(--aCount>=0)
       
   284 		{
       
   285 		test(aD.iA->Append(VA_ARG(list,TInt))==KErrNone);
       
   286 		}
       
   287 	aD.iV.Broadcast();
       
   288 	aD.iM.Signal();
       
   289 	}
       
   290 
       
   291 void AppendToArrayB2(SThreadData& aD, TInt aCount, ...)
       
   292 	{
       
   293 	VA_LIST list;
       
   294 	VA_START(list,aCount);
       
   295 	aD.iM.Wait();
       
   296 	while(--aCount>=0)
       
   297 		{
       
   298 		test(aD.iA->Append(VA_ARG(list,TInt))==KErrNone);
       
   299 		}
       
   300 	aD.iM.Signal();
       
   301 	aD.iV.Broadcast();
       
   302 	}
       
   303 
       
   304 void Thread2Test()
       
   305 	{
       
   306 	test.Next(_L("Thread2Test"));
       
   307 	RCondVar cv2;
       
   308 	RMutex m3;
       
   309 	TInt r = cv2.CreateLocal();
       
   310 	test(r==KErrNone);
       
   311 	r = m3.CreateLocal();
       
   312 	test(r==KErrNone);
       
   313 	SThreadData d1;
       
   314 	d1.iM = m3;
       
   315 	d1.iV = cv2;
       
   316 	RThread t1;
       
   317 
       
   318 	CreateThread2(t1, d1, EPriorityLess);
       
   319 	cv2.Signal();
       
   320 	m3.Signal();
       
   321 	User::After(100000);
       
   322 	test(d1.iInnerLoops == 1);
       
   323 	KillThread2(t1);
       
   324 
       
   325 	CreateThread2(t1, d1, EPriorityLess);
       
   326 	KillThread2(t1);
       
   327 	m3.Signal();
       
   328 	test(d1.iInnerLoops == 1);
       
   329 
       
   330 	CreateThread2(t1, d1, EPriorityLess);
       
   331 	m3.Signal();
       
   332 	User::After(10000);
       
   333 	KillThread2(t1);
       
   334 	test(d1.iInnerLoops == 1);
       
   335 
       
   336 	CreateThread2(t1, d1, EPriorityLess);
       
   337 	cv2.Signal();
       
   338 	User::After(10000);
       
   339 	KillThread2(t1);
       
   340 	m3.Signal();
       
   341 	test(d1.iInnerLoops == 1);
       
   342 
       
   343 	CreateThread2(t1, d1, EPriorityLess);
       
   344 	t1.Suspend();
       
   345 	KillThread2(t1);
       
   346 	m3.Signal();
       
   347 	test(d1.iInnerLoops == 1);
       
   348 
       
   349 	CreateThread2(t1, d1, EPriorityLess);
       
   350 	User::After(10000);
       
   351 	t1.Suspend();
       
   352 	KillThread2(t1);
       
   353 	m3.Signal();
       
   354 	test(d1.iInnerLoops == 1);
       
   355 
       
   356 	CreateThread2(t1, d1, EPriorityLess);
       
   357 	cv2.Signal();
       
   358 	t1.Suspend();
       
   359 	KillThread2(t1);
       
   360 	m3.Signal();
       
   361 	test(d1.iInnerLoops == 1);
       
   362 
       
   363 	CreateThread2(t1, d1, EPriorityLess);
       
   364 	cv2.Signal();
       
   365 	User::After(10000);
       
   366 	t1.Suspend();
       
   367 	KillThread2(t1);
       
   368 	m3.Signal();
       
   369 	test(d1.iInnerLoops == 1);
       
   370 
       
   371 	cv2.Close();
       
   372 	m3.Close();
       
   373 	}
       
   374 
       
   375 const TText* KMutex1Name = _S("mtx1");
       
   376 const TText* KMutex2Name = _S("mtx2");
       
   377 const TText* KCondVar1Name = _S("cv1");
       
   378 const TText* KCondVar2Name = _S("cv2");
       
   379 
       
   380 void TestGlobal()
       
   381 	{
       
   382 	test.Next(_L("Test Global"));
       
   383 	RMutex mg1, mg2;
       
   384 	RCondVar cvg1, cvg2;
       
   385 	TInt r = mg1.CreateGlobal(TPtrC(KMutex1Name));
       
   386 	test(r==KErrNone);
       
   387 	r = mg2.CreateGlobal(TPtrC(KMutex2Name));
       
   388 	test(r==KErrNone);
       
   389 	r = cvg1.CreateGlobal(TPtrC(KCondVar1Name));
       
   390 	test(r==KErrNone);
       
   391 	r = cvg2.CreateGlobal(TPtrC(KCondVar2Name));
       
   392 	test(r==KErrNone);
       
   393 	SThreadData2 d1, d2;
       
   394 	d1.iMutexName = KMutex1Name;
       
   395 	d1.iCondVarName = KCondVar1Name;
       
   396 	d2.iMutexName = KMutex2Name;
       
   397 	d2.iCondVarName = KCondVar2Name;
       
   398 
       
   399 	RThread t1, t2;
       
   400 	r = t1.Create(KNullDesC, &Thread3, 0x1000, 0x1000, 0x1000, &d1);
       
   401 	test(r==KErrNone);
       
   402 	t1.SetPriority(EPriorityMore);
       
   403 	TRequestStatus s1;
       
   404 	t1.Logon(s1);
       
   405 	t1.Resume();
       
   406 	r = t2.Create(KNullDesC, &Thread3, 0x1000, 0x1000, 0x1000, &d2);
       
   407 	test(r==KErrNone);
       
   408 	t2.SetPriority(EPriorityMore);
       
   409 	TRequestStatus s2;
       
   410 	t2.Logon(s2);
       
   411 	t2.Resume();
       
   412 
       
   413 	test(s1==KRequestPending);
       
   414 	test(s2==KRequestPending);
       
   415 	test(d1.iInnerLoops == 0);
       
   416 	test(d2.iInnerLoops == 0);
       
   417 	cvg1.Signal();
       
   418 	test(d1.iInnerLoops == 1);
       
   419 	test(d2.iInnerLoops == 0);
       
   420 	cvg2.Signal();
       
   421 	test(d1.iInnerLoops == 1);
       
   422 	test(d2.iInnerLoops == 1);
       
   423 
       
   424 	cvg1.Close();
       
   425 	cvg2.Close();
       
   426 	test(s1==KRequestPending);
       
   427 	test(s2==KRequestPending);
       
   428 	test(d1.iInnerLoops == 1);
       
   429 	test(d2.iInnerLoops == 1);
       
   430 
       
   431 	t1.Kill(0);
       
   432 	t2.Kill(0);
       
   433 	User::WaitForRequest(s1);
       
   434 	User::WaitForRequest(s2);
       
   435 	test(t1.ExitType()==EExitKill);
       
   436 	test(t1.ExitReason()==0);
       
   437 	test(t2.ExitType()==EExitKill);
       
   438 	test(t2.ExitReason()==0);
       
   439 	CLOSE_AND_WAIT(t1);
       
   440 	CLOSE_AND_WAIT(t2);
       
   441 	r = cvg1.OpenGlobal(TPtrC(KCondVar1Name));
       
   442 	test(r==KErrNotFound);
       
   443 	test(cvg1.Handle()==0);
       
   444 	mg1.Close();
       
   445 	mg2.Close();
       
   446 	}
       
   447 
       
   448 void TestSecondaryProcess()
       
   449 	{
       
   450 	test.Next(_L("Test Secondary Process"));
       
   451 
       
   452 	RProcess p;
       
   453 	RChunk c;
       
   454 	RMutex m;
       
   455 	RCondVar cv;
       
   456 
       
   457 	//cancel lazy dll unloading
       
   458 	RLoader loader;
       
   459 	TInt r = loader.Connect();
       
   460 	test(r==KErrNone);
       
   461 	r = loader.CancelLazyDllUnload();
       
   462 	test(r==KErrNone);
       
   463 	loader.Close();
       
   464 
       
   465 	r = c.CreateGlobal(KNullDesC, 0x1000, 0x1000);
       
   466 	test(r==KErrNone);
       
   467 	volatile TInt& x = *(volatile TInt*)c.Base();
       
   468 	x = 0;
       
   469 	r = m.CreateGlobal(KNullDesC);
       
   470 	test(r==KErrNone);
       
   471 	r = cv.CreateGlobal(KNullDesC);
       
   472 	test(r==KErrNone);
       
   473 	r = p.Create(RProcess().FileName(), KNullDesC);
       
   474 	test(r==KErrNone);
       
   475 	p.SetPriority(EPriorityHigh);
       
   476 	r = p.SetParameter(1, cv);
       
   477 	test(r==KErrNone);
       
   478 	r = p.SetParameter(2, m);
       
   479 	test(r==KErrNone);
       
   480 	r = p.SetParameter(3, c);
       
   481 	test(r==KErrNone);
       
   482 	TRequestStatus s;
       
   483 	p.Logon(s);
       
   484 	p.Resume();
       
   485 	test(s==KRequestPending);
       
   486 	test(x==0);
       
   487 	TInt i;
       
   488 	for (i=0; i<10; ++i)
       
   489 		{
       
   490 		cv.Signal();
       
   491 		test(x == i+1);
       
   492 		}
       
   493 	cv.Close();
       
   494 	test(s==KRequestPending);
       
   495 	test(x==10);
       
   496 	p.Terminate(0);
       
   497 	User::WaitForRequest(s);
       
   498 	test(p.ExitType()==EExitTerminate);
       
   499 	test(p.ExitReason()==0);
       
   500 	CLOSE_AND_WAIT(p);
       
   501 	m.Close();
       
   502 	c.Close();
       
   503 	}
       
   504 
       
   505 TInt SecondaryProcess(RCondVar aCV)
       
   506 	{
       
   507 	RDebug::Print(_L("SecProc"));
       
   508 	RMutex mp;
       
   509 	RChunk cp;
       
   510 	TInt r = mp.Open(2);
       
   511 	if (r!=KErrNone)
       
   512 		return r;
       
   513 	r = cp.Open(3);
       
   514 	if (r!=KErrNone)
       
   515 		return r;
       
   516 	volatile TInt& x = *(volatile TInt*)cp.Base();
       
   517 	mp.Wait();
       
   518 	r = KErrNone;
       
   519 	while (r==KErrNone)
       
   520 		{
       
   521 		r = aCV.Wait(mp);
       
   522 		++x;
       
   523 		RDebug::Print(_L("SecProc r=%d x=%d"), r, x);
       
   524 		}
       
   525 	return r;
       
   526 	}
       
   527 
       
   528 TInt E32Main()
       
   529 	{
       
   530 	__KHEAP_MARK;
       
   531 	__UHEAP_MARK;
       
   532 
       
   533 	TInt r;
       
   534 	RCondVar cvp;
       
   535 	r = cvp.Open(1);
       
   536 	if (r==KErrNone)
       
   537 		return SecondaryProcess(cvp);
       
   538 	test.Title();
       
   539 	test.Start(_L("Create condition variable"));
       
   540 	r = CV1.CreateLocal();
       
   541 	test(r==KErrNone);
       
   542 	r = CV2.CreateLocal();
       
   543 	test(r==KErrNone);
       
   544 
       
   545 	test.Next(_L("Signal with no-one waiting"));
       
   546 	CV1.Signal();
       
   547 
       
   548 	test.Next(_L("Broadcast with no-one waiting"));
       
   549 	CV1.Broadcast();
       
   550 
       
   551 	test.Next(_L("Create mutexes"));
       
   552 	r = M1.CreateLocal();
       
   553 	test(r==KErrNone);
       
   554 	r = M2.CreateLocal();
       
   555 	test(r==KErrNone);
       
   556 
       
   557 	RArray<TInt> array;
       
   558 	SThreadData d0;
       
   559 	d0.iM = M2;
       
   560 	d0.iV = CV1;
       
   561 	d0.iA = &array;
       
   562 	test.Next(_L("Create thread to use mutex 2"));
       
   563 	RThread t0;
       
   564 	r = t0.Create(KNullDesC, &Thread1, 0x1000, 0x1000, 0x1000, &d0);
       
   565 	test(r==KErrNone);
       
   566 	t0.SetPriority(EPriorityMore);
       
   567 	TRequestStatus s0;
       
   568 	t0.Logon(s0);
       
   569 	t0.Resume();
       
   570 	__TRACE_LINE__;
       
   571 	AppendToArray(d0, 1, 4);
       
   572 	test(d0.iTotal==4);
       
   573 	__TRACE_LINE__;
       
   574 	AppendToArray(d0, 2, -3, 17);
       
   575 	test(d0.iTotal==18);
       
   576 	t0.Terminate(11);
       
   577 	User::WaitForRequest(s0);
       
   578 	test(t0.ExitType()==EExitTerminate);
       
   579 	test(t0.ExitReason()==11);
       
   580 	CLOSE_AND_WAIT(t0);
       
   581 	array.Reset();
       
   582 
       
   583 	SThreadData d;
       
   584 	d.iM = M1;
       
   585 	d.iV = CV1;
       
   586 	d.iA = &array;
       
   587 	test.Next(_L("Create thread to use mutex 1"));
       
   588 	RThread t;
       
   589 	r = t.Create(KNullDesC, &Thread1, 0x1000, 0x1000, 0x1000, &d);
       
   590 	test(r==KErrNone);
       
   591 	t.SetPriority(EPriorityMore);
       
   592 	TRequestStatus s;
       
   593 	t.Logon(s);
       
   594 	t.Resume();
       
   595 
       
   596 	test.Next(_L("Test wait with mutex unlocked"));
       
   597 	r = t0.Create(KNullDesC, &Thread0, 0x1000, 0x1000, 0x1000, NULL);
       
   598 	test(r==KErrNone);
       
   599 	t0.SetPriority(EPriorityMore);
       
   600 	t0.Logon(s0);
       
   601 	TBool jit = User::JustInTime();
       
   602 	User::SetJustInTime(EFalse);
       
   603 	t0.Resume();
       
   604 	User::WaitForRequest(s0);
       
   605 	User::SetJustInTime(jit);
       
   606 	test(t0.ExitType()==EExitPanic);
       
   607 	test(t0.ExitCategory()==_L("KERN-EXEC"));
       
   608 	test(t0.ExitReason()==ECondVarWaitMutexNotLocked);
       
   609 	CLOSE_AND_WAIT(t0);
       
   610 
       
   611 	test.Next(_L("Test trying to use two mutexes with 1 condition variable"));
       
   612 	M2.Wait();
       
   613 	r = CV1.Wait(M2);
       
   614 	M2.Signal();
       
   615 	test(r==KErrInUse);
       
   616 
       
   617 	test(d.iTotal==0);
       
   618 	__TRACE_LINE__;
       
   619 	AppendToArray(d, 1, 3);
       
   620 	test(d.iTotal==3);
       
   621 	__TRACE_LINE__;
       
   622 	AppendToArray(d, 2, 3, 19);
       
   623 	test(d.iTotal==25);
       
   624 	__TRACE_LINE__;
       
   625 	AppendToArray(d, 4, 15, -1, -2, -30);
       
   626 	test(d.iTotal==7);
       
   627 	test(d.iInnerLoops==3);
       
   628 	test(d.iOuterLoops==3);
       
   629 	__TRACE_LINE__;
       
   630 	t.Suspend();
       
   631 	__TRACE_LINE__;
       
   632 	t.Resume();
       
   633 	test(d.iTotal==7);
       
   634 	test(d.iInnerLoops==4);
       
   635 	test(d.iOuterLoops==3);
       
   636 	__TRACE_LINE__;
       
   637 	t.SetPriority(EPriorityLess);
       
   638 	test(d.iTotal==7);
       
   639 	test(d.iInnerLoops==4);
       
   640 	test(d.iOuterLoops==3);
       
   641 	__TRACE_LINE__;
       
   642 	t.SetPriority(EPriorityMore);
       
   643 	test(d.iTotal==7);
       
   644 	test(d.iInnerLoops==5);
       
   645 	test(d.iOuterLoops==3);
       
   646 	__TRACE_LINE__;
       
   647 	t.Suspend();
       
   648 	__TRACE_LINE__;
       
   649 	AppendToArray(d, 1, 4);
       
   650 	test(d.iTotal==7);
       
   651 	test(d.iInnerLoops==5);
       
   652 	test(d.iOuterLoops==3);
       
   653 	__TRACE_LINE__;
       
   654 	t.Resume();
       
   655 	test(d.iTotal==11);
       
   656 	test(d.iInnerLoops==6);
       
   657 	test(d.iOuterLoops==4);
       
   658 
       
   659 	SThreadData d2;
       
   660 	d2.iM = M1;
       
   661 	d2.iV = CV1;
       
   662 	d2.iA = &array;
       
   663 
       
   664 	test.Next(_L("Create 2nd thread"));
       
   665 	RThread t2;
       
   666 	r = t2.Create(KNullDesC, &Thread1, 0x1000, NULL, &d2);
       
   667 	test(r==KErrNone);
       
   668 	t2.SetPriority(EPriorityMuchMore);
       
   669 	TRequestStatus s2;
       
   670 	t2.Logon(s2);
       
   671 	__TRACE_LINE__;
       
   672 	t2.Resume();
       
   673 
       
   674 	test(d2.iTotal == 11);
       
   675 	test(d2.iInnerLoops == 0);
       
   676 	test(d2.iOuterLoops == 1);
       
   677 	__TRACE_LINE__;
       
   678 	AppendToArray(d, 2, 9, 10);
       
   679 	test(d2.iTotal == 30);
       
   680 	test(d2.iInnerLoops == 1);
       
   681 	test(d2.iOuterLoops == 2);
       
   682 	test(d.iTotal==11);
       
   683 	test(d.iInnerLoops==6);
       
   684 	test(d.iOuterLoops==4);
       
   685 	__TRACE_LINE__;
       
   686 	AppendToArrayB(d, 2, 20, 30);
       
   687 	test(d2.iTotal == 80);
       
   688 	test(d2.iInnerLoops == 2);
       
   689 	test(d2.iOuterLoops == 3);
       
   690 	test(d.iTotal == 80);
       
   691 	test(d.iInnerLoops == 7);
       
   692 	test(d.iOuterLoops == 5);
       
   693 	__TRACE_LINE__;
       
   694 	AppendToArrayB2(d, 2, -10, -6);
       
   695 	test(d2.iTotal == 64);
       
   696 	test(d2.iInnerLoops == 3);
       
   697 	test(d2.iOuterLoops == 4);
       
   698 	test(d.iTotal == 64);
       
   699 	test(d.iInnerLoops == 8);
       
   700 	test(d.iOuterLoops == 6);
       
   701 	__TRACE_LINE__;
       
   702 	t2.Suspend();
       
   703 	__TRACE_LINE__;
       
   704 	AppendToArray(d, 2, -8, -8);
       
   705 	test(d2.iTotal == 64);
       
   706 	test(d2.iInnerLoops == 3);
       
   707 	test(d2.iOuterLoops == 4);
       
   708 	test(d.iTotal == 48);
       
   709 	test(d.iInnerLoops == 9);
       
   710 	test(d.iOuterLoops == 7);
       
   711 	__TRACE_LINE__;
       
   712 	t2.Resume();
       
   713 	test(d2.iTotal == 48);
       
   714 	test(d2.iInnerLoops == 4);
       
   715 	test(d2.iOuterLoops == 5);
       
   716 	test(d.iTotal == 48);
       
   717 	test(d.iInnerLoops == 9);
       
   718 	test(d.iOuterLoops == 7);
       
   719 
       
   720 	// test timeouts
       
   721 	d.iTimeoutMs = 1000;
       
   722 	__TRACE_LINE__;
       
   723 	t.Suspend();
       
   724 	__TRACE_LINE__;
       
   725 	t.Resume();
       
   726 	test(d2.iTotal == 48);
       
   727 	test(d2.iInnerLoops == 4);
       
   728 	test(d2.iOuterLoops == 5);
       
   729 	test(d2.iTimeouts == 0);
       
   730 	test(d.iTotal == 48);
       
   731 	test(d.iInnerLoops == 10);
       
   732 	test(d.iOuterLoops == 7);
       
   733 	test(d.iTimeouts == 0);
       
   734 	test(array.Append(1)==0);
       
   735 	TInt nt = 0;
       
   736 	do	{
       
   737 		if (d.iTimeouts > nt)
       
   738 			{
       
   739 			test(d.iTimeouts-nt == 1);
       
   740 			nt = d.iTimeouts;
       
   741 			test.Printf(_L("Timeout %d\n"), nt);
       
   742 			test(d2.iTotal == 48);
       
   743 			test(d2.iInnerLoops == 4);
       
   744 			test(d2.iOuterLoops == 5);
       
   745 			test(d2.iTimeouts == 0);
       
   746 			test(d.iTotal == 48+nt);
       
   747 			test(d.iInnerLoops == 10+nt);
       
   748 			test(d.iOuterLoops == 7+nt);
       
   749 			test(array.Append(1)==0);
       
   750 			}
       
   751 		} while (nt<10);
       
   752 
       
   753 	d.iTimeoutMs = 0;
       
   754 	AppendToArrayB(d, 0);
       
   755 	test(d2.iTotal == 59);
       
   756 	test(d2.iInnerLoops == 5);
       
   757 	test(d2.iOuterLoops == 6);
       
   758 	test(d2.iTimeouts == 0);
       
   759 	test(d.iTotal == 59);
       
   760 	test(d.iInnerLoops == 21);
       
   761 	test(d.iOuterLoops == 18);
       
   762 	test(d.iTimeouts == 10);
       
   763 
       
   764 	__TRACE_LINE__;
       
   765 	t.SetPriority(EPriorityLess);
       
   766 	__TRACE_LINE__;
       
   767 	AppendToArrayB(d, 1, 11);
       
   768 	test(d2.iTotal == 70);
       
   769 	test(d2.iInnerLoops == 6);
       
   770 	test(d2.iOuterLoops == 7);
       
   771 	test(d2.iTimeouts == 0);
       
   772 	test(d.iTotal == 59);
       
   773 	test(d.iInnerLoops == 21);
       
   774 	test(d.iOuterLoops == 18);
       
   775 	test(d.iTimeouts == 10);
       
   776 	User::After(50000);
       
   777 	test(d2.iTotal == 70);
       
   778 	test(d2.iInnerLoops == 6);
       
   779 	test(d2.iOuterLoops == 7);
       
   780 	test(d2.iTimeouts == 0);
       
   781 	test(d.iTotal == 70);
       
   782 	test(d.iInnerLoops == 22);
       
   783 	test(d.iOuterLoops == 19);
       
   784 	test(d.iTimeouts == 10);
       
   785 
       
   786 
       
   787 
       
   788 	__TRACE_LINE__;
       
   789 	CV1.Close();
       
   790 	User::WaitForRequest(s);
       
   791 	test(t.ExitType()==EExitKill);
       
   792 	test(t.ExitReason()==KErrGeneral);
       
   793 	User::WaitForRequest(s2);
       
   794 	test(t2.ExitType()==EExitKill);
       
   795 	test(t2.ExitReason()==KErrGeneral);
       
   796 	CLOSE_AND_WAIT(t);
       
   797 	CLOSE_AND_WAIT(t2);
       
   798 
       
   799 
       
   800 	M1.Close();
       
   801 
       
   802 	TestGlobal();
       
   803 
       
   804 	Thread2Test();
       
   805 
       
   806 	TestSecondaryProcess();
       
   807 
       
   808 	RunBench();
       
   809 	M2.Close();
       
   810 	CV2.Close();
       
   811 	array.Close();
       
   812 
       
   813 	test.End();
       
   814 	test.Close();
       
   815 
       
   816 	__UHEAP_MARKEND;
       
   817 	__KHEAP_MARKEND;
       
   818 	return KErrNone;
       
   819 	}
       
   820