2 $Id: ConcurrencyTest2.cpp 383 2002-07-22 09:28:00Z tylerdauwalder $
4 This file implements a test class for testing BMessageQueue functionality.
5 It tests use cases Destruction, Add Message 3, Remove Message 2,
6 Next Message 2, Lock 1, Lock 2, Unlock.
8 The test works like the following:
9 - It does the test two times, one unlocking using Unlock() and the other
10 unlocking using delete.
11 - It populates the queue with numAddMessages messages to start.
13 - It starts four threads.
14 - In one thread, a NextMessage() blocks
15 - In the second thread, a RemoveMessage() blocks
16 - In the third thread, an AddMessage() blocks
17 - In the fourth thread, a Lock() blocks
18 - After a short snooze, the queue is released using Unlock() or delete.
19 - Each of the four threads wake up and each checks as best it can that it
20 was successful and did not violate mutual exclusion.
25 #include "ThreadedTestCaller.h"
26 #include "ConcurrencyTest2.h"
27 #include <MessageQueue.h>
30 // This constant indicates the number of messages to add to the queue.
31 const int numAddMessages
= 50;
33 // This constant is used as a base amount of time to snooze.
34 bigtime_t SNOOZE_TIME
= 100000;
38 * Method: ConcurrencyTest2::ConcurrencyTest2()
39 * Descr: This is the constructor for this test.
43 ConcurrencyTest2::ConcurrencyTest2(std::string name
, bool unlockFlag
) :
44 MessageQueueTestCase(name
), unlockTest(unlockFlag
)
50 * Method: ConcurrencyTest2::~ConcurrencyTest2()
51 * Descr: This is the destructor for this test.
55 ConcurrencyTest2::~ConcurrencyTest2()
61 * Method: ConcurrencyTest2::setUp()
62 * Descr: This member functions sets the environment for the test.
63 * it sets the lock flag and resets the message destructor
64 * count. Finally, it adds numAddMessages messages to the
69 void ConcurrencyTest2::setUp(void)
72 testMessageClass::messageDestructorCount
= 0;
76 for (i
=0; i
< numAddMessages
; i
++) {
77 theMessage
= new testMessageClass(i
);
78 theMessageQueue
->AddMessage(theMessage
);
80 removeMessage
= theMessage
;
85 * Method: ConcurrencyTest2::TestThread1()
86 * Descr: This member function is one thread within the test. It
87 * acquires the lock on the queue and then sleeps for a while.
88 * When it wakes up, it releases the lock on the queue by
89 * either doing an Unlock() or deleting the queue.
93 void ConcurrencyTest2::TestThread1(void)
95 theMessageQueue
->Lock();
102 theMessageQueue
->Unlock();
104 BMessageQueue
*tmpMessageQueue
= theMessageQueue
;
105 theMessageQueue
= NULL
;
106 delete tmpMessageQueue
;
112 * Method: ConcurrencyTest2::TestThread2()
113 * Descr: This member function is one thread within the test. It
114 * snoozes for a short time so that TestThread1() will grab
115 * the lock. If this is the delete test, this thread
116 * terminates since Be's implementation may corrupt memory.
117 * Otherwise, the thread blocks attempting a NextMessage() on
118 * the queue. The result of NextMessage() is checked finally.
121 void ConcurrencyTest2::TestThread2(void)
123 snooze(SNOOZE_TIME
/10);
124 CPPUNIT_ASSERT(isLocked
);
126 // Be's implementation can cause a segv when NextMessage() is in
127 // progress when a delete occurs. The OpenBeOS implementation
128 // does not segv, but it won't be tested here because Be's fails.
131 BMessage
*theMessage
= theMessageQueue
->NextMessage();
132 CPPUNIT_ASSERT(!isLocked
);
135 CPPUNIT_ASSERT(theMessage
!= NULL
);
136 CPPUNIT_ASSERT(theMessage
->what
== 0);
138 // The following test passes for the OpenBeOS implementation but
139 // fails for the Be implementation. If the BMessageQueue is deleted
140 // while another thread is blocking waiting for NextMessage(), the
141 // OpenBeOS implementation detects that the message queue is deleted
142 // and returns NULL. The Be implementation actually returns a message.
143 // It must be doing so from freed memory since the queue has been
144 // deleted. The OpenBeOS implementation will not emulate the Be
145 // implementation since I consider it a bug.
147 // CPPUNIT_ASSERT(theMessage==NULL);
153 * Method: ConcurrencyTest2::TestThread3()
154 * Descr: This member function is one thread within the test. It
155 * snoozes for a short time so that TestThread1() will grab
156 * the lock. If this is the delete test, this thread
157 * terminates since Be's implementation may corrupt memory.
158 * Otherwise, the thread blocks attempting a RemoveMessage()
159 * on the queue. The state of the queue is checked finally.
162 void ConcurrencyTest2::TestThread3(void)
164 snooze(SNOOZE_TIME
/10);
165 CPPUNIT_ASSERT(isLocked
);
167 // Be's implementation causes a segv when RemoveMessage() is in
168 // progress when a delete occurs. The OpenBeOS implementation
169 // does not segv, but it won't be tested here because Be's fails.
172 theMessageQueue
->RemoveMessage(removeMessage
);
173 CPPUNIT_ASSERT(!isLocked
);
175 CPPUNIT_ASSERT(theMessageQueue
->FindMessage(removeMessage
->what
, 0) == NULL
);
181 * Method: ConcurrencyTest2::TestThread1()
182 * Descr: This member function is one thread within the test. It
183 * snoozes for a short time so that TestThread1() will grab
184 * the lock. If this is the delete test, this thread
185 * terminates since Be's implementation may corrupt memory.
186 * Otherwise, the thread blocks attempting a AddMessage() on
187 * the queue. The state of the queue is checked finally.
190 void ConcurrencyTest2::TestThread4(void)
192 snooze(SNOOZE_TIME
/10);
193 CPPUNIT_ASSERT(isLocked
);
195 // Be's implementation can cause a segv when AddMessage() is in
196 // progress when a delete occurs. The OpenBeOS implementation
197 // does not segv, but it won't be tested here because Be's fails.
200 theMessageQueue
->AddMessage(new testMessageClass(numAddMessages
));
201 CPPUNIT_ASSERT(!isLocked
);
203 CPPUNIT_ASSERT(theMessageQueue
->FindMessage(numAddMessages
, 0) != NULL
);
209 * Method: ConcurrencyTest2::TestThread1()
210 * Descr: This member function is one thread within the test. It
211 * snoozes for a short time so that TestThread1() will grab
212 * the lock. The thread blocks attempting to acquire the
213 * lock on the queue. Once the lock is acquired, mutual
214 * exclusion is checked as well as the result of the lock
218 void ConcurrencyTest2::TestThread5(void)
220 SafetyLock
mySafetyLock(theMessageQueue
);
222 snooze(SNOOZE_TIME
/10);
223 CPPUNIT_ASSERT(isLocked
);
224 bool result
= theMessageQueue
->Lock();
225 CPPUNIT_ASSERT(!isLocked
);
227 CPPUNIT_ASSERT(result
);
228 theMessageQueue
->Unlock();
230 CPPUNIT_ASSERT(!result
);
236 * Method: ConcurrencyTest2::suite()
237 * Descr: This static member function returns a test suite for performing
238 * all combinations of "ConcurrencyTest2". The test suite contains
239 * two instances of the test. One is performed with an unlock,
240 * the other with a delete. Each individual test
241 * is created as a ThreadedTestCase (typedef'd as
242 * ConcurrencyTest2Caller) with five independent threads.
245 Test
*ConcurrencyTest2::suite(void)
247 typedef BThreadedTestCaller
<ConcurrencyTest2
>
248 ConcurrencyTest2Caller
;
250 TestSuite
*testSuite
= new TestSuite("ConcurrencyTest2");
252 ConcurrencyTest2
*theTest
= new ConcurrencyTest2("WithUnlock", true);
253 ConcurrencyTest2Caller
*threadedTest1
= new ConcurrencyTest2Caller("BMessageQueue::Concurrency Test #2 (with unlock)", theTest
);
254 threadedTest1
->addThread("A", &ConcurrencyTest2::TestThread1
);
255 threadedTest1
->addThread("B", &ConcurrencyTest2::TestThread2
);
256 threadedTest1
->addThread("C", &ConcurrencyTest2::TestThread3
);
257 threadedTest1
->addThread("D", &ConcurrencyTest2::TestThread4
);
258 threadedTest1
->addThread("E", &ConcurrencyTest2::TestThread5
);
260 theTest
= new ConcurrencyTest2("WithDelete", false);
261 ConcurrencyTest2Caller
*threadedTest2
= new ConcurrencyTest2Caller("BMessageQueue::Concurrency Test #2 (with delete)", theTest
);
262 threadedTest2
->addThread("A", &ConcurrencyTest2::TestThread1
);
263 threadedTest2
->addThread("B", &ConcurrencyTest2::TestThread2
);
264 threadedTest2
->addThread("C", &ConcurrencyTest2::TestThread3
);
265 threadedTest2
->addThread("D", &ConcurrencyTest2::TestThread4
);
266 threadedTest2
->addThread("E", &ConcurrencyTest2::TestThread5
);
268 testSuite
->addTest(threadedTest1
);
269 testSuite
->addTest(threadedTest2
);