aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJim Carroll <thecarrolls@jiminger.com>2011-07-11 09:31:51 -0400
committerJim Carroll <thecarrolls@jiminger.com>2011-07-20 00:58:28 -0400
commit7c17463d76f8015ba8339df973b47d78c1ff9817 (patch)
tree96375d229819c6101332fbc03a1c0c191674a97b
parent99c10f107ea7edefbd5eeebedc55d48380964887 (diff)
All testing is now much less time sensitive and should avoid spurious failures.
-rw-r--r--xbmc/threads/test/TestEvent.cpp73
-rw-r--r--xbmc/threads/test/TestSharedSection.cpp138
2 files changed, 168 insertions, 43 deletions
diff --git a/xbmc/threads/test/TestEvent.cpp b/xbmc/threads/test/TestEvent.cpp
index 42df6361a7..659b3dd42a 100644
--- a/xbmc/threads/test/TestEvent.cpp
+++ b/xbmc/threads/test/TestEvent.cpp
@@ -22,6 +22,7 @@
#include <boost/test/unit_test.hpp>
#include "threads/Event.h"
+#include "threads/Atomics.h"
#include <boost/thread/thread.hpp>
#include <boost/shared_array.hpp>
@@ -97,7 +98,7 @@ public:
static void Sleep(unsigned int millis) { boost::thread::sleep(BOOST_MILLIS(millis)); }
-template<class E> bool waitForWaiters(E& event, int numWaiters, int milliseconds)
+template<class E> static bool waitForWaiters(E& event, int numWaiters, int milliseconds)
{
for( int i = 0; i < milliseconds; i++)
{
@@ -178,7 +179,7 @@ BOOST_AUTO_TEST_CASE(TestEventTimedWaitsTimeoutCase)
timed_waiter w1(event,result1,50);
boost::thread waitThread1(w1);
- BOOST_CHECK(waitForWaiters(event,1,10000));
+ BOOST_CHECK(waitForWaiters(event,1,100));
BOOST_CHECK(result1 == 0);
@@ -542,10 +543,19 @@ BOOST_AUTO_TEST_CASE(TestEventGroupTimedWait)
BOOST_CHECK(waitThread2.timed_join(BOOST_MILLIS(10000)));
}
+class AtomicGuard
+{
+ volatile long* val;
+public:
+ inline AtomicGuard(volatile long* val_) : val(val_) { if (val) AtomicIncrement(val); }
+ inline ~AtomicGuard() { if (val) AtomicDecrement(val); }
+};
+
#define TESTNUM 100000l
#define NUMTHREADS 100l
-CEvent g_event(true);
+CEvent* g_event = NULL;
+volatile long g_mutex;
class mass_waiter
{
@@ -555,11 +565,12 @@ public:
volatile bool waiting;
- mass_waiter() : event(g_event), waiting(false) {}
+ mass_waiter() : event(*g_event), waiting(false) {}
void operator()()
{
waiting = true;
+ AtomicGuard g(&g_mutex);
result = event.Wait();
waiting = false;
}
@@ -573,38 +584,54 @@ public:
volatile bool waiting;
- poll_mass_waiter() : event(g_event), waiting(false) {}
+ poll_mass_waiter() : event(*g_event), waiting(false) {}
void operator()()
{
waiting = true;
+ AtomicGuard g(&g_mutex);
while ((result = event.WaitMSec(0)) == false);
waiting = false;
}
};
-
-BOOST_AUTO_TEST_CASE(TestMassEvent)
+static bool waitForThread(volatile long& mutex, int numWaiters, int milliseconds)
{
- boost::shared_array<mass_waiter> m;
- m.reset(new mass_waiter[NUMTHREADS]);
+ CCriticalSection sec;
+ for( int i = 0; i < milliseconds; i++)
+ {
+ if (mutex == (long)numWaiters)
+ return true;
+
+ {
+ CSingleLock tmplock(sec); // kick any memory syncs
+ }
+ Sleep(1);
+ }
+ return false;
+}
+template <class W> void RunMassEventTest(boost::shared_array<W>& m, bool canWaitOnEvent)
+{
boost::shared_array<boost::thread> t;
t.reset(new boost::thread[NUMTHREADS]);
for(size_t i=0; i<NUMTHREADS; i++)
t[i] = boost::thread(boost::ref(m[i]));
- for(size_t i=0; i<NUMTHREADS; i++)
+ BOOST_CHECK(waitForThread(g_mutex,NUMTHREADS,10000));
+ if (canWaitOnEvent)
{
- BOOST_CHECK(waitForWaiters(g_event,NUMTHREADS,10000));
+ BOOST_CHECK(waitForWaiters(*g_event,NUMTHREADS,10000));
}
+ Sleep(100);// give them a little more time
+
for(size_t i=0; i<NUMTHREADS; i++)
{
BOOST_CHECK(m[i].waiting);
}
- g_event.Set();
+ g_event->Set();
for(size_t i=0; i<NUMTHREADS; i++)
{
@@ -616,5 +643,27 @@ BOOST_AUTO_TEST_CASE(TestMassEvent)
BOOST_CHECK(!m[i].waiting);
BOOST_CHECK(m[i].result);
}
+}
+
+
+BOOST_AUTO_TEST_CASE(TestMassEvent)
+{
+ g_event = new CEvent();
+
+ boost::shared_array<mass_waiter> m;
+ m.reset(new mass_waiter[NUMTHREADS]);
+
+ RunMassEventTest(m,true);
+ delete g_event;
+}
+
+BOOST_AUTO_TEST_CASE(TestMassEventPolling)
+{
+ g_event = new CEvent(true); // polling needs to avoid the auto-reset
+
+ boost::shared_array<poll_mass_waiter> m;
+ m.reset(new poll_mass_waiter[NUMTHREADS]);
+ RunMassEventTest(m,false);
+ delete g_event;
}
diff --git a/xbmc/threads/test/TestSharedSection.cpp b/xbmc/threads/test/TestSharedSection.cpp
index 9cdf942b89..0eea876c4d 100644
--- a/xbmc/threads/test/TestSharedSection.cpp
+++ b/xbmc/threads/test/TestSharedSection.cpp
@@ -23,6 +23,8 @@
#include "threads/SharedSection.h"
#include "threads/SingleLock.h"
+#include "threads/Event.h"
+#include "threads/Atomics.h"
#include <boost/thread/thread.hpp>
#include <stdio.h>
@@ -31,26 +33,70 @@
// Helper classes
//=============================================================================
+#define BOOST_MILLIS(x) (boost::get_system_time() + boost::posix_time::milliseconds(x))
+
static void Sleep(unsigned int millis) { boost::thread::sleep(boost::get_system_time() + boost::posix_time::milliseconds(millis)); }
+static bool waitForThread(volatile long& mutex, int numWaiters, int milliseconds)
+{
+ CCriticalSection sec;
+ for( int i = 0; i < milliseconds; i++)
+ {
+ if (mutex == (long)numWaiters)
+ return true;
+
+ {
+ CSingleLock tmplock(sec); // kick any memory syncs
+ }
+ Sleep(1);
+ }
+ return false;
+}
+
+template<class E> static bool waitForWaiters(E& event, int numWaiters, int milliseconds)
+{
+ for( int i = 0; i < milliseconds; i++)
+ {
+ if (event.getNumWaits() == numWaiters)
+ return true;
+ Sleep(1);
+ }
+ return false;
+}
+
+class AtomicGuard
+{
+ volatile long* val;
+public:
+ inline AtomicGuard(volatile long* val_) : val(val_) { if (val) AtomicIncrement(val); }
+ inline ~AtomicGuard() { if (val) AtomicDecrement(val); }
+};
+
template<class L>
class locker
{
CSharedSection& sec;
- unsigned int wait;
+ CEvent* wait;
+
+ volatile long* mutex;
public:
volatile bool haslock;
volatile bool obtainedlock;
- locker(CSharedSection& o, unsigned int waitTime = 0) : sec(o), wait(waitTime), haslock(false), obtainedlock(false) {}
+ inline locker(CSharedSection& o, volatile long* mutex_ = NULL, CEvent* wait_ = NULL) :
+ sec(o), wait(wait_), mutex(mutex_), haslock(false), obtainedlock(false) {}
+
+ inline locker(CSharedSection& o, CEvent* wait_ = NULL) :
+ sec(o), wait(wait_), mutex(NULL), haslock(false), obtainedlock(false) {}
void operator()()
{
+ AtomicGuard g(mutex);
L lock(sec);
haslock = true;
obtainedlock = true;
if (wait)
- Sleep(wait);
+ wait->Wait();
haslock = false;
}
};
@@ -73,23 +119,32 @@ BOOST_AUTO_TEST_CASE(TestSharedSectionCase)
BOOST_AUTO_TEST_CASE(TestGetSharedLockWhileTryingExclusiveLock)
{
+ volatile long mutex = 0;
+ CEvent event;
+
CSharedSection sec;
CSharedLock l1(sec); // get a shared lock
- locker<CExclusiveLock> l2(sec);
+ locker<CExclusiveLock> l2(sec,&mutex);
boost::thread waitThread1(boost::ref(l2)); // try to get an exclusive lock
- Sleep(10);
+
+ BOOST_CHECK(waitForThread(mutex,1,10000));
+ Sleep(10); // still need to give it a chance to move ahead
+
BOOST_CHECK(!l2.haslock); // this thread is waiting ...
BOOST_CHECK(!l2.obtainedlock); // this thread is waiting ...
// now try and get a SharedLock
- locker<CSharedLock> l3(sec,50);
+ locker<CSharedLock> l3(sec,&mutex,&event);
boost::thread waitThread3(boost::ref(l3)); // try to get a shared lock
+ BOOST_CHECK(waitForThread(mutex,2,10000));
Sleep(10);
BOOST_CHECK(l3.haslock);
- Sleep(50);
+ event.Set();
+ BOOST_CHECK(waitThread3.timed_join(BOOST_MILLIS(10000)));
+
// l3 should have released.
BOOST_CHECK(!l3.haslock);
@@ -100,43 +155,52 @@ BOOST_AUTO_TEST_CASE(TestGetSharedLockWhileTryingExclusiveLock)
// let it go
l1.Leave(); // the last shared lock leaves.
- Sleep(10); // give the exclusive lock some time
+ BOOST_CHECK(waitThread1.timed_join(BOOST_MILLIS(10000)));
BOOST_CHECK(l2.obtainedlock); // the exclusive lock was captured
BOOST_CHECK(!l2.haslock); // ... but it doesn't have it anymore
-
- Sleep(50);
}
BOOST_AUTO_TEST_CASE(TestSharedSection2Case)
{
CSharedSection sec;
- locker<CSharedLock> l1(sec,20);
+ CEvent event;
+ volatile long mutex = 0;
+
+ locker<CSharedLock> l1(sec,&mutex,&event);
{
CSharedLock lock(sec);
boost::thread waitThread1(boost::ref(l1));
- Sleep(10);
+ BOOST_CHECK(waitForWaiters(event,1,10000));
BOOST_CHECK(l1.haslock);
- waitThread1.join();
+ event.Set();
+
+ BOOST_CHECK(waitThread1.timed_join(BOOST_MILLIS(10000)));
}
- locker<CSharedLock> l2(sec,20);
+ locker<CSharedLock> l2(sec,&mutex,&event);
{
- CExclusiveLock lock(sec);
- boost::thread waitThread1(boost::ref(l2));
+ CExclusiveLock lock(sec); // get exclusive lock
+ boost::thread waitThread2(boost::ref(l2)); // thread should block
+
+ BOOST_CHECK(waitForThread(mutex,1,10000));
+ Sleep(10);
- Sleep(5);
BOOST_CHECK(!l2.haslock);
lock.Leave();
- Sleep(5);
+
+ BOOST_CHECK(waitForWaiters(event,1,10000));
+ Sleep(10);
BOOST_CHECK(l2.haslock);
+
+ event.Set();
- waitThread1.join();
+ BOOST_CHECK(waitThread2.timed_join(BOOST_MILLIS(10000)));
}
}
@@ -144,22 +208,29 @@ BOOST_AUTO_TEST_CASE(TestMultipleSharedSectionCase)
{
CSharedSection sec;
- locker<CSharedLock> l1(sec,20);
+ CEvent event;
+ volatile long mutex = 0;
+
+ locker<CSharedLock> l1(sec,&mutex, &event);
{
CSharedLock lock(sec);
boost::thread waitThread1(boost::ref(l1));
+ BOOST_CHECK(waitForThread(mutex,1,10000));
Sleep(10);
+
BOOST_CHECK(l1.haslock);
- waitThread1.join();
+ event.Set();
+
+ BOOST_CHECK(waitThread1.timed_join(BOOST_MILLIS(10000)));
}
- locker<CSharedLock> l2(sec,50);
- locker<CSharedLock> l3(sec,50);
- locker<CSharedLock> l4(sec,50);
- locker<CSharedLock> l5(sec,50);
+ locker<CSharedLock> l2(sec,&mutex,&event);
+ locker<CSharedLock> l3(sec,&mutex,&event);
+ locker<CSharedLock> l4(sec,&mutex,&event);
+ locker<CSharedLock> l5(sec,&mutex,&event);
{
CExclusiveLock lock(sec);
boost::thread waitThread1(boost::ref(l2));
@@ -167,7 +238,9 @@ BOOST_AUTO_TEST_CASE(TestMultipleSharedSectionCase)
boost::thread waitThread3(boost::ref(l4));
boost::thread waitThread4(boost::ref(l5));
- Sleep(5);
+ BOOST_CHECK(waitForThread(mutex,4,10000));
+ Sleep(10);
+
BOOST_CHECK(!l2.haslock);
BOOST_CHECK(!l3.haslock);
BOOST_CHECK(!l4.haslock);
@@ -175,16 +248,19 @@ BOOST_AUTO_TEST_CASE(TestMultipleSharedSectionCase)
lock.Leave();
- Sleep(5);
+ BOOST_CHECK(waitForWaiters(event,4,10000));
+
BOOST_CHECK(l2.haslock);
BOOST_CHECK(l3.haslock);
BOOST_CHECK(l4.haslock);
BOOST_CHECK(l5.haslock);
+
+ event.Set();
- waitThread1.join();
- waitThread2.join();
- waitThread3.join();
- waitThread4.join();
+ BOOST_CHECK(waitThread1.timed_join(BOOST_MILLIS(10000)));
+ BOOST_CHECK(waitThread2.timed_join(BOOST_MILLIS(10000)));
+ BOOST_CHECK(waitThread3.timed_join(BOOST_MILLIS(10000)));
+ BOOST_CHECK(waitThread4.timed_join(BOOST_MILLIS(10000)));
}
}