#include <Locker.h>
#include <TestSuiteAddon.h>
#include <ThreadedTestCaller.h>
#include <cppunit/TestSuite.h>
#include <cppunit/extensions/HelperMacros.h>
#include <string.h>
static const int32 MAX_LOOP = 10000;
static const bigtime_t SNOOZE_TIME = 200000;
class SafetyLock {
public:
SafetyLock(BLocker* lock) : fLocker(lock) {}
~SafetyLock() { if (fLocker != NULL) fLocker->Unlock(); }
private:
BLocker* fLocker;
};
class LockerConcurrencyTest : public BThreadedTestCase {
public:
LockerConcurrencyTest(std::string name, bool benaphoreFlag);
virtual ~LockerConcurrencyTest();
virtual void setUp();
void SimpleLockingLoop();
void AcquireThread();
void TimeoutThread();
static CppUnit::Test* suite();
private:
void CheckLock(int expectedCount);
bool AcquireLock(int lockAttempt, bool firstAcquisition);
BLocker* fLocker;
bool fLockTestValue;
};
LockerConcurrencyTest::LockerConcurrencyTest(std::string name, bool benaphoreFlag)
:
BThreadedTestCase(name),
fLocker(new BLocker(benaphoreFlag)),
fLockTestValue(false)
{
}
LockerConcurrencyTest::~LockerConcurrencyTest()
{
delete fLocker;
}
void
LockerConcurrencyTest::CheckLock(int expectedCount)
{
CPPUNIT_ASSERT(fLocker->CountLockRequests() == expectedCount);
}
void
LockerConcurrencyTest::setUp()
{
fLockTestValue = false;
}
bool
LockerConcurrencyTest::AcquireLock(int lockAttempt, bool firstAcquisition)
{
bool timeoutLock;
if (firstAcquisition)
timeoutLock = ((lockAttempt % 2) == 1);
else
timeoutLock = (((lockAttempt / 2) % 2) == 1);
if (timeoutLock)
return fLocker->LockWithTimeout(1000000) == B_OK;
return fLocker->Lock();
}
void
LockerConcurrencyTest::SimpleLockingLoop()
{
SafetyLock theSafetyLock(fLocker);
for (int i = 0; i < MAX_LOOP; i++) {
CheckLock(0);
CPPUNIT_ASSERT(AcquireLock(i, true));
CPPUNIT_ASSERT(!fLockTestValue);
fLockTestValue = true;
CheckLock(1);
CPPUNIT_ASSERT(AcquireLock(i, false));
CheckLock(2);
fLocker->Unlock();
CheckLock(1);
CPPUNIT_ASSERT(fLockTestValue);
fLockTestValue = false;
fLocker->Unlock();
CheckLock(0);
}
}
void
LockerConcurrencyTest::AcquireThread()
{
SafetyLock theSafetyLock(fLocker);
CPPUNIT_ASSERT(fLocker->Lock());
snooze(SNOOZE_TIME);
fLocker->Unlock();
SimpleLockingLoop();
}
void
LockerConcurrencyTest::TimeoutThread()
{
SafetyLock theSafetyLock(fLocker);
snooze(SNOOZE_TIME / 2);
CPPUNIT_ASSERT(fLocker->LockWithTimeout(SNOOZE_TIME / 10) == B_TIMED_OUT);
SimpleLockingLoop();
}
CppUnit::Test*
LockerConcurrencyTest::suite()
{
typedef BThreadedTestCaller<LockerConcurrencyTest> LockerConcurrencyTestCaller;
CppUnit::TestSuite* testSuite = new CppUnit::TestSuite("LockerConcurrencyTest");
LockerConcurrencyTest* simpleBenaphore = new LockerConcurrencyTest("SimpleBenaphore", true);
LockerConcurrencyTestCaller* simpleBenaphoreCaller
= new LockerConcurrencyTestCaller("BLocker::Concurrency Test #1 (benaphore)", simpleBenaphore);
simpleBenaphoreCaller->addThread("A", &LockerConcurrencyTest::SimpleLockingLoop);
simpleBenaphoreCaller->addThread("B", &LockerConcurrencyTest::SimpleLockingLoop);
simpleBenaphoreCaller->addThread("C", &LockerConcurrencyTest::SimpleLockingLoop);
testSuite->addTest(simpleBenaphoreCaller);
LockerConcurrencyTest* simpleSemaphore = new LockerConcurrencyTest("SimpleSemaphore", false);
LockerConcurrencyTestCaller* simpleSemaphoreCaller
= new LockerConcurrencyTestCaller("BLocker::Concurrency Test #1 (semaphore)", simpleSemaphore);
simpleSemaphoreCaller->addThread("A", &LockerConcurrencyTest::SimpleLockingLoop);
simpleSemaphoreCaller->addThread("B", &LockerConcurrencyTest::SimpleLockingLoop);
simpleSemaphoreCaller->addThread("C", &LockerConcurrencyTest::SimpleLockingLoop);
testSuite->addTest(simpleSemaphoreCaller);
LockerConcurrencyTest* timeoutBenaphore = new LockerConcurrencyTest("TimeoutBenaphore", true);
LockerConcurrencyTestCaller* timeoutBenaphoreCaller
= new LockerConcurrencyTestCaller("BLocker::Concurrency Test #2 (benaphore)", timeoutBenaphore);
timeoutBenaphoreCaller->addThread("Acquire", &LockerConcurrencyTest::AcquireThread);
timeoutBenaphoreCaller->addThread("Timeout1", &LockerConcurrencyTest::TimeoutThread);
timeoutBenaphoreCaller->addThread("Timeout2", &LockerConcurrencyTest::TimeoutThread);
testSuite->addTest(timeoutBenaphoreCaller);
LockerConcurrencyTest* timeoutSemaphore = new LockerConcurrencyTest("TimeoutSemaphore", false);
LockerConcurrencyTestCaller* timeoutSemaphoreCaller
= new LockerConcurrencyTestCaller("BLocker::Concurrency Test #2 (semaphore)", timeoutSemaphore);
timeoutSemaphoreCaller->addThread("Acquire", &LockerConcurrencyTest::AcquireThread);
timeoutSemaphoreCaller->addThread("Timeout1", &LockerConcurrencyTest::TimeoutThread);
timeoutSemaphoreCaller->addThread("Timeout2", &LockerConcurrencyTest::TimeoutThread);
testSuite->addTest(timeoutSemaphoreCaller);
return testSuite;
}