1 /* 2 $Id: ConcurrencyTest1.cpp 301 2002-07-18 05:32:00Z tylerdauwalder $ 3 4 This file implements a test class for testing BLocker functionality. 5 It tests use cases "Locking 1", "Locking 2", "Unlocking", "Is Locked", 6 "Locking Thread" and "Count Locks". 7 8 */ 9 10 11 #include <ThreadedTestCaller.h> 12 #include "ConcurrencyTest1.h" 13 #include <cppunit/TestSuite.h> 14 #include <Locker.h> 15 16 17 // This constant indicates the number of times the thread should test the 18 // acquisition and release of the BLocker. 19 20 const int32 MAXLOOP = 10000; 21 22 23 /* 24 * Method: ConcurrencyTest1::ConcurrencyTest1() 25 * Descr: This is the only constructor for this test case. It takes a 26 * test name and a flag to indicate whether to test a benaphore 27 * or semaphore type BLocker. 28 */ 29 30 31 ConcurrencyTest1::ConcurrencyTest1(std::string name, bool benaphoreFlag) : 32 LockerTestCase(name, benaphoreFlag), lockTestValue(false) 33 { 34 } 35 36 37 /* 38 * Method: ConcurrencyTest1::~ConcurrencyTest1() 39 * Descr: This is the descriptor for this test case. 40 */ 41 42 43 ConcurrencyTest1::~ConcurrencyTest1() 44 { 45 } 46 47 48 /* 49 * Method: ConcurrencyTest1::setUp() 50 * Descr: This member is called before starting the actual test threads 51 * and is used to ensure that the class is initialized for the 52 * testing. It just sets the "lockTestValue" flag to false. This 53 * flag is used to show that there is mutual exclusion between the 54 * threads. 55 */ 56 57 void 58 ConcurrencyTest1::setUp(void) 59 { 60 lockTestValue = false; 61 } 62 63 64 /* 65 * Method: ConcurrencyTest1::suite() 66 * Descr: This static member function returns a test suite for performing 67 * all combinations of "ConcurrencyTest1". The test suite contains 68 * two instances of the test. One is performed on a benaphore, 69 * the other on a semaphore based BLocker. Each individual test 70 * is created as a ThreadedTestCase (typedef'd as 71 * ConcurrencyTest1Caller) with three independent threads. 72 */ 73 74 CppUnit::Test *ConcurrencyTest1::suite(void) 75 { 76 typedef BThreadedTestCaller<ConcurrencyTest1> 77 ConcurrencyTest1Caller; 78 79 80 CppUnit::TestSuite *testSuite = new CppUnit::TestSuite("ConcurrencyTest1"); 81 82 // Make a benaphore based test object, create a ThreadedTestCase for it and add 83 // three threads to it. 84 ConcurrencyTest1 *theTest = new ConcurrencyTest1("Benaphore", true); 85 ConcurrencyTest1Caller *threadedTest1 = new ConcurrencyTest1Caller("BLocker::Concurrency Test #1 (benaphore)", theTest); 86 threadedTest1->addThread("A", &ConcurrencyTest1::TestThread); 87 threadedTest1->addThread("B", &ConcurrencyTest1::TestThread); 88 threadedTest1->addThread("C", &ConcurrencyTest1::TestThread); 89 90 // Make a semaphore based test object, create a ThreadedTestCase for it and add 91 // three threads to it. 92 theTest = new ConcurrencyTest1("Semaphore", false); 93 ConcurrencyTest1Caller *threadedTest2 = new ConcurrencyTest1Caller("BLocker::Concurrency Test #1 (semaphore)", theTest); 94 threadedTest2->addThread("A", &ConcurrencyTest1::TestThread); 95 threadedTest2->addThread("B", &ConcurrencyTest1::TestThread); 96 threadedTest2->addThread("C", &ConcurrencyTest1::TestThread); 97 98 testSuite->addTest(threadedTest1); 99 testSuite->addTest(threadedTest2); 100 return(testSuite); 101 } 102 103 104 /* 105 * Method: ConcurrencyTest1::AcquireLock() 106 * Descr: This member function is passed the number of times through the 107 * acquisition loop (lockAttempt) and whether or not this is 108 * the first acquisition of the lock within this iteration. 109 * Based on these values, it may do a LockWithTimeout() or just 110 * a plain Lock() on theLocker. This is done to get coverage of 111 * both lock acquisition methods on the BLocker. 112 */ 113 114 bool ConcurrencyTest1::AcquireLock(int lockAttempt, 115 bool firstAcquisition) 116 { 117 bool timeoutLock; 118 bool result; 119 120 if (firstAcquisition) { 121 timeoutLock = ((lockAttempt % 2) == 1); 122 } else { 123 timeoutLock = (((lockAttempt / 2) % 2) == 1); 124 } 125 if (timeoutLock) { 126 result = (theLocker->LockWithTimeout(1000000) == B_OK); 127 } else { 128 result = theLocker->Lock(); 129 } 130 return(result); 131 } 132 133 134 /* 135 * Method: ConcurrencyTest1::TestThread() 136 * Descr: This method is the core of the test. Each of the three threads 137 * run this method to perform the concurrency test. First, the 138 * SafetyLock class (see LockerTestCase.h) is used to make sure that 139 * the lock is released if an assertion happens. Then, each thread 140 * iterates MAXLOOP times through the main loop where the following 141 * actions are performed: 142 * - CheckLock() is used to show that the thread does not have 143 * the lock. 144 * - The thread acquires the lock. 145 * - The thread confirms that mutual exclusion is OK by testing 146 * lockTestValue. 147 * - The thread confirms the lock is held once by the thread. 148 * - The thread acquires the lock again. 149 * - The thread confirms the lock is held twice now by the thread. 150 * - The thread releases the lock once. 151 * - The thread confirms the lock is held once now. 152 * - The thread confirms that mutual exclusion is still OK by 153 * testing lockTestValue. 154 * - The thread releases the lock again. 155 * - The thread confirms that the lock is no longer held. 156 */ 157 158 void ConcurrencyTest1::TestThread(void) 159 { 160 int i; 161 SafetyLock theSafetyLock(theLocker); 162 163 for (i = 0; i < MAXLOOP; i++) { 164 // Print out 10 sub test markers per thread 165 if (i % (MAXLOOP / 10) == 0) 166 NextSubTest(); 167 168 CheckLock(0); 169 CPPUNIT_ASSERT(AcquireLock(i, true)); 170 171 CPPUNIT_ASSERT(!lockTestValue); 172 lockTestValue = true; 173 CheckLock(1); 174 175 CPPUNIT_ASSERT(AcquireLock(i, false)); 176 CheckLock(2); 177 178 theLocker->Unlock(); 179 CheckLock(1); 180 181 CPPUNIT_ASSERT(lockTestValue); 182 lockTestValue = false; 183 theLocker->Unlock(); 184 CheckLock(0); 185 } 186 } 187 188 189 190 191