First public contribution.
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".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
14 // e32test\prime\t_rwlock.cpp
16 // Test the RReadWriteLock type.
20 // Test all functions individually and in combination.
21 // Platforms/Drives/Compatibility:
23 // Assumptions/Requirement/Pre-requisites:
24 // Failures and causes:
25 // Base Port information:
29 //! @SYMTestCaseID KBASE-T_RWLOCK-2444
31 //! @SYMTestCaseDesc Verify correct operation of RReadWriteLock
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
38 #include <e32atomics.h>
42 #include <e32def_private.h>
44 RTest Test(_L("T_RWLOCK"));
45 RReadWriteLock TheLock;
46 volatile TInt ThreadsRunning;
50 // Check creating, using and closing a lock doesn't leak memory
53 Test.Next(_L("Creation"));
58 Test(TheLock.CreateLocal() == KErrNone);
69 TInt ReadEntryPoint(TAny* aArg)
71 *(TBool*)aArg = ETrue;
72 __e32_atomic_add_ord32(&ThreadsRunning, 1);
74 const TInt index = __e32_atomic_add_ord32(&LogIndex, 1);
75 LogReaders[index] = ETrue;
77 __e32_atomic_add_ord32(&ThreadsRunning, TUint32(-1));
81 TInt WriteEntryPoint(TAny* aArg)
83 *(TBool*)aArg = ETrue;
84 __e32_atomic_add_ord32(&ThreadsRunning, 1);
86 const TInt index = __e32_atomic_add_ord32(&LogIndex, 1);
87 LogReaders[index] = EFalse;
89 __e32_atomic_add_ord32(&ThreadsRunning, TUint32(-1));
95 __e32_atomic_store_ord32(&ThreadsRunning, 0);
96 __e32_atomic_store_ord32(&LogIndex, 0);
99 void CreateThread(TBool aReader)
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);
107 while (!threadStarted)
112 void WaitForThreadsToClose(TInt aThreads = 0)
114 while (ThreadsRunning > aThreads)
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()
125 Test.Next(_L("Writer Priority"));
126 TInt ret = TheLock.CreateLocal(RReadWriteLock::EWriterPriority);
127 Test(ret == KErrNone, __LINE__);
133 CreateThread(EFalse);
135 CreateThread(EFalse);
137 CreateThread(EFalse);
139 CreateThread(EFalse);
143 WaitForThreadsToClose();
146 CreateThread(EFalse);
149 CreateThread(EFalse);
153 WaitForThreadsToClose();
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++)
161 Test(LogReaders[index] == expected[index], __LINE__);
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()
170 Test.Next(_L("Alternate Priority"));
171 TInt ret = TheLock.CreateLocal(RReadWriteLock::EAlternatePriority);
172 Test(ret == KErrNone, __LINE__);
181 CreateThread(EFalse);
182 CreateThread(EFalse);
183 CreateThread(EFalse);
184 CreateThread(EFalse);
185 CreateThread(EFalse);
188 WaitForThreadsToClose();
191 CreateThread(EFalse);
194 CreateThread(EFalse);
198 WaitForThreadsToClose();
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++)
206 Test(LogReaders[index] == expected[index], __LINE__);
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()
215 Test.Next(_L("Reader Priority"));
216 TInt ret = TheLock.CreateLocal(RReadWriteLock::EReaderPriority);
217 Test(ret == KErrNone, __LINE__);
223 CreateThread(EFalse);
225 CreateThread(EFalse);
227 CreateThread(EFalse);
229 CreateThread(EFalse);
233 WaitForThreadsToClose();
236 CreateThread(EFalse);
239 CreateThread(EFalse);
243 WaitForThreadsToClose();
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++)
251 Test(LogReaders[index] == expected[index], __LINE__);
255 void DoTestTryLock(TBool aWriterFirst)
259 TBool tryLock = TheLock.TryWriteLock();
260 Test(!tryLock, __LINE__);
262 tryLock = TheLock.TryReadLock();
263 Test(tryLock, __LINE__);
267 CreateThread(EFalse);
268 tryLock = TheLock.TryReadLock();
271 Test(!aWriterFirst, __LINE__);
276 Test(aWriterFirst, __LINE__);
278 tryLock = TheLock.TryWriteLock();
279 Test(!tryLock, __LINE__);
282 WaitForThreadsToClose();
286 tryLock = TheLock.TryReadLock();
287 Test(!tryLock, __LINE__);
288 tryLock = TheLock.TryWriteLock();
289 Test(!tryLock, __LINE__);
295 // Check that the TryReadLock and TryWriteLock functions block only when they
296 // should for the different types of priority
299 Test.Next(_L("Try Lock"));
301 TInt ret = TheLock.CreateLocal(RReadWriteLock::EWriterPriority);
302 Test(ret == KErrNone, __LINE__);
303 DoTestTryLock(ETrue);
305 ret = TheLock.CreateLocal(RReadWriteLock::EAlternatePriority);
306 Test(ret == KErrNone, __LINE__);
307 DoTestTryLock(ETrue);
309 ret = TheLock.CreateLocal(RReadWriteLock::EReaderPriority);
310 Test(ret == KErrNone, __LINE__);
311 DoTestTryLock(EFalse);
316 void DoTestUpgrade(RReadWriteLock::TReadWriteLockPriority aPriority)
318 TInt ret = TheLock.CreateLocal(aPriority);
319 Test(ret == KErrNone, __LINE__);
322 TBool success = TheLock.TryUpgradeReadLock();
323 Test(success, __LINE__);
328 success = TheLock.TryUpgradeReadLock();
329 Test(!success, __LINE__);
335 CreateThread(EFalse);
336 success = TheLock.TryUpgradeReadLock();
337 Test(success || !(aPriority == RReadWriteLock::EReaderPriority), __LINE__);
340 WaitForThreadsToClose();
344 // Check that upgrading a lock succeeds only when it should
347 Test.Next(_L("Upgrade Lock"));
349 DoTestUpgrade(RReadWriteLock::EWriterPriority);
350 DoTestUpgrade(RReadWriteLock::EAlternatePriority);
351 DoTestUpgrade(RReadWriteLock::EReaderPriority);
354 void DoTestDowngrade(RReadWriteLock::TReadWriteLockPriority aPriority)
356 TInt ret = TheLock.CreateLocal(aPriority);
357 Test(ret == KErrNone, __LINE__);
362 CreateThread(EFalse);
364 CreateThread(EFalse);
366 TheLock.DowngradeWriteLock();
370 case RReadWriteLock::EWriterPriority:
371 case RReadWriteLock::EAlternatePriority:
373 Test(LogIndex == 0, __LINE__);
376 case RReadWriteLock::EReaderPriority:
378 WaitForThreadsToClose(2);
379 Test(LogIndex == 2, __LINE__);
380 Test(LogReaders[0], __LINE__);
381 Test(LogReaders[1], __LINE__);
387 CreateThread(EFalse);
389 CreateThread(EFalse);
392 WaitForThreadsToClose();
395 Test(LogIndex == 8, __LINE__);
399 case RReadWriteLock::EWriterPriority:
401 const TInt expected[] = { EFalse, EFalse, EFalse, EFalse, ETrue, ETrue, ETrue, ETrue };
402 for (TInt index = 0; index < LogIndex; index++)
404 Test(LogReaders[index] == expected[index], __LINE__);
408 case RReadWriteLock::EAlternatePriority:
410 const TInt expected[] = { EFalse, ETrue, EFalse, ETrue, EFalse, ETrue, EFalse, ETrue };
411 for (TInt index = 0; index < LogIndex; index++)
413 Test(LogReaders[index] == expected[index], __LINE__);
417 case RReadWriteLock::EReaderPriority:
419 const TInt expected[] = { ETrue, ETrue, ETrue, ETrue, EFalse, EFalse, EFalse, EFalse };
420 for (TInt index = 0; index < LogIndex; index++)
422 Test(LogReaders[index] == expected[index], __LINE__);
429 // Check that downgrading a lock succeeds only when it should
432 Test.Next(_L("Downgrade Lock"));
434 DoTestDowngrade(RReadWriteLock::EWriterPriority);
435 DoTestDowngrade(RReadWriteLock::EAlternatePriority);
436 DoTestDowngrade(RReadWriteLock::EReaderPriority);
439 TInt PanicEntryPoint(TAny* aArg)
443 case 0: // Check priority lower bound
444 TheLock.CreateLocal(RReadWriteLock::TReadWriteLockPriority(RReadWriteLock::EWriterPriority-1));
446 case 1: // Check priority upper bound
447 TheLock.CreateLocal(RReadWriteLock::TReadWriteLockPriority(RReadWriteLock::EReaderPriority+1));
449 case 2: // Check close while holding read lock
450 TheLock.CreateLocal(RReadWriteLock::TReadWriteLockPriority(RReadWriteLock::EAlternatePriority));
454 case 3: // Check close while holding write lock
455 TheLock.CreateLocal(RReadWriteLock::TReadWriteLockPriority(RReadWriteLock::EAlternatePriority));
459 case 4: // Check max readers
460 TheLock.CreateLocal(RReadWriteLock::TReadWriteLockPriority(RReadWriteLock::EReaderPriority));
462 for (TInt count = 0; count < RReadWriteLock::EReadWriteLockClientCategoryLimit; count++)
467 case 5: // Check max pending readers
468 TheLock.CreateLocal(RReadWriteLock::TReadWriteLockPriority(RReadWriteLock::EReaderPriority));
471 TUint16* hackLock = (TUint16*)&TheLock;
472 hackLock[2] = KMaxTUint16; // Hack readers pending field
476 case 6: // Check max pending writers
477 TheLock.CreateLocal(RReadWriteLock::TReadWriteLockPriority(RReadWriteLock::EReaderPriority));
480 TUint16* hackLock = (TUint16*)&TheLock;
481 hackLock[3] = KMaxTUint16; // Hack writers pending field
485 case 7: // Check lock held when unlocking
486 TheLock.CreateLocal(RReadWriteLock::TReadWriteLockPriority(RReadWriteLock::EAlternatePriority));
489 case 8: // Check lock held when unlocking after read lock/unlock
490 TheLock.CreateLocal(RReadWriteLock::TReadWriteLockPriority(RReadWriteLock::EAlternatePriority));
495 case 9: // Check lock held when unlocking after write lock/unlock
496 TheLock.CreateLocal(RReadWriteLock::TReadWriteLockPriority(RReadWriteLock::EAlternatePriority));
505 return KErrNotSupported;
508 TBool CreatePanicThread(TInt aTest)
510 User::SetJustInTime(EFalse);
511 TBool finished = EFalse;
514 TInt ret = panicThread.Create(KNullDesC, PanicEntryPoint, KDefaultStackSize, KMinHeapSize, KMinHeapSize, (TAny*)aTest, EOwnerThread);
515 Test(ret == KErrNone, __LINE__);
516 panicThread.Resume();
519 panicThread.Logon(stat);
520 User::WaitForRequest(stat);
521 User::SetJustInTime(ETrue);
523 if (panicThread.ExitType() == EExitPanic)
530 panicValue = EReadWriteLockInvalidPriority;
534 panicValue = EReadWriteLockStillPending;
539 panicValue = EReadWriteLockTooManyClients;
544 panicValue = EReadWriteLockBadLockState;
551 Test(stat == panicValue, __LINE__);
552 Test(panicThread.ExitReason() == panicValue, __LINE__);
556 Test(stat == KErrNone, __LINE__);
560 RTest::CloseHandleAndWaitForDestruction(panicThread);
564 case 2: // Check close while holding read lock
565 case 3: // Check close while holding write lock
569 case 4: // Check max readers
571 for (TInt count = 0; count < RReadWriteLock::EReadWriteLockClientCategoryLimit; count++)
576 case 5: // Check max pending readers
577 case 6: // Check max pending writers
579 TUint16* hackLock = (TUint16*)&TheLock;
580 hackLock[2] = 0; // Reset readers pending field
581 hackLock[3] = 0; // Reset writers pending field
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
597 // Check that the various asserts guarding invalid conditions can be reached
600 Test.Next(_L("Panics"));
602 for (TInt testIndex = 0; !CreatePanicThread(testIndex); testIndex++) ;
608 Test.Start(_L("RReadWriteLock Testing"));
611 TestWriterPriority();
612 TestAlternatePriority();
613 TestReaderPriority();