1/*
2	$Id: DestructionTest2.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 "Destruction" and "Locking 4".
6
7	The test works like the following:
8		- the main thread acquires the lock
9		- it creates a new thread and sleeps
10		- the new thread attempts to acquire the lock but times out
11		- the new thread then attempts to acquire the lock again
12		- before the new thread times out a second time, the first thread releases
13		  the lock
14		- at this time, the new thread acquires the lock and goes to sleep
15		- the first thread attempts to acquire the lock
16		- the second thread deletes the lock
17		- the first thread is woken up indicating that the lock wasn't acquired.
18
19	*/
20
21
22#include <ThreadedTestCaller.h>
23#include "DestructionTest2.h"
24#include <cppunit/TestSuite.h>
25#include <Locker.h>
26
27// This constant is used to determine the number of microseconds to
28// sleep during major steps of the test.
29
30const bigtime_t SNOOZE_TIME = 200000;
31
32
33/*
34 *  Method:  DestructionTest2::DestructionTest2()
35 *   Descr:  This is the only constructor for this test class.
36 */
37
38
39	DestructionTest2::DestructionTest2(std::string name,
40											   bool isBenaphore) :
41		LockerTestCase(name, isBenaphore)
42{
43	}
44
45
46/*
47 *  Method:  DestructionTest2::~DestructionTest2()
48 *   Descr:  This is the only destructor for this test class.
49 */
50
51
52	DestructionTest2::~DestructionTest2()
53{
54	}
55
56
57/*
58 *  Method:  DestructionTest2::TestThread1()
59 *   Descr:  This method immediately acquires the lock, sleeps
60 *           for SNOOZE_TIME and then releases the lock.  It sleeps
61 *           again for SNOOZE_TIME and then tries to re-acquire the
62 *           lock.  By this time, the other thread should have
63 *           deleted the lock.  This acquisition should fail.
64 */
65
66void DestructionTest2::TestThread1(void)
67{
68	CPPUNIT_ASSERT(theLocker->LockWithTimeout(SNOOZE_TIME) == B_OK);
69	NextSubTest();
70	snooze(SNOOZE_TIME);
71	NextSubTest();
72	theLocker->Unlock();
73	NextSubTest();
74	snooze(SNOOZE_TIME);
75	NextSubTest();
76	CPPUNIT_ASSERT(theLocker->LockWithTimeout(SNOOZE_TIME * 10) == B_BAD_SEM_ID);
77	NextSubTest();
78}
79
80
81/*
82 *  Method:  DestructionTest2::TestThread2()
83 *   Descr:  This method sleeps for SNOOZE_TIME/10 and then attempts to acquire
84 *           the lock for SNOOZE_TIME/10 seconds.  This acquisition will timeout
85 *           because the other thread is holding the lock.  Then it acquires the
86 *           lock by using a larger timeout. It sleeps again for 2*SNOOZE_TIME and
87 *           then deletes the lock.  This should wake up the other thread.
88 */
89
90void DestructionTest2::TestThread2(void)
91{
92	BLocker *tmpLock;
93
94	snooze(SNOOZE_TIME/10);
95	NextSubTest();
96	CPPUNIT_ASSERT(theLocker->LockWithTimeout(SNOOZE_TIME / 10) == B_TIMED_OUT);
97	NextSubTest();
98	CPPUNIT_ASSERT(theLocker->LockWithTimeout(SNOOZE_TIME * 10) == B_OK);
99	NextSubTest();
100	snooze(SNOOZE_TIME);
101	NextSubTest();
102	snooze(SNOOZE_TIME);
103	NextSubTest();
104	tmpLock = theLocker;
105	theLocker = NULL;
106	delete tmpLock;
107}
108
109
110/*
111 *  Method:  DestructionTest2::suite()
112 *   Descr:  This static member function returns a test suite for performing
113 *           all combinations of "DestructionTest2".  The test suite contains
114 *           two instances of the test.  One is performed on a benaphore,
115 *           the other on a semaphore based BLocker.  Each individual test
116 *           is created as a ThreadedTestCase (typedef'd as
117 *           DestructionTest2Caller) with two independent threads.
118 */
119
120CppUnit::Test *DestructionTest2::suite(void)
121{
122	typedef BThreadedTestCaller<DestructionTest2> DestructionTest2Caller;
123	CppUnit::TestSuite *testSuite = new CppUnit::TestSuite("DestructionTest2");
124
125	// Make a benaphore based test object, create a ThreadedTestCase for it and add
126	// two threads to it.
127	DestructionTest2 *theTest = new DestructionTest2("Benaphore", true);
128	DestructionTest2Caller *threadedTest1 = new DestructionTest2Caller("BLocker::Destruction Test #2 (benaphore)", theTest);
129	threadedTest1->addThread("A", &DestructionTest2::TestThread1);
130	threadedTest1->addThread("B", &DestructionTest2::TestThread2);
131
132	// Make a semaphore based test object, create a ThreadedTestCase for it and add
133	// three threads to it.
134	theTest = new DestructionTest2("Semaphore", false);
135	DestructionTest2Caller *threadedTest2 = new DestructionTest2Caller("BLocker::Destruction Test #2 (semaphore)", theTest);
136	threadedTest2->addThread("A", &DestructionTest2::TestThread1);
137	threadedTest2->addThread("B", &DestructionTest2::TestThread2);
138
139	testSuite->addTest(threadedTest1);
140	testSuite->addTest(threadedTest2);
141	return(testSuite);
142}
143
144
145
146
147