1 /* 2 $Id: ConcurrencyTest2.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". It is essentially the same as Test1.cpp 7 except it makes the first LockWithTimeout inside the threads timeout. The 8 reason for this is because the implementation of BLocker by Be and with Haiku 9 is such that after one timeout occurs on a benaphore style BLocker, the lock 10 effectively becomes a semaphore style BLocker. This test tests that condition. 11 12 */ 13 14 15 #include "ThreadedTestCaller.h" 16 #include "ConcurrencyTest2.h" 17 #include "cppunit/TestSuite.h" 18 #include "Locker.h" 19 20 21 // This constant indicates the number of times the thread should test the 22 // acquisition and release of the BLocker. 23 24 const int32 MAXLOOP = 10000; 25 26 // This constant is used to determine the number of microseconds to 27 // sleep during major steps of the test. 28 29 const bigtime_t SNOOZE_TIME = 200000; 30 31 /* 32 * Method: ConcurrencyTest2::ConcurrencyTest2() 33 * Descr: This is the only constructor for this test case. It takes a 34 * test name and a flag to indicate whether to test a benaphore 35 * or semaphore type BLocker. 36 */ 37 38 39 ConcurrencyTest2::ConcurrencyTest2(std::string name, bool benaphoreFlag) : 40 LockerTestCase(name, benaphoreFlag), lockTestValue(false) 41 { 42 } 43 44 45 /* 46 * Method: ConcurrencyTest2::~ConcurrencyTest2() 47 * Descr: This is the descriptor for this test case. 48 */ 49 50 51 ConcurrencyTest2::~ConcurrencyTest2() 52 { 53 } 54 55 56 /* 57 * Method: ConcurrencyTest2::setUp() 58 * Descr: This member is called before starting the actual test threads 59 * and is used to ensure that the class is initialized for the 60 * testing. It just sets the "lockTestValue" flag to false. This 61 * flag is used to show that there is mutual exclusion between the 62 * threads. 63 */ 64 65 void 66 ConcurrencyTest2::setUp(void) 67 { 68 lockTestValue = false; 69 } 70 71 72 /* 73 * Method: ConcurrencyTest2::suite() 74 * Descr: This static member function returns a test suite for performing 75 * all combinations of "ConcurrencyTest2". The test suite contains 76 * two instances of the test. One is performed on a benaphore, 77 * the other on a semaphore based BLocker. Each individual test 78 * is created as a ThreadedTestCase (typedef'd as 79 * ConcurrencyTest2Caller) with three independent threads. 80 */ 81 82 CppUnit::Test *ConcurrencyTest2::suite(void) 83 { 84 typedef BThreadedTestCaller <ConcurrencyTest2 > 85 ConcurrencyTest2Caller; 86 CppUnit::TestSuite *testSuite = new CppUnit::TestSuite("ConcurrencyTest2"); 87 88 // Make a benaphore based test object, create a ThreadedTestCase for it and add 89 // three threads to it. 90 ConcurrencyTest2 *theTest = new ConcurrencyTest2("Benaphore", true); 91 ConcurrencyTest2Caller *threadedTest1 = new ConcurrencyTest2Caller("BLocker::Concurrency Test #2 (benaphore)", theTest); 92 threadedTest1->addThread("Acquire", &ConcurrencyTest2::AcquireThread); 93 threadedTest1->addThread("Timeout1", &ConcurrencyTest2::TimeoutThread); 94 threadedTest1->addThread("Timeout2", &ConcurrencyTest2::TimeoutThread); 95 96 // Make a semaphore based test object, create a ThreadedTestCase for it and add 97 // three threads to it. 98 theTest = new ConcurrencyTest2("Semaphore", false); 99 ConcurrencyTest2Caller *threadedTest2 = new ConcurrencyTest2Caller("BLocker::Concurrency Test #2 (semaphore)", theTest); 100 threadedTest2->addThread("Acquire", &ConcurrencyTest2::AcquireThread); 101 threadedTest2->addThread("Timeout1", &ConcurrencyTest2::TimeoutThread); 102 threadedTest2->addThread("Timeout2", &ConcurrencyTest2::TimeoutThread); 103 104 testSuite->addTest(threadedTest1); 105 testSuite->addTest(threadedTest2); 106 return(testSuite); 107 } 108 109 110 /* 111 * Method: ConcurrencyTest2::AcquireThread() 112 * Descr: This member function acquires the lock, sleeps for SNOOZE_TIME, 113 * releases the lock and then launches into the lock loop test. 114 */ 115 116 void ConcurrencyTest2::AcquireThread(void) 117 { 118 SafetyLock theSafetyLock(theLocker); 119 120 CPPUNIT_ASSERT(theLocker->Lock()); 121 NextSubTest(); 122 snooze(SNOOZE_TIME); 123 NextSubTest(); 124 theLocker->Unlock(); 125 NextSubTest(); 126 LockingLoop(); 127 NextSubTest(); 128 } 129 130 131 /* 132 * Method: ConcurrencyTest2::AcquireLock() 133 * Descr: This member function is passed the number of times through the 134 * acquisition loop (lockAttempt) and whether or not this is 135 * the first acquisition of the lock within this iteration. 136 * Based on these values, it may do a LockWithTimeout() or just 137 * a plain Lock() on theLocker. This is done to get coverage of 138 * both lock acquisition methods on the BLocker. 139 */ 140 141 bool ConcurrencyTest2::AcquireLock(int lockAttempt, 142 bool firstAcquisition) 143 { 144 bool timeoutLock; 145 bool result; 146 147 if (firstAcquisition) { 148 timeoutLock = ((lockAttempt % 2) == 1); 149 } else { 150 timeoutLock = (((lockAttempt / 2) % 2) == 1); 151 } 152 if (timeoutLock) { 153 result = (theLocker->LockWithTimeout(1000000) == B_OK); 154 } else { 155 result = theLocker->Lock(); 156 } 157 return(result); 158 } 159 160 161 /* 162 * Method: ConcurrencyTest2::TimeoutThread() 163 * Descr: This member function sleeps for a short time and then attempts to 164 * acquire the lock for SNOOZE_TIME/10 seconds. This acquisition 165 * should timeout. Then the locking loop is started. 166 */ 167 168 void ConcurrencyTest2::TimeoutThread(void) 169 { 170 SafetyLock theSafetyLock(theLocker); 171 172 snooze(SNOOZE_TIME/2); 173 NextSubTest(); 174 CPPUNIT_ASSERT(theLocker->LockWithTimeout(SNOOZE_TIME/10) == B_TIMED_OUT); 175 NextSubTest(); 176 LockingLoop(); 177 NextSubTest(); 178 } 179 180 181 /* 182 * Method: ConcurrencyTest2::TestThread() 183 * Descr: This method is the core of the test. Each of the three threads 184 * run this method to perform the concurrency test. First, the 185 * SafetyLock class (see LockerTestCase.h) is used to make sure that 186 * the lock is released if an assertion happens. Then, each thread 187 * iterates MAXLOOP times through the main loop where the following 188 * actions are performed: 189 * - CheckLock() is used to show that the thread does not have 190 * the lock. 191 * - The thread acquires the lock. 192 * - The thread confirms that mutual exclusion is OK by testing 193 * lockTestValue. 194 * - The thread confirms the lock is held once by the thread. 195 * - The thread acquires the lock again. 196 * - The thread confirms the lock is held twice now by the thread. 197 * - The thread releases the lock once. 198 * - The thread confirms the lock is held once now. 199 * - The thread confirms that mutual exclusion is still OK by 200 * testing lockTestValue. 201 * - The thread releases the lock again. 202 * - The thread confirms that the lock is no longer held. 203 */ 204 205 void ConcurrencyTest2::LockingLoop(void) 206 { 207 int i; 208 SafetyLock theSafetyLock(theLocker); 209 210 for (i = 0; i < MAXLOOP; i++) { 211 CheckLock(0); 212 CPPUNIT_ASSERT(AcquireLock(i, true)); 213 214 CPPUNIT_ASSERT(!lockTestValue); 215 lockTestValue = true; 216 CheckLock(1); 217 218 CPPUNIT_ASSERT(AcquireLock(i, false)); 219 CheckLock(2); 220 221 theLocker->Unlock(); 222 CheckLock(1); 223 224 CPPUNIT_ASSERT(lockTestValue); 225 lockTestValue = false; 226 theLocker->Unlock(); 227 CheckLock(0); 228 } 229 } 230 231 232 233