os/kernelhwsrv/kerneltest/e32test/prime/t_rwlock.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 // Copyright (c) 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_rwlock.cpp
    15 // Overview:
    16 // Test the RReadWriteLock type.
    17 // API Information:
    18 // RReadWriteLock
    19 // Details:
    20 // Test all functions individually and in combination.
    21 // Platforms/Drives/Compatibility:
    22 // All.
    23 // Assumptions/Requirement/Pre-requisites:
    24 // Failures and causes:
    25 // Base Port information:
    26 // 
    27 //
    28 
    29 //! @SYMTestCaseID             KBASE-T_RWLOCK-2444
    30 //! @SYMTestType               UT
    31 //! @SYMTestCaseDesc           Verify correct operation of RReadWriteLock
    32 //! @SYMPREQ                   PREQ2094
    33 //! @SYMTestPriority           High
    34 //! @SYMTestActions            Call all functions of RReadWriteLock in a variety
    35 //!                            of circumstances and verify correct results                                            
    36 //! @SYMTestExpectedResults    All tests pass
    37 
    38 #include <e32atomics.h>
    39 #include <e32test.h>
    40 #include <e32panic.h>
    41 #include <e32def.h>
    42 #include <e32def_private.h>
    43 
    44 RTest Test(_L("T_RWLOCK"));
    45 RReadWriteLock TheLock;
    46 volatile TInt ThreadsRunning;
    47 TInt LogIndex;
    48 TBool LogReaders[20];
    49 
    50 // Check creating, using and closing a lock doesn't leak memory
    51 void TestCreation()
    52 	{
    53 	Test.Next(_L("Creation"));
    54 	
    55     __KHEAP_MARK;
    56     __UHEAP_MARK;
    57 
    58 	Test(TheLock.CreateLocal() == KErrNone);
    59 	TheLock.ReadLock();
    60 	TheLock.Unlock();
    61 	TheLock.WriteLock();
    62 	TheLock.Unlock();
    63 	TheLock.Close();
    64 
    65 	__UHEAP_MARKEND;
    66 	__KHEAP_MARKEND;
    67 	}
    68 
    69 TInt ReadEntryPoint(TAny* aArg)
    70 	{
    71 	*(TBool*)aArg = ETrue;
    72 	__e32_atomic_add_ord32(&ThreadsRunning, 1);
    73 	TheLock.ReadLock();
    74 	const TInt index = __e32_atomic_add_ord32(&LogIndex, 1);
    75 	LogReaders[index] = ETrue;
    76 	TheLock.Unlock();
    77 	__e32_atomic_add_ord32(&ThreadsRunning, TUint32(-1));
    78 	return KErrNone;
    79 	}
    80 
    81 TInt WriteEntryPoint(TAny* aArg)
    82 	{
    83 	*(TBool*)aArg = ETrue;
    84 	__e32_atomic_add_ord32(&ThreadsRunning, 1);
    85 	TheLock.WriteLock();
    86 	const TInt index = __e32_atomic_add_ord32(&LogIndex, 1);
    87 	LogReaders[index] = EFalse;
    88 	TheLock.Unlock();
    89 	__e32_atomic_add_ord32(&ThreadsRunning, TUint32(-1));
    90 	return KErrNone;
    91 	}
    92 
    93 void Init()
    94 	{
    95 	__e32_atomic_store_ord32(&ThreadsRunning, 0);
    96 	__e32_atomic_store_ord32(&LogIndex, 0);
    97 	}
    98 
    99 void CreateThread(TBool aReader)
   100 	{
   101 	RThread newThread;
   102 	TBool threadStarted = EFalse;
   103 	TInt ret = newThread.Create(KNullDesC, aReader ? ReadEntryPoint : WriteEntryPoint, KDefaultStackSize, KMinHeapSize, KMinHeapSize, &threadStarted, EOwnerProcess);
   104 	Test(ret == KErrNone, __LINE__);
   105 	newThread.SetPriority(EPriorityMore);
   106 	newThread.Resume();
   107 	while (!threadStarted)
   108 		User::After(1000);
   109 	newThread.Close();
   110 	}
   111 
   112 void WaitForThreadsToClose(TInt aThreads = 0)
   113 	{
   114 	while (ThreadsRunning > aThreads)
   115 		{
   116 		User::After(1000);
   117 		}
   118 	}
   119 
   120 // Check that queuing multiple reads and writes on a lock with writer priority
   121 // results in the correct type of client being released in the correct order
   122 // (can' predict exact client order on multi-processor systems though)
   123 void TestWriterPriority()
   124 	{
   125 	Test.Next(_L("Writer Priority"));
   126 	TInt ret = TheLock.CreateLocal(RReadWriteLock::EWriterPriority);
   127 	Test(ret == KErrNone, __LINE__);
   128 	TheLock.WriteLock();
   129 
   130 	Init();
   131 	CreateThread(ETrue);
   132 	CreateThread(ETrue);
   133 	CreateThread(EFalse);
   134 	CreateThread(ETrue);
   135 	CreateThread(EFalse);
   136 	CreateThread(ETrue);
   137 	CreateThread(EFalse);
   138 	CreateThread(ETrue);
   139 	CreateThread(EFalse);
   140 	CreateThread(ETrue);
   141 
   142 	TheLock.Unlock();
   143 	WaitForThreadsToClose();
   144 	TheLock.ReadLock();
   145 
   146 	CreateThread(EFalse);
   147 	CreateThread(ETrue);
   148 	CreateThread(ETrue);
   149 	CreateThread(EFalse);
   150 	CreateThread(ETrue);
   151 
   152 	TheLock.Unlock();
   153 	WaitForThreadsToClose();
   154 
   155 	TheLock.Close();
   156 
   157 	Test(LogIndex == 15, __LINE__);
   158 	const TBool expected[] = { EFalse, EFalse, EFalse, EFalse, ETrue, ETrue, ETrue, ETrue, ETrue, ETrue, EFalse, EFalse, ETrue, ETrue, ETrue };
   159 	for (TInt index = 0; index < LogIndex; index++)
   160 		{
   161 		Test(LogReaders[index] == expected[index], __LINE__);
   162 		}
   163 	}
   164 
   165 // Check that queuing multiple reads and writes on a lock with alternate priority
   166 // results in the correct type of client being released in the correct order
   167 // (can' predict exact client order on multi-processor systems though)
   168 void TestAlternatePriority()
   169 	{
   170 	Test.Next(_L("Alternate Priority"));
   171 	TInt ret = TheLock.CreateLocal(RReadWriteLock::EAlternatePriority);
   172 	Test(ret == KErrNone, __LINE__);
   173 	TheLock.WriteLock();
   174 
   175 	Init();
   176 	CreateThread(ETrue);
   177 	CreateThread(ETrue);
   178 	CreateThread(ETrue);
   179 	CreateThread(ETrue);
   180 	CreateThread(ETrue);
   181 	CreateThread(EFalse);
   182 	CreateThread(EFalse);
   183 	CreateThread(EFalse);
   184 	CreateThread(EFalse);
   185 	CreateThread(EFalse);
   186 
   187 	TheLock.Unlock();
   188 	WaitForThreadsToClose();
   189 	TheLock.ReadLock();
   190 
   191 	CreateThread(EFalse);
   192 	CreateThread(ETrue);
   193 	CreateThread(ETrue);
   194 	CreateThread(EFalse);
   195 	CreateThread(ETrue);
   196 
   197 	TheLock.Unlock();
   198 	WaitForThreadsToClose();
   199 
   200 	TheLock.Close();
   201 
   202 	Test(LogIndex == 15, __LINE__);
   203 	const TInt expected[] = { ETrue, EFalse, ETrue, EFalse, ETrue, EFalse, ETrue, EFalse, ETrue, EFalse, EFalse, ETrue, EFalse, ETrue, ETrue };
   204 	for (TInt index = 0; index < LogIndex; index++)
   205 		{
   206 		Test(LogReaders[index] == expected[index], __LINE__);
   207 		}
   208 	}
   209 
   210 // Check that queuing multiple reads and writes on a lock with reader priority
   211 // results in the correct type of client being released in the correct order
   212 // (can' predict exact client order on multi-processor systems though)
   213 void TestReaderPriority()
   214 	{
   215 	Test.Next(_L("Reader Priority"));
   216 	TInt ret = TheLock.CreateLocal(RReadWriteLock::EReaderPriority);
   217 	Test(ret == KErrNone, __LINE__);
   218 	TheLock.WriteLock();
   219 
   220 	Init();
   221 	CreateThread(ETrue);
   222 	CreateThread(ETrue);
   223 	CreateThread(EFalse);
   224 	CreateThread(ETrue);
   225 	CreateThread(EFalse);
   226 	CreateThread(ETrue);
   227 	CreateThread(EFalse);
   228 	CreateThread(ETrue);
   229 	CreateThread(EFalse);
   230 	CreateThread(ETrue);
   231 
   232 	TheLock.Unlock();
   233 	WaitForThreadsToClose();
   234 	TheLock.WriteLock();
   235 
   236 	CreateThread(EFalse);
   237 	CreateThread(ETrue);
   238 	CreateThread(ETrue);
   239 	CreateThread(EFalse);
   240 	CreateThread(ETrue);
   241 
   242 	TheLock.Unlock();
   243 	WaitForThreadsToClose();
   244 
   245 	TheLock.Close();
   246 
   247 	Test(LogIndex == 15, __LINE__);
   248 	const TInt expected[] = { ETrue, ETrue, ETrue, ETrue, ETrue, ETrue, EFalse, EFalse, EFalse, EFalse, ETrue, ETrue, ETrue, EFalse, EFalse };
   249 	for (TInt index = 0; index < LogIndex; index++)
   250 		{
   251 		Test(LogReaders[index] == expected[index], __LINE__);
   252 		}
   253 	}
   254 
   255 void DoTestTryLock(TBool aWriterFirst)
   256 	{
   257 	TheLock.ReadLock();
   258 
   259 		TBool tryLock = TheLock.TryWriteLock();
   260 		Test(!tryLock, __LINE__);
   261 
   262 			tryLock = TheLock.TryReadLock();
   263 			Test(tryLock, __LINE__);
   264 			TheLock.Unlock();
   265 
   266 		Init();
   267 		CreateThread(EFalse);
   268 		tryLock = TheLock.TryReadLock();
   269 		if (tryLock)
   270 			{
   271 			Test(!aWriterFirst, __LINE__);
   272 			TheLock.Unlock();
   273 			}
   274 		else
   275 			{
   276 			Test(aWriterFirst, __LINE__);
   277 			}
   278 		tryLock = TheLock.TryWriteLock();
   279 		Test(!tryLock, __LINE__);
   280 
   281 	TheLock.Unlock();
   282 	WaitForThreadsToClose();
   283 
   284 	TheLock.WriteLock();
   285 
   286 		tryLock = TheLock.TryReadLock();
   287 		Test(!tryLock, __LINE__);
   288 		tryLock = TheLock.TryWriteLock();
   289 		Test(!tryLock, __LINE__);
   290 
   291 	TheLock.Unlock();
   292 	TheLock.Close();
   293 	}
   294 
   295 // Check that the TryReadLock and TryWriteLock functions block only when they
   296 // should for the different types of priority
   297 void TestTryLock()
   298 	{
   299 	Test.Next(_L("Try Lock"));
   300 
   301 	TInt ret = TheLock.CreateLocal(RReadWriteLock::EWriterPriority);
   302 	Test(ret == KErrNone, __LINE__);
   303 	DoTestTryLock(ETrue);
   304 
   305 	ret = TheLock.CreateLocal(RReadWriteLock::EAlternatePriority);
   306 	Test(ret == KErrNone, __LINE__);
   307 	DoTestTryLock(ETrue);
   308 
   309 	ret = TheLock.CreateLocal(RReadWriteLock::EReaderPriority);
   310 	Test(ret == KErrNone, __LINE__);
   311 	DoTestTryLock(EFalse);
   312 
   313 	TheLock.Close();
   314 	}
   315 
   316 void DoTestUpgrade(RReadWriteLock::TReadWriteLockPriority aPriority)
   317 	{
   318 	TInt ret = TheLock.CreateLocal(aPriority);
   319 	Test(ret == KErrNone, __LINE__);
   320 	TheLock.ReadLock();
   321 
   322 	TBool success = TheLock.TryUpgradeReadLock();
   323 	Test(success, __LINE__);
   324 	TheLock.Unlock();
   325 
   326 	TheLock.ReadLock();
   327 	TheLock.ReadLock();
   328 	success = TheLock.TryUpgradeReadLock();
   329 	Test(!success, __LINE__);
   330 	TheLock.Unlock();
   331 	TheLock.Unlock();
   332 
   333 	TheLock.ReadLock();
   334 	Init();
   335 	CreateThread(EFalse);
   336 	success = TheLock.TryUpgradeReadLock();
   337 	Test(success || !(aPriority == RReadWriteLock::EReaderPriority), __LINE__);
   338 
   339 	TheLock.Unlock();
   340 	WaitForThreadsToClose();
   341 	TheLock.Close();
   342 	}
   343 
   344 // Check that upgrading a lock succeeds only when it should
   345 void TestUpgrade()
   346 	{
   347 	Test.Next(_L("Upgrade Lock"));
   348 
   349 	DoTestUpgrade(RReadWriteLock::EWriterPriority);
   350 	DoTestUpgrade(RReadWriteLock::EAlternatePriority);
   351 	DoTestUpgrade(RReadWriteLock::EReaderPriority);
   352 	}
   353 
   354 void DoTestDowngrade(RReadWriteLock::TReadWriteLockPriority aPriority)
   355 	{
   356 	TInt ret = TheLock.CreateLocal(aPriority);
   357 	Test(ret == KErrNone, __LINE__);
   358 	TheLock.WriteLock();
   359 
   360 	Init();
   361 	CreateThread(ETrue);
   362 	CreateThread(EFalse);
   363 	CreateThread(ETrue);
   364 	CreateThread(EFalse);
   365 
   366 	TheLock.DowngradeWriteLock();
   367 
   368 	switch (aPriority)
   369 		{
   370 	case RReadWriteLock::EWriterPriority:
   371 	case RReadWriteLock::EAlternatePriority:
   372 		{
   373 		Test(LogIndex == 0, __LINE__);
   374 		break;
   375 		}
   376 	case RReadWriteLock::EReaderPriority:
   377 		{
   378 		WaitForThreadsToClose(2);
   379 		Test(LogIndex == 2, __LINE__);
   380 		Test(LogReaders[0], __LINE__);
   381 		Test(LogReaders[1], __LINE__);
   382 		break;
   383 		}
   384 		};
   385 
   386 	CreateThread(ETrue);
   387 	CreateThread(EFalse);
   388 	CreateThread(ETrue);
   389 	CreateThread(EFalse);
   390 
   391 	TheLock.Unlock();
   392 	WaitForThreadsToClose();
   393 	TheLock.Close();
   394 
   395 	Test(LogIndex == 8, __LINE__);
   396 
   397 	switch (aPriority)
   398 		{
   399 	case RReadWriteLock::EWriterPriority:
   400 		{
   401 		const TInt expected[] = { EFalse, EFalse, EFalse, EFalse, ETrue, ETrue, ETrue, ETrue };
   402 		for (TInt index = 0; index < LogIndex; index++)
   403 			{
   404 			Test(LogReaders[index] == expected[index], __LINE__);
   405 			}
   406 		break;
   407 		}
   408 	case RReadWriteLock::EAlternatePriority:
   409 		{
   410 		const TInt expected[] = { EFalse, ETrue, EFalse, ETrue, EFalse, ETrue, EFalse, ETrue };
   411 		for (TInt index = 0; index < LogIndex; index++)
   412 			{
   413 			Test(LogReaders[index] == expected[index], __LINE__);
   414 			}
   415 		break;
   416 		}
   417 	case RReadWriteLock::EReaderPriority:
   418 		{
   419 		const TInt expected[] = { ETrue, ETrue, ETrue, ETrue, EFalse, EFalse, EFalse, EFalse };
   420 		for (TInt index = 0; index < LogIndex; index++)
   421 			{
   422 			Test(LogReaders[index] == expected[index], __LINE__);
   423 			}
   424 		break;
   425 		}
   426 		};
   427 	}
   428 
   429 // Check that downgrading a lock succeeds only when it should
   430 void TestDowngrade()
   431 	{
   432 	Test.Next(_L("Downgrade Lock"));
   433 
   434 	DoTestDowngrade(RReadWriteLock::EWriterPriority);
   435 	DoTestDowngrade(RReadWriteLock::EAlternatePriority);
   436 	DoTestDowngrade(RReadWriteLock::EReaderPriority);
   437 	}
   438 
   439 TInt PanicEntryPoint(TAny* aArg)
   440 	{
   441 	switch (TInt(aArg))
   442 		{
   443 		case 0: // Check priority lower bound
   444 			TheLock.CreateLocal(RReadWriteLock::TReadWriteLockPriority(RReadWriteLock::EWriterPriority-1));
   445 			break;
   446 		case 1: // Check priority upper bound
   447 			TheLock.CreateLocal(RReadWriteLock::TReadWriteLockPriority(RReadWriteLock::EReaderPriority+1));
   448 			break;
   449 		case 2: // Check close while holding read lock
   450 			TheLock.CreateLocal(RReadWriteLock::TReadWriteLockPriority(RReadWriteLock::EAlternatePriority));
   451 			TheLock.ReadLock();
   452 			TheLock.Close();
   453 			break;
   454 		case 3: // Check close while holding write lock
   455 			TheLock.CreateLocal(RReadWriteLock::TReadWriteLockPriority(RReadWriteLock::EAlternatePriority));
   456 			TheLock.WriteLock();
   457 			TheLock.Close();
   458 			break;
   459 		case 4: // Check max readers
   460 			TheLock.CreateLocal(RReadWriteLock::TReadWriteLockPriority(RReadWriteLock::EReaderPriority));
   461 			{
   462 			for (TInt count = 0; count < RReadWriteLock::EReadWriteLockClientCategoryLimit; count++)
   463 				TheLock.ReadLock();
   464 			}
   465 			TheLock.ReadLock();
   466 			break;
   467 		case 5: // Check max pending readers
   468 			TheLock.CreateLocal(RReadWriteLock::TReadWriteLockPriority(RReadWriteLock::EReaderPriority));
   469 			TheLock.WriteLock();
   470 			{
   471 			TUint16* hackLock = (TUint16*)&TheLock;
   472 			hackLock[2] = KMaxTUint16; // Hack readers pending field
   473 			}
   474 			TheLock.ReadLock();
   475 			break;
   476 		case 6: // Check max pending writers
   477 			TheLock.CreateLocal(RReadWriteLock::TReadWriteLockPriority(RReadWriteLock::EReaderPriority));
   478 			TheLock.ReadLock();
   479 			{
   480 			TUint16* hackLock = (TUint16*)&TheLock;
   481 			hackLock[3] = KMaxTUint16; // Hack writers pending field
   482 			}
   483 			TheLock.WriteLock();
   484 			break;
   485 		case 7: // Check lock held when unlocking
   486 			TheLock.CreateLocal(RReadWriteLock::TReadWriteLockPriority(RReadWriteLock::EAlternatePriority));
   487 			TheLock.Unlock();
   488 			break;
   489 		case 8: // Check lock held when unlocking after read lock/unlock
   490 			TheLock.CreateLocal(RReadWriteLock::TReadWriteLockPriority(RReadWriteLock::EAlternatePriority));
   491 			TheLock.ReadLock();
   492 			TheLock.Unlock();
   493 			TheLock.Unlock();
   494 			break;
   495 		case 9: // Check lock held when unlocking after write lock/unlock
   496 			TheLock.CreateLocal(RReadWriteLock::TReadWriteLockPriority(RReadWriteLock::EAlternatePriority));
   497 			TheLock.WriteLock();
   498 			TheLock.Unlock();
   499 			TheLock.Unlock();
   500 			break;
   501 		default:
   502 			return KErrNone;
   503 		};
   504 
   505 	return KErrNotSupported;
   506 	}
   507 
   508 TBool CreatePanicThread(TInt aTest)
   509 	{
   510 	User::SetJustInTime(EFalse);
   511 	TBool finished = EFalse;
   512 
   513 	RThread panicThread;
   514 	TInt ret = panicThread.Create(KNullDesC, PanicEntryPoint, KDefaultStackSize, KMinHeapSize, KMinHeapSize, (TAny*)aTest, EOwnerThread);
   515 	Test(ret == KErrNone, __LINE__);
   516 	panicThread.Resume();
   517 
   518 	TRequestStatus stat;
   519 	panicThread.Logon(stat);
   520 	User::WaitForRequest(stat);
   521 	User::SetJustInTime(ETrue);
   522 
   523 	if (panicThread.ExitType() == EExitPanic)
   524 		{
   525 		TInt panicValue = 0;
   526 		switch (aTest)
   527 			{
   528 		case 0:
   529 		case 1:
   530 			panicValue = EReadWriteLockInvalidPriority;
   531 			break;
   532 		case 2:
   533 		case 3:
   534 			panicValue = EReadWriteLockStillPending;
   535 			break;
   536 		case 4:
   537 		case 5:
   538 		case 6:
   539 			panicValue = EReadWriteLockTooManyClients;
   540 			break;
   541 		case 7:
   542 		case 8:
   543 		case 9:
   544 			panicValue = EReadWriteLockBadLockState;
   545 			break;
   546 		default:
   547 			Test(0, __LINE__);
   548 			break;
   549 			};
   550 	
   551 		Test(stat == panicValue, __LINE__);
   552 		Test(panicThread.ExitReason() == panicValue, __LINE__);
   553 		}
   554 	else
   555 		{
   556 		Test(stat == KErrNone, __LINE__);
   557 		finished = ETrue;
   558 		}
   559 
   560 	RTest::CloseHandleAndWaitForDestruction(panicThread);
   561 	
   562 	switch (aTest)
   563 		{
   564 		case 2: // Check close while holding read lock
   565 		case 3: // Check close while holding write lock
   566 			TheLock.Unlock();
   567 			TheLock.Close();
   568 			break;
   569 		case 4: // Check max readers
   570 			{
   571 			for (TInt count = 0; count < RReadWriteLock::EReadWriteLockClientCategoryLimit; count++)
   572 				TheLock.Unlock();
   573 			}
   574 			TheLock.Close();
   575 			break;
   576 		case 5: // Check max pending readers
   577 		case 6: // Check max pending writers
   578 			{
   579 			TUint16* hackLock = (TUint16*)&TheLock;
   580 			hackLock[2] = 0; // Reset readers pending field
   581 			hackLock[3] = 0; // Reset writers pending field
   582 			}
   583 			TheLock.Unlock();
   584 			TheLock.Close();
   585 			break;
   586 		case 7: // Check lock held when unlocking
   587 		case 8: // Check lock held when unlocking after read lock/unlock
   588 		case 9: // Check lock held when unlocking after write lock/unlock
   589 			TheLock.Close();
   590 			break;
   591 		default:
   592 			break;
   593 		};
   594 	return finished;
   595 	}
   596 
   597 // Check that the various asserts guarding invalid conditions can be reached
   598 void TestPanics()
   599 	{
   600 	Test.Next(_L("Panics"));
   601 
   602 	for (TInt testIndex = 0; !CreatePanicThread(testIndex); testIndex++) ;
   603 	}
   604 
   605 TInt E32Main()
   606     {
   607 	Test.Title();
   608 	Test.Start(_L("RReadWriteLock Testing"));
   609 
   610 	TestCreation();
   611 	TestWriterPriority();
   612 	TestAlternatePriority();
   613 	TestReaderPriority();
   614 	TestTryLock();
   615 	TestUpgrade();
   616 	TestDowngrade();
   617 	TestPanics();
   618 
   619 	Test.End();
   620 	return KErrNone;
   621     }
   622 
   623