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
20const 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
57void
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
74CppUnit::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
114bool 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
158void 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