xref: /haiku/src/tests/kits/support/blocker/ConcurrencyTest2.cpp (revision 4c8e85b316c35a9161f5a1c50ad70bc91c83a76f)
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