290 lines
6.9 KiB
C++
290 lines
6.9 KiB
C++
// Copyright (C) 2001-2003
|
|
// William E. Kempf
|
|
//
|
|
// Copyright Frank Mori Hess 2009
|
|
//
|
|
// Use, modification and
|
|
// distribution is subject to the Boost Software License, Version
|
|
// 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
|
// http://www.boost.org/LICENSE_1_0.txt)
|
|
|
|
// This is a simplified/modified version of libs/thread/test/test_mutex.cpp
|
|
// added to test boost::signals2::mutex.
|
|
// For more information, see http://www.boost.org
|
|
|
|
// note boost/test/minimal.hpp can cause windows.h to get included, which
|
|
// can screw up our checks of _WIN32_WINNT if it is included
|
|
// after boost/signals2/mutex.hpp. Frank Hess 2009-03-07.
|
|
#include <boost/test/minimal.hpp>
|
|
|
|
#include <boost/bind.hpp>
|
|
#include <boost/signals2/dummy_mutex.hpp>
|
|
#include <boost/signals2/mutex.hpp>
|
|
#include <boost/thread/locks.hpp>
|
|
#include <boost/thread/mutex.hpp>
|
|
#include <boost/thread/thread.hpp>
|
|
#include <boost/thread/thread_time.hpp>
|
|
#include <boost/thread/condition.hpp>
|
|
|
|
class execution_monitor
|
|
{
|
|
public:
|
|
execution_monitor(int secs)
|
|
: done(false), m_secs(secs) { }
|
|
void start()
|
|
{
|
|
boost::mutex::scoped_lock lock(mutex);
|
|
done = false;
|
|
}
|
|
void finish()
|
|
{
|
|
boost::mutex::scoped_lock lock(mutex);
|
|
done = true;
|
|
cond.notify_one();
|
|
}
|
|
bool wait()
|
|
{
|
|
boost::posix_time::time_duration timeout = boost::posix_time::seconds(m_secs);
|
|
boost::mutex::scoped_lock lock(mutex);
|
|
while (!done) {
|
|
if (!cond.timed_wait(lock, timeout))
|
|
break;
|
|
}
|
|
return done;
|
|
}
|
|
|
|
private:
|
|
boost::mutex mutex;
|
|
boost::condition cond;
|
|
bool done;
|
|
int m_secs;
|
|
};
|
|
|
|
template <typename F>
|
|
class indirect_adapter
|
|
{
|
|
public:
|
|
indirect_adapter(F func, execution_monitor& monitor)
|
|
: m_func(func), m_monitor(monitor) { }
|
|
void operator()() const
|
|
{
|
|
try
|
|
{
|
|
boost::thread thrd(m_func);
|
|
thrd.join();
|
|
}
|
|
catch (...)
|
|
{
|
|
m_monitor.finish();
|
|
throw;
|
|
}
|
|
m_monitor.finish();
|
|
}
|
|
|
|
private:
|
|
F m_func;
|
|
execution_monitor& m_monitor;
|
|
void operator=(indirect_adapter&);
|
|
};
|
|
|
|
template <typename F>
|
|
void timed_test(F func, int secs)
|
|
{
|
|
execution_monitor monitor(secs);
|
|
indirect_adapter<F> ifunc(func, monitor);
|
|
monitor.start();
|
|
boost::thread thrd(ifunc);
|
|
BOOST_REQUIRE(monitor.wait()); // Timed test didn't complete in time, possible deadlock
|
|
}
|
|
|
|
template <typename M>
|
|
struct test_lock
|
|
{
|
|
typedef M mutex_type;
|
|
typedef typename boost::unique_lock<M> lock_type;
|
|
|
|
void operator()()
|
|
{
|
|
mutex_type mutex;
|
|
boost::condition condition;
|
|
|
|
// Test the lock's constructors.
|
|
{
|
|
lock_type lock(mutex, boost::defer_lock);
|
|
BOOST_CHECK(!lock);
|
|
}
|
|
lock_type lock(mutex);
|
|
BOOST_CHECK(lock ? true : false);
|
|
|
|
// Construct a fast time out.
|
|
boost::posix_time::time_duration timeout = boost::posix_time::milliseconds(100);
|
|
|
|
// Test the lock and the mutex with condition variables.
|
|
// No one is going to notify this condition variable. We expect to
|
|
// time out.
|
|
BOOST_CHECK(!condition.timed_wait(lock, timeout));
|
|
BOOST_CHECK(lock ? true : false);
|
|
|
|
// Test the lock and unlock methods.
|
|
lock.unlock();
|
|
BOOST_CHECK(!lock);
|
|
lock.lock();
|
|
BOOST_CHECK(lock ? true : false);
|
|
}
|
|
};
|
|
|
|
template <typename M>
|
|
struct test_trylock
|
|
{
|
|
typedef M mutex_type;
|
|
typedef typename boost::unique_lock<M> lock_type;
|
|
|
|
void operator()()
|
|
{
|
|
mutex_type mutex;
|
|
boost::condition condition;
|
|
|
|
// Test the lock's constructors.
|
|
{
|
|
lock_type lock(mutex, boost::try_to_lock);
|
|
BOOST_CHECK(lock ? true : false);
|
|
}
|
|
{
|
|
lock_type lock(mutex, boost::defer_lock);
|
|
BOOST_CHECK(!lock);
|
|
}
|
|
lock_type lock(mutex, boost::try_to_lock);
|
|
BOOST_CHECK(lock ? true : false);
|
|
|
|
// Construct a fast time out.
|
|
boost::posix_time::time_duration timeout = boost::posix_time::milliseconds(100);
|
|
|
|
// Test the lock and the mutex with condition variables.
|
|
// No one is going to notify this condition variable. We expect to
|
|
// time out.
|
|
BOOST_CHECK(!condition.timed_wait(lock, timeout));
|
|
BOOST_CHECK(lock ? true : false);
|
|
|
|
// Test the lock, unlock and trylock methods.
|
|
lock.unlock();
|
|
BOOST_CHECK(!lock);
|
|
lock.lock();
|
|
BOOST_CHECK(lock ? true : false);
|
|
lock.unlock();
|
|
BOOST_CHECK(!lock);
|
|
BOOST_CHECK(lock.try_lock());
|
|
BOOST_CHECK(lock ? true : false);
|
|
}
|
|
};
|
|
|
|
template<typename Mutex>
|
|
struct test_lock_exclusion
|
|
{
|
|
typedef boost::unique_lock<Mutex> Lock;
|
|
|
|
Mutex m;
|
|
boost::mutex done_mutex;
|
|
bool done;
|
|
bool locked;
|
|
boost::condition_variable done_cond;
|
|
|
|
test_lock_exclusion():
|
|
done(false),locked(false)
|
|
{}
|
|
|
|
void locking_thread()
|
|
{
|
|
Lock lock(m);
|
|
|
|
boost::lock_guard<boost::mutex> lk(done_mutex);
|
|
locked=lock.owns_lock();
|
|
done=true;
|
|
done_cond.notify_one();
|
|
}
|
|
|
|
bool is_done() const
|
|
{
|
|
return done;
|
|
}
|
|
|
|
typedef test_lock_exclusion<Mutex> this_type;
|
|
|
|
void do_test(void (this_type::*test_func)())
|
|
{
|
|
Lock lock(m);
|
|
|
|
{
|
|
boost::lock_guard<boost::mutex> lk(done_mutex);
|
|
locked=false;
|
|
}
|
|
|
|
done=false;
|
|
|
|
boost::thread t(test_func,this);
|
|
|
|
try
|
|
{
|
|
{
|
|
boost::mutex::scoped_lock lk(done_mutex);
|
|
BOOST_CHECK(!done_cond.timed_wait(lk, boost::posix_time::seconds(1),
|
|
boost::bind(&this_type::is_done,this)));
|
|
}
|
|
lock.unlock();
|
|
{
|
|
boost::mutex::scoped_lock lk(done_mutex);
|
|
BOOST_CHECK(done_cond.timed_wait(lk, boost::posix_time::seconds(1),
|
|
boost::bind(&this_type::is_done,this)));
|
|
}
|
|
t.join();
|
|
BOOST_CHECK(locked);
|
|
}
|
|
catch(...)
|
|
{
|
|
lock.unlock();
|
|
t.join();
|
|
throw;
|
|
}
|
|
}
|
|
|
|
|
|
void operator()()
|
|
{
|
|
do_test(&this_type::locking_thread);
|
|
}
|
|
};
|
|
|
|
|
|
void do_test_mutex()
|
|
{
|
|
test_lock<boost::signals2::mutex>()();
|
|
// try_lock not supported on old versions of windows
|
|
#if !defined(BOOST_HAS_WINTHREADS) || (defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0400))
|
|
test_trylock<boost::signals2::mutex>()();
|
|
#endif
|
|
test_lock_exclusion<boost::signals2::mutex>()();
|
|
}
|
|
|
|
void test_mutex()
|
|
{
|
|
timed_test(&do_test_mutex, 3);
|
|
}
|
|
|
|
void do_test_dummy_mutex()
|
|
{
|
|
test_lock<boost::signals2::dummy_mutex>()();
|
|
test_trylock<boost::signals2::dummy_mutex>()();
|
|
}
|
|
|
|
void test_dummy_mutex()
|
|
{
|
|
timed_test(&do_test_dummy_mutex, 2);
|
|
}
|
|
|
|
int test_main(int, char*[])
|
|
{
|
|
test_mutex();
|
|
test_dummy_mutex();
|
|
|
|
return 0;
|
|
}
|