os/kernelhwsrv/kerneltest/e32test/prime/t_semutx.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\prime\t_semutx.cpp
    15 // Tests the RSemaphore, RMutex and RCriticalSection classes
    16 // Overview:
    17 // Tests the RSemaphore, RMutex and RCriticalSection classes
    18 // API Information:
    19 // RSemaphore, RMutex, RCriticalSection
    20 // Details:
    21 // - Test RSemaphore and RMutex with the producer/consumer scenario.
    22 // Create two threads, use signal and wait to coordinate the
    23 // threads. Verify results are as expected.
    24 // - Calculate the time required to create, resume and close a thread.
    25 // - Test RSemaphore::Wait(timeout) in a variety ways and timeout 
    26 // values. Verify results are as expected.
    27 // - Test RMutex via two threads which write to an array. The writing
    28 // and updating of the index is wrapped within a mutex pair. Verify 
    29 // results are as expected.
    30 // - Test RCriticalSection via two threads which write to an array. The 
    31 // writing and updating of the index is wrapped within a critical section
    32 // pair. Verify results are as expected.
    33 // Platforms/Drives/Compatibility:
    34 // All.
    35 // Assumptions/Requirement/Pre-requisites:
    36 // Failures and causes:
    37 // Base Port information:
    38 // 
    39 //
    40 
    41 #include <e32test.h>
    42 
    43 const TInt KMaxBufferSize=10;
    44 const TInt KMaxArraySize=10;
    45 const TInt KNumProducerItems=100;
    46 
    47 enum {EThread1ID=1,EThread2ID};
    48 
    49 RTest test(_L("T_SEMUTX"));
    50 RMutex mutex;
    51 RCriticalSection criticalSn;	
    52 TInt thread1Count,thread2Count;
    53 TInt arrayIndex;
    54 TInt array[KMaxArraySize];  
    55 TInt consumerArray[KNumProducerItems];
    56 RSemaphore slotAvailable,itemAvailable;  
    57 			 
    58 class CStack
    59 	{
    60 public:	   
    61 	CStack() {iCount=0;};
    62 	void Push(TInt aItem) {iStack[iCount++]=aItem;};
    63 	TInt Pop(void) {return(iStack[--iCount]);};
    64 private:
    65 	TInt iStack[KMaxBufferSize];
    66 	TInt iCount;
    67 	};
    68 CStack stack;
    69 
    70 
    71 TInt Producer(TAny*)
    72 	{
    73 	for(TInt ii=0;ii<KNumProducerItems;ii++)
    74 		{
    75 		slotAvailable.Wait();
    76 		mutex.Wait();
    77 		stack.Push(ii);
    78 		mutex.Signal();
    79 		itemAvailable.Signal();
    80 		}
    81 	return(KErrNone);
    82 	}
    83 
    84 TInt Consumer(TAny*)
    85 	{
    86 	TInt item;
    87 	for(TInt ii=0;ii<KNumProducerItems;ii++)
    88 		{
    89 		itemAvailable.Wait();
    90 		mutex.Wait();
    91 		item=stack.Pop();
    92 		mutex.Signal();
    93 		slotAvailable.Signal();
    94 		consumerArray[item]=item;
    95 		}
    96 	return(KErrNone);
    97 	}
    98 
    99 void BusyWait(TInt aMicroseconds)
   100 	{
   101 	TTime begin;
   102 	begin.HomeTime();
   103 	FOREVER
   104 		{
   105 		TTime now;
   106 		now.HomeTime();
   107 		TTimeIntervalMicroSeconds iv=now.MicroSecondsFrom(begin);
   108 		if (iv.Int64()>=TInt64(aMicroseconds))
   109 			return;
   110 		}
   111 	}
   112 
   113 TInt MutexThreadEntryPoint1(TAny*)
   114 //
   115 // Mutex test thread 1
   116 //
   117 	{	
   118 
   119 	thread1Count=0;
   120 	TBool running=ETrue;
   121 	do
   122 		{
   123 		mutex.Wait();
   124 		BusyWait(100000);
   125 		if (arrayIndex<KMaxArraySize)
   126 			{
   127 			array[arrayIndex++]=EThread1ID;
   128 			thread1Count++;
   129 			}
   130 		else
   131 			running=EFalse;
   132 		mutex.Signal();
   133 		} while (running);
   134 	return(KErrNone);
   135 	}
   136 
   137 TInt MutexThreadEntryPoint2(TAny*)
   138 //
   139 // Mutex test thread 2
   140 //
   141 	{
   142 
   143 	thread2Count=0;
   144 	TBool running=ETrue;
   145 	do
   146 		{
   147 		mutex.Wait();
   148 		BusyWait(200000);
   149 		if (arrayIndex<KMaxArraySize)
   150 			{
   151 			array[arrayIndex++]=EThread2ID;
   152 			thread2Count++;
   153 			}
   154 		else
   155 			running=EFalse;
   156 		mutex.Signal();
   157 		} while (running);
   158 	return(KErrNone);
   159 	}
   160 
   161 TInt CriticalSnThreadEntryPoint1(TAny*)
   162 //
   163 // Critical Section test thread 1
   164 //
   165 	{	
   166 
   167 	thread1Count=0;
   168 	TBool running=ETrue;
   169 	do
   170 		{
   171 		criticalSn.Wait();
   172 		User::After(100000);
   173 		if (arrayIndex<KMaxArraySize)
   174 			{
   175 			array[arrayIndex++]=EThread1ID;
   176 			thread1Count++;
   177 			}
   178 		else
   179 			running=EFalse;
   180 		criticalSn.Signal();
   181 		} while (running);
   182 	return(KErrNone);
   183 	}
   184 
   185 TInt CriticalSnThreadEntryPoint2(TAny*)
   186 //
   187 // Critical Section test thread 2
   188 //
   189 	{
   190 
   191 	thread2Count=0;
   192 	TBool running=ETrue;
   193 	do
   194 		{
   195 		criticalSn.Wait();
   196 		User::After(200000);
   197 		if (arrayIndex<KMaxArraySize)
   198 			{
   199 			array[arrayIndex++]=EThread2ID;
   200 			thread2Count++;
   201 			}
   202 		else
   203 			running=EFalse;
   204 		criticalSn.Signal();
   205 		} while (running);
   206 	return(KErrNone);
   207 	}
   208 
   209 struct SWaitSem
   210 	{
   211 	RSemaphore iSem;
   212 	TInt iTimeout;
   213 	};
   214 
   215 TInt WaitSemThread(TAny* a)
   216 	{
   217 	SWaitSem& ws = *(SWaitSem*)a;
   218 	return ws.iSem.Wait(ws.iTimeout);
   219 	}
   220 
   221 void StartWaitSemThread(RThread& aT, SWaitSem& aW, TThreadPriority aP=EPriorityLess)
   222 	{
   223 	TInt r = aT.Create(KNullDesC, &WaitSemThread, 0x1000, 0x1000, 0x1000, &aW);
   224 	test(r==KErrNone);
   225 	aT.SetPriority(aP);
   226 	aT.Resume();
   227 	}
   228 
   229 void WaitForWaitSemThread(RThread& aT, TInt aResult)
   230 	{
   231 	TRequestStatus s;
   232 	aT.Logon(s);
   233 	User::WaitForRequest(s);
   234 	test(aT.ExitType()==EExitKill);
   235 	test(aT.ExitReason()==aResult);
   236 	test(s.Int()==aResult);
   237 	CLOSE_AND_WAIT(aT);
   238 	}
   239 
   240 TInt DummyThread(TAny*)
   241 	{
   242 	return 0;
   243 	}
   244 
   245 void TestSemaphore2()
   246 	{
   247 	test.Start(_L("Test semaphore wait with timeout"));
   248 	SWaitSem ws;
   249 	RThread t;
   250 	TTime initial;
   251 	TTime final;
   252 	TInt elapsed=0;
   253 	TInt r = ws.iSem.CreateLocal(0);
   254 	test(r==KErrNone);
   255 
   256 	RThread().SetPriority(EPriorityAbsoluteVeryLow);
   257 	TInt threadcount=0;
   258 	initial.HomeTime();
   259 	while (elapsed<1000000)
   260 		{
   261 		r = t.Create(KNullDesC, &DummyThread, 0x1000, NULL, NULL);
   262 		test(r==KErrNone);
   263 		t.SetPriority(EPriorityMore);
   264 		t.Resume();
   265 		t.Close();
   266 		++threadcount;
   267 		final.HomeTime();
   268 		elapsed = I64INT(final.Int64()-initial.Int64());
   269 		}
   270 	RThread().SetPriority(EPriorityNormal);
   271 	test.Printf(_L("%d threads in 1 sec\n"),threadcount);
   272 	TInt overhead = 1000000/threadcount;
   273 	test.Printf(_L("overhead = %dus\n"),overhead);
   274 
   275 	ws.iTimeout=1000000;
   276 	initial.HomeTime();
   277 	StartWaitSemThread(t, ws);
   278 	WaitForWaitSemThread(t, KErrTimedOut);
   279 	final.HomeTime();
   280 	elapsed = I64INT(final.Int64()-initial.Int64());
   281 	test.Printf(_L("Time taken = %dus\n"), elapsed);
   282 	test(elapsed>=900000+overhead && elapsed<1500000+overhead);
   283 
   284 	ws.iTimeout=-1;
   285 	initial.HomeTime();
   286 	StartWaitSemThread(t, ws);
   287 	WaitForWaitSemThread(t, KErrArgument);
   288 	final.HomeTime();
   289 	elapsed = I64INT(final.Int64()-initial.Int64());
   290 	test.Printf(_L("Time taken = %dus\n"), elapsed);
   291 
   292 	ws.iTimeout=2000000;
   293 	initial.HomeTime();
   294 	StartWaitSemThread(t, ws);
   295 	User::After(1000000);
   296 	ws.iSem.Signal();
   297 	WaitForWaitSemThread(t, KErrNone);
   298 	final.HomeTime();
   299 	elapsed = I64INT(final.Int64()-initial.Int64());
   300 	test.Printf(_L("Time taken = %dus\n"), elapsed);
   301 	test(elapsed>=900000+overhead && elapsed<1500000+overhead);
   302 
   303 	ws.iTimeout=100000;
   304 	StartWaitSemThread(t, ws, EPriorityMore);
   305 	t.Suspend();
   306 	ws.iSem.Signal();
   307 	User::After(200000);
   308 	t.Resume();
   309 	WaitForWaitSemThread(t, KErrTimedOut);
   310 	test(ws.iSem.Wait(1)==KErrNone);
   311 
   312 	ws.iTimeout=100000;
   313 	StartWaitSemThread(t, ws, EPriorityMore);
   314 	t.Suspend();
   315 	ws.iSem.Signal();
   316 	User::After(50000);
   317 	t.Resume();
   318 	WaitForWaitSemThread(t, KErrNone);
   319 	test(ws.iSem.Wait(1)==KErrTimedOut);
   320 
   321 	RThread t2;
   322 	ws.iTimeout=100000;
   323 	StartWaitSemThread(t, ws, EPriorityMuchMore);
   324 	StartWaitSemThread(t2, ws, EPriorityMore);
   325 	t.Suspend();
   326 	ws.iSem.Signal();
   327 	test(t2.ExitType()==EExitKill);
   328 	test(t.ExitType()==EExitPending);
   329 	t.Resume();
   330 	WaitForWaitSemThread(t, KErrTimedOut);
   331 	WaitForWaitSemThread(t2, KErrNone);
   332 	test(ws.iSem.Wait(1)==KErrTimedOut);
   333 
   334 	ws.iTimeout=1000000;
   335 	initial.HomeTime();
   336 	StartWaitSemThread(t2, ws, EPriorityMore);
   337 	StartWaitSemThread(t, ws, EPriorityMuchMore);
   338 	ws.iSem.Signal();
   339 	WaitForWaitSemThread(t, KErrNone);
   340 	final.HomeTime();
   341 	elapsed = I64INT(final.Int64()-initial.Int64());
   342 	test.Printf(_L("Time taken = %dus\n"), elapsed);
   343 	WaitForWaitSemThread(t2, KErrTimedOut);
   344 	final.HomeTime();
   345 	elapsed = I64INT(final.Int64()-initial.Int64());
   346 	test.Printf(_L("Time taken = %dus\n"), elapsed);
   347 	test(elapsed>=900000+2*overhead && elapsed<1500000+2*overhead);
   348 
   349 	ws.iTimeout=1000000;
   350 	initial.HomeTime();
   351 	StartWaitSemThread(t2, ws, EPriorityMore);
   352 	StartWaitSemThread(t, ws, EPriorityMuchMore);
   353 	WaitForWaitSemThread(t, KErrTimedOut);
   354 	final.HomeTime();
   355 	elapsed = I64INT(final.Int64()-initial.Int64());
   356 	test.Printf(_L("Time taken = %dus\n"), elapsed);
   357 	WaitForWaitSemThread(t2, KErrTimedOut);
   358 	final.HomeTime();
   359 	elapsed = I64INT(final.Int64()-initial.Int64());
   360 	test.Printf(_L("Time taken = %dus\n"), elapsed);
   361 	test(elapsed>=900000+2*overhead && elapsed<1500000+2*overhead);
   362 
   363 	ws.iTimeout=1000000;
   364 	initial.HomeTime();
   365 	StartWaitSemThread(t2, ws, EPriorityMore);
   366 	StartWaitSemThread(t, ws, EPriorityMuchMore);
   367 	t.Kill(299792458);
   368 	WaitForWaitSemThread(t2, KErrTimedOut);
   369 	WaitForWaitSemThread(t, 299792458);
   370 	final.HomeTime();
   371 	elapsed = I64INT(final.Int64()-initial.Int64());
   372 	test.Printf(_L("Time taken = %dus\n"), elapsed);
   373 	test(elapsed>=900000+2*overhead && elapsed<1500000+2*overhead);
   374 
   375 	ws.iTimeout=1000000;
   376 	initial.HomeTime();
   377 	StartWaitSemThread(t, ws, EPriorityMore);
   378 	StartWaitSemThread(t2, ws, EPriorityMuchMore);
   379 	test(t.ExitType()==EExitPending);
   380 	test(t2.ExitType()==EExitPending);
   381 	ws.iSem.Close();
   382 	test(t.ExitType()==EExitKill);
   383 	test(t2.ExitType()==EExitKill);
   384 	WaitForWaitSemThread(t2, KErrGeneral);
   385 	WaitForWaitSemThread(t, KErrGeneral);
   386 	final.HomeTime();
   387 	elapsed = I64INT(final.Int64()-initial.Int64());
   388 	test.Printf(_L("Time taken = %dus\n"), elapsed);
   389 	test(elapsed<=50000+3*overhead);
   390 
   391 	test.End();
   392 	}
   393 
   394 void TestSemaphore()
   395 	{
   396 /*********** TO DO ************/
   397 // Check it panics if the count <0
   398 
   399 	test.Start(_L("Create"));
   400 	RSemaphore semaphore;
   401 	RThread thread1, thread2;
   402 
   403 	semaphore.CreateLocal(0); 	// creates a DPlatSemaphore but casts it to a pointer to a DSemaphore
   404 								// sets semaphore count to the value of the parameter, 
   405 								// adds object to the K::Semaphores container, sets iHandle
   406 								// Local sets DSemaphore.iName to NULL & iOwner to Kern::CurrentProcess()
   407 								// Global sets iName to that passed and iOwner to NULL
   408 								// Adds a record into CObjectIx containing a pointer to the semaphore object
   409 /*	test.Next(_L("Find"));
   410 	fullName=semaphore.FullName();	
   411 	find.Find(fullName);	// sets iMatch to fullName	(misleadingly named method as it doesn't find anything)
   412 	test(find.Next(fullName)== KErrNone);	
   413 */
   414 	test.Next(_L("Producer/Consumer scenario"));
   415 	// Test Rsemaphore with the producer/consumer scenario	RThread thread1, thread2;
   416 	TRequestStatus stat1, stat2;
   417 	test(mutex.CreateLocal()==KErrNone);
   418 	test(slotAvailable.CreateLocal(KMaxBufferSize)==KErrNone);
   419 	test(itemAvailable.CreateLocal(0)==KErrNone);
   420 	test(thread1.Create(_L("Thread1"),Producer,KDefaultStackSize,0x200,0x200,NULL)==KErrNone);
   421 	test(thread2.Create(_L("Thread2"),Consumer,KDefaultStackSize,0x200,0x200,NULL)==KErrNone);
   422 	thread1.Logon(stat1);
   423 	thread2.Logon(stat2);
   424 	test(stat1==KRequestPending);
   425 	test(stat2==KRequestPending);
   426 	thread1.Resume(); 
   427 	thread2.Resume();
   428 	User::WaitForRequest(stat1);
   429 	User::WaitForRequest(stat2);
   430 	test(stat1==KErrNone);
   431 	test(stat2==KErrNone);
   432 	for(TInt jj=0;jj<KNumProducerItems;jj++)
   433 		test(consumerArray[jj]==jj);		
   434 	
   435 	test.Next(_L("Close"));
   436 	mutex.Close();
   437 	CLOSE_AND_WAIT(thread1);
   438 	CLOSE_AND_WAIT(thread2);
   439 	test.End();
   440 	}
   441 
   442 void TestMutex2()
   443 	{
   444 	RMutex m;
   445 	test.Start(_L("Create"));
   446 	test(m.CreateLocal()==KErrNone);
   447 
   448 	// Test RMutex::IsHeld()
   449 	test.Next(_L("IsHeld ?"));
   450 	test(!m.IsHeld());
   451 	test.Next(_L("Wait"));
   452 	m.Wait();
   453 	test.Next(_L("IsHeld ?"));
   454 	test(m.IsHeld());
   455 	test.Next(_L("Signal"));
   456 	m.Signal();
   457 	test.Next(_L("IsHeld ?"));
   458 	test(!m.IsHeld());
   459 
   460 	test.End();
   461 	}
   462 
   463 void TestMutex()
   464 	{
   465 	test.Start(_L("Create"));
   466 	test(mutex.CreateLocal()==KErrNone);
   467 	
   468 	test.Next(_L("Threads writing to arrays test"));
   469 //
   470 // Create two threads which write to two arrays. The arrays and indexs
   471 // are global and each thread writes an identifier to the arrays. For
   472 // one array the writing and updating of the index is wrapped in a mutex
   473 // pair. The other array is a control and is not wrapaped within mutex.
   474 // Each thread records the number of instances it "thinks" it wrote to
   475 // each array. For the mutex controlled array the actual instances
   476 // written to the array should always be the same as the threads think.
   477 //
   478 	arrayIndex=0;
   479 	RThread thread1,thread2;	
   480 	test(thread1.Create(_L("Thread1"),MutexThreadEntryPoint1,KDefaultStackSize,0x2000,0x2000,NULL)==KErrNone);
   481 	test(thread2.Create(_L("Thread2"),MutexThreadEntryPoint2,KDefaultStackSize,0x2000,0x2000,NULL)==KErrNone);			 
   482 	TRequestStatus stat1,stat2;
   483 	thread1.Logon(stat1);
   484 	thread2.Logon(stat2);
   485 	test(stat1==KRequestPending);
   486 	test(stat2==KRequestPending);
   487 	thread1.Resume(); 
   488 	thread2.Resume();
   489 	User::WaitForRequest(stat1);
   490 	User::WaitForRequest(stat2);
   491 	test(stat1==KErrNone);
   492 	test(stat2==KErrNone); 
   493 	TInt thread1ActualCount=0; 
   494 	TInt thread2ActualCount=0;
   495 	TInt ii=0;
   496 	while(ii<KMaxArraySize)
   497 		{
   498 		if (array[ii]==EThread1ID)
   499 			thread1ActualCount++;
   500 		if (array[ii]==EThread2ID)
   501 			thread2ActualCount++;
   502 		ii++;
   503 		}
   504 	test.Printf(_L("T1 %d T1ACT %d T2 %d T2ACT %d"),thread1Count,thread1ActualCount,thread2Count,thread2ActualCount);
   505 	test(thread1ActualCount==thread1Count);
   506 	test(thread2ActualCount==thread2Count);
   507 	test(thread1Count==thread2Count);
   508 	test(thread1Count==(KMaxArraySize>>1));
   509 	
   510 	test.Next(_L("Close"));
   511 	CLOSE_AND_WAIT(thread1);
   512 	CLOSE_AND_WAIT(thread2);
   513 	mutex.Close();
   514 	test.End();
   515 	}
   516 
   517 void TestCriticalSection()
   518 //
   519 //As TestMutex, but for RCriticalSection
   520 //
   521 	{
   522 	
   523 	test.Start(_L("Create"));
   524 	test(criticalSn.CreateLocal()==KErrNone);
   525 
   526 /***************** TO DO ***********************
   527 
   528 	test.Next(_L("Find"));
   529 //
   530 // Test finding the RCriticalSection
   531 //
   532 	TFindCriticalSection find;
   533 	TFullName fullName;
   534 	fullName=criticalSn.FullName();
   535 	find.Find(fullName);
   536 	test(find.Next(fullName)==KErrNone);
   537 	test(fullName==criticalSn.FullName());
   538 
   539 ************************************************/
   540 
   541 	test.Next(_L("Threads writing to arrays test"));
   542 //
   543 // Create two threads which write to two arrays. The arrays and indexs
   544 // are global and each thread writes an identifier to the arrays. For
   545 // one array the writing and updating of the index is wrapped in a critical
   546 // section pair. The other array is a control and is not wrapaped within
   547 // a critical section. Each thread records the number of instances it
   548 // "thinks" it wrote to each array. For the mutex controlled array the
   549 // actual instances written to the array should always be the same as the
   550 // threads think.
   551 //
   552 	arrayIndex=0;
   553 	RThread thread1,thread2;	
   554 	test(thread1.Create(_L("Thread1"),CriticalSnThreadEntryPoint1,KDefaultStackSize,0x2000,0x2000,NULL)==KErrNone);
   555 	test(thread2.Create(_L("Thread2"),CriticalSnThreadEntryPoint2,KDefaultStackSize,0x2000,0x2000,NULL)==KErrNone);			 
   556 	TRequestStatus stat1,stat2;
   557 	thread1.Logon(stat1);
   558 	thread2.Logon(stat2);
   559 	test(stat1==KRequestPending);
   560 	test(stat2==KRequestPending);
   561 	thread1.Resume(); 
   562 	thread2.Resume();
   563 	User::WaitForRequest(stat1);
   564 	User::WaitForRequest(stat2);
   565 	test(stat1==KErrNone);
   566 	test(stat2==KErrNone); 
   567 	TInt thread1ActualCount=0; 
   568 	TInt thread2ActualCount=0;
   569 	TInt ii=0;
   570 	while(ii<KMaxArraySize)
   571 		{
   572 		if (array[ii]==EThread1ID)
   573 			thread1ActualCount++;
   574 		if (array[ii]==EThread2ID)
   575 			thread2ActualCount++;
   576 		ii++;
   577 		}
   578 	test(thread1ActualCount==thread1Count);
   579 	test(thread2ActualCount==thread2Count);
   580 	test(thread1Count==thread2Count);
   581 	test(thread1Count==(KMaxArraySize>>1));
   582 
   583 	test.Next(_L("Close"));
   584 	CLOSE_AND_WAIT(thread1);
   585 	CLOSE_AND_WAIT(thread2);
   586 	criticalSn.Close();
   587 	test.End();
   588 	}
   589 
   590 
   591 GLDEF_C TInt E32Main()
   592 	{	
   593 
   594 	test.Title();
   595  	__UHEAP_MARK;
   596 	test.Start(_L("Test RSemaphore"));
   597 	TestSemaphore();
   598 	TestSemaphore2();
   599 	test.Next(_L("Test RMutex"));
   600 	TestMutex();
   601 	TestMutex2();
   602 	test.Next(_L("Test RCriticalSection"));
   603 	TestCriticalSection();
   604 	test.End();
   605 	__UHEAP_MARKEND;
   606 	return(KErrNone);
   607 	}
   608 
   609