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