xref: /haiku/src/tests/kits/app/bmessagequeue/ConcurrencyTest2.cpp (revision 268f99dd7dc4bd7474a8bd2742d3f1ec1de6752a)
152a38012Sejakowatz /*
2571d840aSOliver Tappe 	$Id: ConcurrencyTest2.cpp 383 2002-07-22 09:28:00Z tylerdauwalder $
352a38012Sejakowatz 
452a38012Sejakowatz 	This file implements a test class for testing BMessageQueue functionality.
552a38012Sejakowatz 	It tests use cases Destruction, Add Message 3, Remove Message 2,
652a38012Sejakowatz 	Next Message 2, Lock 1, Lock 2, Unlock.
752a38012Sejakowatz 
852a38012Sejakowatz 	The test works like the following:
952a38012Sejakowatz 		- It does the test two times, one unlocking using Unlock() and the other
1052a38012Sejakowatz 		  unlocking using delete.
1152a38012Sejakowatz 		- It populates the queue with numAddMessages messages to start.
1252a38012Sejakowatz 		- The queue is locked
1352a38012Sejakowatz 	    - It starts four threads.
1452a38012Sejakowatz 	    - In one thread, a NextMessage() blocks
1552a38012Sejakowatz 	    - In the second thread, a RemoveMessage() blocks
1652a38012Sejakowatz 	    - In the third thread, an AddMessage() blocks
1752a38012Sejakowatz 	    - In the fourth thread, a Lock() blocks
1852a38012Sejakowatz 	    - After a short snooze, the queue is released using Unlock() or delete.
1952a38012Sejakowatz 	    - Each of the four threads wake up and each checks as best it can that it
2052a38012Sejakowatz 	      was successful and did not violate mutual exclusion.
2152a38012Sejakowatz 
2252a38012Sejakowatz 	*/
2352a38012Sejakowatz 
2452a38012Sejakowatz 
2552a38012Sejakowatz #include "ThreadedTestCaller.h"
26be2939caSTyler Dauwalder #include "ConcurrencyTest2.h"
2752a38012Sejakowatz #include <MessageQueue.h>
2852a38012Sejakowatz 
2952a38012Sejakowatz 
3052a38012Sejakowatz // This constant indicates the number of messages to add to the queue.
3152a38012Sejakowatz const int numAddMessages = 50;
3252a38012Sejakowatz 
3352a38012Sejakowatz // This constant is used as a base amount of time to snooze.
3452a38012Sejakowatz bigtime_t SNOOZE_TIME = 100000;
3552a38012Sejakowatz 
3652a38012Sejakowatz 
3752a38012Sejakowatz /*
38be2939caSTyler Dauwalder  *  Method:  ConcurrencyTest2::ConcurrencyTest2()
3952a38012Sejakowatz  *   Descr:  This is the constructor for this test.
4052a38012Sejakowatz  */
4152a38012Sejakowatz 
42be2939caSTyler Dauwalder 
ConcurrencyTest2(std::string name,bool unlockFlag)43be2939caSTyler Dauwalder 	ConcurrencyTest2::ConcurrencyTest2(std::string name, bool unlockFlag) :
44be2939caSTyler Dauwalder 		MessageQueueTestCase(name), unlockTest(unlockFlag)
4552a38012Sejakowatz {
4652a38012Sejakowatz 	}
4752a38012Sejakowatz 
4852a38012Sejakowatz 
4952a38012Sejakowatz /*
50be2939caSTyler Dauwalder  *  Method:  ConcurrencyTest2::~ConcurrencyTest2()
5152a38012Sejakowatz  *   Descr:  This is the destructor for this test.
5252a38012Sejakowatz  */
5352a38012Sejakowatz 
54be2939caSTyler Dauwalder 
~ConcurrencyTest2()55be2939caSTyler Dauwalder 	ConcurrencyTest2::~ConcurrencyTest2()
5652a38012Sejakowatz {
5752a38012Sejakowatz 	}
5852a38012Sejakowatz 
5952a38012Sejakowatz 
6052a38012Sejakowatz /*
61be2939caSTyler Dauwalder  *  Method:  ConcurrencyTest2::setUp()
6252a38012Sejakowatz  *   Descr:  This member functions sets the environment for the test.
6352a38012Sejakowatz  *           it sets the lock flag and resets the message destructor
6452a38012Sejakowatz  *           count.  Finally, it adds numAddMessages messages to the
6552a38012Sejakowatz  *           queue.
6652a38012Sejakowatz  */
6752a38012Sejakowatz 
68be2939caSTyler Dauwalder 
setUp(void)69be2939caSTyler Dauwalder 	void ConcurrencyTest2::setUp(void)
7052a38012Sejakowatz {
7152a38012Sejakowatz 	isLocked = false;
7252a38012Sejakowatz 	testMessageClass::messageDestructorCount = 0;
7352a38012Sejakowatz 
7452a38012Sejakowatz 	int i;
7552a38012Sejakowatz 	BMessage *theMessage;
7652a38012Sejakowatz 	for (i=0; i < numAddMessages; i++) {
7752a38012Sejakowatz 		theMessage = new testMessageClass(i);
7852a38012Sejakowatz 		theMessageQueue->AddMessage(theMessage);
7952a38012Sejakowatz 	}
8052a38012Sejakowatz 	removeMessage = theMessage;
8152a38012Sejakowatz }
8252a38012Sejakowatz 
8352a38012Sejakowatz 
8452a38012Sejakowatz /*
85be2939caSTyler Dauwalder  *  Method:  ConcurrencyTest2::TestThread1()
8652a38012Sejakowatz  *   Descr:  This member function is one thread within the test.  It
8752a38012Sejakowatz  *           acquires the lock on the queue and then sleeps for a while.
8852a38012Sejakowatz  *           When it wakes up, it releases the lock on the queue by
8952a38012Sejakowatz  *           either doing an Unlock() or deleting the queue.
9052a38012Sejakowatz  */
9152a38012Sejakowatz 
92be2939caSTyler Dauwalder 
TestThread1(void)93be2939caSTyler Dauwalder 	void ConcurrencyTest2::TestThread1(void)
9452a38012Sejakowatz {
9552a38012Sejakowatz 	theMessageQueue->Lock();
9652a38012Sejakowatz 	isLocked = true;
9752a38012Sejakowatz 
9852a38012Sejakowatz 	snooze(SNOOZE_TIME);
9952a38012Sejakowatz 
10052a38012Sejakowatz 	isLocked = false;
10152a38012Sejakowatz 	if (unlockTest) {
10252a38012Sejakowatz 		theMessageQueue->Unlock();
10352a38012Sejakowatz 	} else {
104be2939caSTyler Dauwalder 		BMessageQueue *tmpMessageQueue = theMessageQueue;
10552a38012Sejakowatz 		theMessageQueue = NULL;
10652a38012Sejakowatz 		delete tmpMessageQueue;
10752a38012Sejakowatz 	}
10852a38012Sejakowatz }
10952a38012Sejakowatz 
11052a38012Sejakowatz 
11152a38012Sejakowatz /*
112be2939caSTyler Dauwalder  *  Method:  ConcurrencyTest2::TestThread2()
11352a38012Sejakowatz  *   Descr:  This member function is one thread within the test.  It
11452a38012Sejakowatz  *           snoozes for a short time so that TestThread1() will grab
11552a38012Sejakowatz  *           the lock.  If this is the delete test, this thread
11652a38012Sejakowatz  *           terminates since Be's implementation may corrupt memory.
11752a38012Sejakowatz  *           Otherwise, the thread blocks attempting a NextMessage() on
11852a38012Sejakowatz  *           the queue.  The result of NextMessage() is checked finally.
11952a38012Sejakowatz  */
12052a38012Sejakowatz 
TestThread2(void)121be2939caSTyler Dauwalder  void ConcurrencyTest2::TestThread2(void)
12252a38012Sejakowatz {
12352a38012Sejakowatz 	snooze(SNOOZE_TIME/10);
124be2939caSTyler Dauwalder 	CPPUNIT_ASSERT(isLocked);
12552a38012Sejakowatz 	if (!unlockTest) {
12652a38012Sejakowatz 		// Be's implementation can cause a segv when NextMessage() is in
127*2ca13760SColdfirex 		// progress when a delete occurs.  The Haiku implementation
12852a38012Sejakowatz 		// does not segv, but it won't be tested here because Be's fails.
12952a38012Sejakowatz 		return;
13052a38012Sejakowatz 	}
13152a38012Sejakowatz 	BMessage *theMessage = theMessageQueue->NextMessage();
132be2939caSTyler Dauwalder 	CPPUNIT_ASSERT(!isLocked);
13352a38012Sejakowatz 
13452a38012Sejakowatz 	if (unlockTest) {
135be2939caSTyler Dauwalder 		CPPUNIT_ASSERT(theMessage != NULL);
136be2939caSTyler Dauwalder 		CPPUNIT_ASSERT(theMessage->what == 0);
13752a38012Sejakowatz 	} else {
138*2ca13760SColdfirex 		// The following test passes for the Haiku implementation but
13952a38012Sejakowatz 		// fails for the Be implementation.  If the BMessageQueue is deleted
14052a38012Sejakowatz 		// while another thread is blocking waiting for NextMessage(), the
141*2ca13760SColdfirex 		// Haiku implementation detects that the message queue is deleted
14252a38012Sejakowatz 		// and returns NULL.  The Be implementation actually returns a message.
14352a38012Sejakowatz 		// It must be doing so from freed memory since the queue has been
144*2ca13760SColdfirex 		// deleted.  The Haiku implementation will not emulate the Be
14552a38012Sejakowatz 		// implementation since I consider it a bug.
14652a38012Sejakowatz 		//
147be2939caSTyler Dauwalder 		// CPPUNIT_ASSERT(theMessage==NULL);
14852a38012Sejakowatz 	}
14952a38012Sejakowatz }
15052a38012Sejakowatz 
15152a38012Sejakowatz 
15252a38012Sejakowatz /*
153be2939caSTyler Dauwalder  *  Method:  ConcurrencyTest2::TestThread3()
15452a38012Sejakowatz  *   Descr:  This member function is one thread within the test.  It
15552a38012Sejakowatz  *           snoozes for a short time so that TestThread1() will grab
15652a38012Sejakowatz  *           the lock.  If this is the delete test, this thread
15752a38012Sejakowatz  *           terminates since Be's implementation may corrupt memory.
15852a38012Sejakowatz  *           Otherwise, the thread blocks attempting a RemoveMessage()
15952a38012Sejakowatz  *           on the queue.  The state of the queue is checked finally.
16052a38012Sejakowatz  */
16152a38012Sejakowatz 
TestThread3(void)162be2939caSTyler Dauwalder  void ConcurrencyTest2::TestThread3(void)
16352a38012Sejakowatz {
16452a38012Sejakowatz 	snooze(SNOOZE_TIME/10);
165be2939caSTyler Dauwalder 	CPPUNIT_ASSERT(isLocked);
16652a38012Sejakowatz 	if (!unlockTest) {
16752a38012Sejakowatz 		// Be's implementation causes a segv when RemoveMessage() is in
168*2ca13760SColdfirex 		// progress when a delete occurs.  The Haiku implementation
16952a38012Sejakowatz 		// does not segv, but it won't be tested here because Be's fails.
17052a38012Sejakowatz 		return;
17152a38012Sejakowatz 	}
17252a38012Sejakowatz 	theMessageQueue->RemoveMessage(removeMessage);
173be2939caSTyler Dauwalder 	CPPUNIT_ASSERT(!isLocked);
17452a38012Sejakowatz 	if (unlockTest) {
175be2939caSTyler Dauwalder 		CPPUNIT_ASSERT(theMessageQueue->FindMessage(removeMessage->what, 0) == NULL);
17652a38012Sejakowatz 	}
17752a38012Sejakowatz }
17852a38012Sejakowatz 
17952a38012Sejakowatz 
18052a38012Sejakowatz /*
181be2939caSTyler Dauwalder  *  Method:  ConcurrencyTest2::TestThread1()
18252a38012Sejakowatz  *   Descr:  This member function is one thread within the test.  It
18352a38012Sejakowatz  *           snoozes for a short time so that TestThread1() will grab
18452a38012Sejakowatz  *           the lock.  If this is the delete test, this thread
18552a38012Sejakowatz  *           terminates since Be's implementation may corrupt memory.
18652a38012Sejakowatz  *           Otherwise, the thread blocks attempting a AddMessage() on
18752a38012Sejakowatz  *           the queue.  The state of the queue is checked finally.
18852a38012Sejakowatz  */
18952a38012Sejakowatz 
TestThread4(void)190be2939caSTyler Dauwalder  void ConcurrencyTest2::TestThread4(void)
19152a38012Sejakowatz {
19252a38012Sejakowatz 	snooze(SNOOZE_TIME/10);
193be2939caSTyler Dauwalder 	CPPUNIT_ASSERT(isLocked);
19452a38012Sejakowatz 	if (!unlockTest) {
19552a38012Sejakowatz 		// Be's implementation can cause a segv when AddMessage() is in
196*2ca13760SColdfirex 		// progress when a delete occurs.  The Haiku implementation
19752a38012Sejakowatz 		// does not segv, but it won't be tested here because Be's fails.
19852a38012Sejakowatz 		return;
19952a38012Sejakowatz 	}
20052a38012Sejakowatz 	theMessageQueue->AddMessage(new testMessageClass(numAddMessages));
201be2939caSTyler Dauwalder 	CPPUNIT_ASSERT(!isLocked);
20252a38012Sejakowatz 	if (unlockTest) {
203be2939caSTyler Dauwalder 		CPPUNIT_ASSERT(theMessageQueue->FindMessage(numAddMessages, 0) != NULL);
20452a38012Sejakowatz 	}
20552a38012Sejakowatz }
20652a38012Sejakowatz 
20752a38012Sejakowatz 
20852a38012Sejakowatz /*
209be2939caSTyler Dauwalder  *  Method:  ConcurrencyTest2::TestThread1()
21052a38012Sejakowatz  *   Descr:  This member function is one thread within the test.  It
21152a38012Sejakowatz  *           snoozes for a short time so that TestThread1() will grab
21252a38012Sejakowatz  *           the lock.  The thread blocks attempting to acquire the
21352a38012Sejakowatz  *           lock on the queue.  Once the lock is acquired, mutual
21452a38012Sejakowatz  *           exclusion is checked as well as the result of the lock
21552a38012Sejakowatz  *           acquisition.
21652a38012Sejakowatz  */
21752a38012Sejakowatz 
TestThread5(void)218be2939caSTyler Dauwalder  void ConcurrencyTest2::TestThread5(void)
21952a38012Sejakowatz {
220be2939caSTyler Dauwalder 	SafetyLock mySafetyLock(theMessageQueue);
22152a38012Sejakowatz 
22252a38012Sejakowatz 	snooze(SNOOZE_TIME/10);
223be2939caSTyler Dauwalder 	CPPUNIT_ASSERT(isLocked);
22452a38012Sejakowatz 	bool result = theMessageQueue->Lock();
225be2939caSTyler Dauwalder 	CPPUNIT_ASSERT(!isLocked);
22652a38012Sejakowatz 	if (unlockTest) {
227be2939caSTyler Dauwalder 		CPPUNIT_ASSERT(result);
22852a38012Sejakowatz 		theMessageQueue->Unlock();
22952a38012Sejakowatz 	} else {
230be2939caSTyler Dauwalder 		CPPUNIT_ASSERT(!result);
23152a38012Sejakowatz 	}
23252a38012Sejakowatz }
23352a38012Sejakowatz 
23452a38012Sejakowatz 
23552a38012Sejakowatz /*
236be2939caSTyler Dauwalder  *  Method:  ConcurrencyTest2::suite()
23752a38012Sejakowatz  *   Descr:  This static member function returns a test suite for performing
23852a38012Sejakowatz  *           all combinations of "ConcurrencyTest2".  The test suite contains
23952a38012Sejakowatz  *           two instances of the test.  One is performed with an unlock,
24052a38012Sejakowatz  *           the other with a delete.  Each individual test
24152a38012Sejakowatz  *           is created as a ThreadedTestCase (typedef'd as
24252a38012Sejakowatz  *           ConcurrencyTest2Caller) with five independent threads.
24352a38012Sejakowatz  */
24452a38012Sejakowatz 
suite(void)245be2939caSTyler Dauwalder  Test *ConcurrencyTest2::suite(void)
24652a38012Sejakowatz {
247be2939caSTyler Dauwalder 	typedef BThreadedTestCaller<ConcurrencyTest2>
248be2939caSTyler Dauwalder 		ConcurrencyTest2Caller;
249be2939caSTyler Dauwalder 
25052a38012Sejakowatz 	TestSuite *testSuite = new TestSuite("ConcurrencyTest2");
25152a38012Sejakowatz 
252be2939caSTyler Dauwalder 	ConcurrencyTest2 *theTest = new ConcurrencyTest2("WithUnlock", true);
253be2939caSTyler Dauwalder 	ConcurrencyTest2Caller *threadedTest1 = new ConcurrencyTest2Caller("BMessageQueue::Concurrency Test #2 (with unlock)", theTest);
254be2939caSTyler Dauwalder 	threadedTest1->addThread("A", &ConcurrencyTest2::TestThread1);
255be2939caSTyler Dauwalder 	threadedTest1->addThread("B", &ConcurrencyTest2::TestThread2);
256be2939caSTyler Dauwalder 	threadedTest1->addThread("C", &ConcurrencyTest2::TestThread3);
257be2939caSTyler Dauwalder 	threadedTest1->addThread("D", &ConcurrencyTest2::TestThread4);
258be2939caSTyler Dauwalder 	threadedTest1->addThread("E", &ConcurrencyTest2::TestThread5);
25952a38012Sejakowatz 
260be2939caSTyler Dauwalder 	theTest = new ConcurrencyTest2("WithDelete", false);
261be2939caSTyler Dauwalder 	ConcurrencyTest2Caller *threadedTest2 = new ConcurrencyTest2Caller("BMessageQueue::Concurrency Test #2 (with delete)", theTest);
262be2939caSTyler Dauwalder 	threadedTest2->addThread("A", &ConcurrencyTest2::TestThread1);
263be2939caSTyler Dauwalder 	threadedTest2->addThread("B", &ConcurrencyTest2::TestThread2);
264be2939caSTyler Dauwalder 	threadedTest2->addThread("C", &ConcurrencyTest2::TestThread3);
265be2939caSTyler Dauwalder 	threadedTest2->addThread("D", &ConcurrencyTest2::TestThread4);
266be2939caSTyler Dauwalder 	threadedTest2->addThread("E", &ConcurrencyTest2::TestThread5);
26752a38012Sejakowatz 
26852a38012Sejakowatz 	testSuite->addTest(threadedTest1);
26952a38012Sejakowatz 	testSuite->addTest(threadedTest2);
27052a38012Sejakowatz 	return(testSuite);
27152a38012Sejakowatz 	}
27252a38012Sejakowatz 
27352a38012Sejakowatz 
274be2939caSTyler Dauwalder 
275