vfs: check userland buffers before reading them.
[haiku.git] / src / tests / kits / app / bmessagequeue / ConcurrencyTest2.cpp
blob7d3990c37b60864cbf2619f23e8b968ac0163fc1
1 /*
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.
12 - The queue is locked
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
65 * queue.
69 void ConcurrencyTest2::setUp(void)
71 isLocked = false;
72 testMessageClass::messageDestructorCount = 0;
74 int i;
75 BMessage *theMessage;
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();
96 isLocked = true;
98 snooze(SNOOZE_TIME);
100 isLocked = false;
101 if (unlockTest) {
102 theMessageQueue->Unlock();
103 } else {
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);
125 if (!unlockTest) {
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.
129 return;
131 BMessage *theMessage = theMessageQueue->NextMessage();
132 CPPUNIT_ASSERT(!isLocked);
134 if (unlockTest) {
135 CPPUNIT_ASSERT(theMessage != NULL);
136 CPPUNIT_ASSERT(theMessage->what == 0);
137 } else {
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);
166 if (!unlockTest) {
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.
170 return;
172 theMessageQueue->RemoveMessage(removeMessage);
173 CPPUNIT_ASSERT(!isLocked);
174 if (unlockTest) {
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);
194 if (!unlockTest) {
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.
198 return;
200 theMessageQueue->AddMessage(new testMessageClass(numAddMessages));
201 CPPUNIT_ASSERT(!isLocked);
202 if (unlockTest) {
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
215 * acquisition.
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);
226 if (unlockTest) {
227 CPPUNIT_ASSERT(result);
228 theMessageQueue->Unlock();
229 } else {
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);
270 return(testSuite);