Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r62107 - sandbox/chrono/libs/thread/test
From: vicente.botet_at_[hidden]
Date: 2010-05-20 03:56:04


Author: viboes
Date: 2010-05-20 03:55:54 EDT (Thu, 20 May 2010)
New Revision: 62107
URL: http://svn.boost.org/trac/boost/changeset/62107

Log:
Boost.Chrono: Add Boost.Threads 1.43: port to Boost.Chrono to conform with C++0x
Added:
   sandbox/chrono/libs/thread/test/
   sandbox/chrono/libs/thread/test/Carbon.r (contents, props changed)
   sandbox/chrono/libs/thread/test/Jamfile.v2 (contents, props changed)
   sandbox/chrono/libs/thread/test/condition_test_common.hpp (contents, props changed)
   sandbox/chrono/libs/thread/test/no_implicit_assign_from_lvalue_thread.cpp (contents, props changed)
   sandbox/chrono/libs/thread/test/no_implicit_move_from_lvalue_thread.cpp (contents, props changed)
   sandbox/chrono/libs/thread/test/shared_mutex_locking_thread.hpp (contents, props changed)
   sandbox/chrono/libs/thread/test/test.mcp (contents, props changed)
   sandbox/chrono/libs/thread/test/test_barrier.cpp (contents, props changed)
   sandbox/chrono/libs/thread/test/test_condition.cpp (contents, props changed)
   sandbox/chrono/libs/thread/test/test_condition_notify_all.cpp (contents, props changed)
   sandbox/chrono/libs/thread/test/test_condition_notify_one.cpp (contents, props changed)
   sandbox/chrono/libs/thread/test/test_condition_timed_wait_times_out.cpp (contents, props changed)
   sandbox/chrono/libs/thread/test/test_futures.cpp (contents, props changed)
   sandbox/chrono/libs/thread/test/test_generic_locks.cpp (contents, props changed)
   sandbox/chrono/libs/thread/test/test_hardware_concurrency.cpp (contents, props changed)
   sandbox/chrono/libs/thread/test/test_lock_concept.cpp (contents, props changed)
   sandbox/chrono/libs/thread/test/test_move_function.cpp (contents, props changed)
   sandbox/chrono/libs/thread/test/test_mutex.cpp (contents, props changed)
   sandbox/chrono/libs/thread/test/test_once.cpp (contents, props changed)
   sandbox/chrono/libs/thread/test/test_shared_mutex.cpp (contents, props changed)
   sandbox/chrono/libs/thread/test/test_shared_mutex_part_2.cpp (contents, props changed)
   sandbox/chrono/libs/thread/test/test_shared_mutex_timed_locks.cpp (contents, props changed)
   sandbox/chrono/libs/thread/test/test_thread.cpp (contents, props changed)
   sandbox/chrono/libs/thread/test/test_thread_exit.cpp (contents, props changed)
   sandbox/chrono/libs/thread/test/test_thread_id.cpp (contents, props changed)
   sandbox/chrono/libs/thread/test/test_thread_launching.cpp (contents, props changed)
   sandbox/chrono/libs/thread/test/test_thread_mf.cpp (contents, props changed)
   sandbox/chrono/libs/thread/test/test_thread_move.cpp (contents, props changed)
   sandbox/chrono/libs/thread/test/test_thread_move_return.cpp (contents, props changed)
   sandbox/chrono/libs/thread/test/test_thread_return_local.cpp (contents, props changed)
   sandbox/chrono/libs/thread/test/test_tss.cpp (contents, props changed)
   sandbox/chrono/libs/thread/test/test_xtime.cpp (contents, props changed)
   sandbox/chrono/libs/thread/test/util.inl (contents, props changed)

Added: sandbox/chrono/libs/thread/test/Carbon.r
==============================================================================
--- (empty file)
+++ sandbox/chrono/libs/thread/test/Carbon.r 2010-05-20 03:55:54 EDT (Thu, 20 May 2010)
@@ -0,0 +1,18 @@
+/*
+ * Permit this Carbon application to launch on OS X
+ *
+ * © 1997-2000 Metrowerks Corp.
+ *
+ * Questions and comments to:
+ * <mailto:support_at_[hidden]>
+ * <http://www.metrowerks.com/>
+ */
+
+
+/*----------------------------carb ¥ Carbon on OS X launch information --------------------------*/
+type 'carb' {
+};
+
+
+resource 'carb'(0) {
+};

Added: sandbox/chrono/libs/thread/test/Jamfile.v2
==============================================================================
--- (empty file)
+++ sandbox/chrono/libs/thread/test/Jamfile.v2 2010-05-20 03:55:54 EDT (Thu, 20 May 2010)
@@ -0,0 +1,65 @@
+# (C) Copyright William E. Kempf 2001.
+# (C) Copyright 2007 Anthony Williams.
+# Distributed under 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)
+#
+# Boost.Threads test Jamfile
+#
+# Additional configuration variables used:
+# 1. PTW32 may be used on Win32 platforms to specify that the pthreads-win32
+# library should be used instead of "native" threads. This feature is
+# mostly used for testing and it's generally recommended you use the
+# native threading libraries instead. PTW32 should be set to be a list
+# of two strings, the first specifying the installation path of the
+# pthreads-win32 library and the second specifying which library
+# variant to link against (see the pthreads-win32 documentation).
+# Example: jam -sPTW32="c:\pthreads-win32 pthreadVCE.lib"
+
+# bring in rules for testing
+import testing ;
+
+project
+ : requirements <library>/boost/test//boost_unit_test_framework/<link>static
+ <threading>multi
+ ;
+
+rule thread-run ( sources )
+{
+ return
+ [ run $(sources) ../build//boost_thread ]
+ [ run $(sources) ../src/tss_null.cpp ../build//boost_thread/<link>static
+ : : : : $(sources[1]:B)_lib ]
+ ;
+}
+
+{
+ test-suite "threads"
+ : [ thread-run test_thread.cpp ]
+ [ thread-run test_thread_id.cpp ]
+ [ thread-run test_hardware_concurrency.cpp ]
+ [ thread-run test_thread_move.cpp ]
+ [ thread-run test_thread_return_local.cpp ]
+ [ thread-run test_thread_move_return.cpp ]
+ [ thread-run test_thread_launching.cpp ]
+ [ thread-run test_thread_mf.cpp ]
+ [ thread-run test_thread_exit.cpp ]
+ [ thread-run test_move_function.cpp ]
+ [ thread-run test_mutex.cpp ]
+ [ thread-run test_condition_notify_one.cpp ]
+ [ thread-run test_condition_timed_wait_times_out.cpp ]
+ [ thread-run test_condition_notify_all.cpp ]
+ [ thread-run test_condition.cpp ]
+ [ thread-run test_tss.cpp ]
+ [ thread-run test_once.cpp ]
+ [ thread-run test_xtime.cpp ]
+ [ thread-run test_barrier.cpp ]
+ [ thread-run test_shared_mutex.cpp ]
+ [ thread-run test_shared_mutex_part_2.cpp ]
+ [ thread-run test_shared_mutex_timed_locks.cpp ]
+ [ thread-run test_lock_concept.cpp ]
+ [ thread-run test_generic_locks.cpp ]
+ [ thread-run test_futures.cpp ]
+ [ compile-fail no_implicit_move_from_lvalue_thread.cpp ]
+ [ compile-fail no_implicit_assign_from_lvalue_thread.cpp ]
+ ;
+}

Added: sandbox/chrono/libs/thread/test/condition_test_common.hpp
==============================================================================
--- (empty file)
+++ sandbox/chrono/libs/thread/test/condition_test_common.hpp 2010-05-20 03:55:54 EDT (Thu, 20 May 2010)
@@ -0,0 +1,97 @@
+#ifndef CONDITION_TEST_COMMON_HPP
+#define CONDITION_TEST_COMMON_HPP
+// Copyright (C) 2007 Anthony Williams
+//
+// Distributed under 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)
+
+#include <boost/thread/condition_variable.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/thread_time.hpp>
+
+unsigned const timeout_seconds=5;
+
+struct wait_for_flag
+{
+ boost::mutex mutex;
+ boost::condition_variable cond_var;
+ bool flag;
+ unsigned woken;
+
+ wait_for_flag():
+ flag(false),woken(0)
+ {}
+
+ struct check_flag
+ {
+ bool const& flag;
+
+ check_flag(bool const& flag_):
+ flag(flag_)
+ {}
+
+ bool operator()() const
+ {
+ return flag;
+ }
+ private:
+ void operator=(check_flag&);
+ };
+
+
+ void wait_without_predicate()
+ {
+ boost::mutex::scoped_lock lock(mutex);
+ while(!flag)
+ {
+ cond_var.wait(lock);
+ }
+ ++woken;
+ }
+
+ void wait_with_predicate()
+ {
+ boost::mutex::scoped_lock lock(mutex);
+ cond_var.wait(lock,check_flag(flag));
+ if(flag)
+ {
+ ++woken;
+ }
+ }
+
+ void timed_wait_without_predicate()
+ {
+ boost::system_time const timeout=boost::get_system_time()+boost::posix_time::seconds(timeout_seconds);
+
+ boost::mutex::scoped_lock lock(mutex);
+ while(!flag)
+ {
+ if(!cond_var.timed_wait(lock,timeout))
+ {
+ return;
+ }
+ }
+ ++woken;
+ }
+
+ void timed_wait_with_predicate()
+ {
+ boost::system_time const timeout=boost::get_system_time()+boost::posix_time::seconds(timeout_seconds);
+ boost::mutex::scoped_lock lock(mutex);
+ if(cond_var.timed_wait(lock,timeout,check_flag(flag)) && flag)
+ {
+ ++woken;
+ }
+ }
+ void relative_timed_wait_with_predicate()
+ {
+ boost::mutex::scoped_lock lock(mutex);
+ if(cond_var.timed_wait(lock,boost::posix_time::seconds(timeout_seconds),check_flag(flag)) && flag)
+ {
+ ++woken;
+ }
+ }
+};
+
+
+#endif

Added: sandbox/chrono/libs/thread/test/no_implicit_assign_from_lvalue_thread.cpp
==============================================================================
--- (empty file)
+++ sandbox/chrono/libs/thread/test/no_implicit_assign_from_lvalue_thread.cpp 2010-05-20 03:55:54 EDT (Thu, 20 May 2010)
@@ -0,0 +1,15 @@
+// Copyright (C) 2008 Anthony Williams
+//
+// Distributed under 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)
+#include <boost/thread/thread.hpp>
+
+void do_nothing()
+{}
+
+void test()
+{
+ boost::thread t1(do_nothing);
+ boost::thread t2;
+ t2=t1;
+}

Added: sandbox/chrono/libs/thread/test/no_implicit_move_from_lvalue_thread.cpp
==============================================================================
--- (empty file)
+++ sandbox/chrono/libs/thread/test/no_implicit_move_from_lvalue_thread.cpp 2010-05-20 03:55:54 EDT (Thu, 20 May 2010)
@@ -0,0 +1,14 @@
+// Copyright (C) 2008 Anthony Williams
+//
+// Distributed under 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)
+#include <boost/thread/thread.hpp>
+
+void do_nothing()
+{}
+
+void test()
+{
+ boost::thread t1(do_nothing);
+ boost::thread t2(t1);
+}

Added: sandbox/chrono/libs/thread/test/shared_mutex_locking_thread.hpp
==============================================================================
--- (empty file)
+++ sandbox/chrono/libs/thread/test/shared_mutex_locking_thread.hpp 2010-05-20 03:55:54 EDT (Thu, 20 May 2010)
@@ -0,0 +1,132 @@
+#ifndef SHARED_MUTEX_LOCKING_THREAD_HPP
+#define SHARED_MUTEX_LOCKING_THREAD_HPP
+
+// (C) Copyright 2008 Anthony Williams
+//
+// Distributed under 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)
+
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/condition_variable.hpp>
+#include <boost/thread/shared_mutex.hpp>
+
+template<typename lock_type>
+class locking_thread
+{
+ boost::shared_mutex& rw_mutex;
+ unsigned& unblocked_count;
+ boost::condition_variable& unblocked_condition;
+ unsigned& simultaneous_running_count;
+ unsigned& max_simultaneous_running;
+ boost::mutex& unblocked_count_mutex;
+ boost::mutex& finish_mutex;
+public:
+ locking_thread(boost::shared_mutex& rw_mutex_,
+ unsigned& unblocked_count_,
+ boost::mutex& unblocked_count_mutex_,
+ boost::condition_variable& unblocked_condition_,
+ boost::mutex& finish_mutex_,
+ unsigned& simultaneous_running_count_,
+ unsigned& max_simultaneous_running_):
+ rw_mutex(rw_mutex_),
+ unblocked_count(unblocked_count_),
+ unblocked_condition(unblocked_condition_),
+ simultaneous_running_count(simultaneous_running_count_),
+ max_simultaneous_running(max_simultaneous_running_),
+ unblocked_count_mutex(unblocked_count_mutex_),
+ finish_mutex(finish_mutex_)
+ {}
+
+ void operator()()
+ {
+ // acquire lock
+ lock_type lock(rw_mutex);
+
+ // increment count to show we're unblocked
+ {
+ boost::mutex::scoped_lock ublock(unblocked_count_mutex);
+ ++unblocked_count;
+ unblocked_condition.notify_one();
+ ++simultaneous_running_count;
+ if(simultaneous_running_count>max_simultaneous_running)
+ {
+ max_simultaneous_running=simultaneous_running_count;
+ }
+ }
+
+ // wait to finish
+ boost::mutex::scoped_lock finish_lock(finish_mutex);
+ {
+ boost::mutex::scoped_lock ublock(unblocked_count_mutex);
+ --simultaneous_running_count;
+ }
+ }
+private:
+ void operator=(locking_thread&);
+};
+
+class simple_writing_thread
+{
+ boost::shared_mutex& rwm;
+ boost::mutex& finish_mutex;
+ boost::mutex& unblocked_mutex;
+ unsigned& unblocked_count;
+
+ void operator=(simple_writing_thread&);
+
+public:
+ simple_writing_thread(boost::shared_mutex& rwm_,
+ boost::mutex& finish_mutex_,
+ boost::mutex& unblocked_mutex_,
+ unsigned& unblocked_count_):
+ rwm(rwm_),finish_mutex(finish_mutex_),
+ unblocked_mutex(unblocked_mutex_),unblocked_count(unblocked_count_)
+ {}
+
+ void operator()()
+ {
+ boost::unique_lock<boost::shared_mutex> lk(rwm);
+
+ {
+ boost::mutex::scoped_lock ulk(unblocked_mutex);
+ ++unblocked_count;
+ }
+
+ boost::mutex::scoped_lock flk(finish_mutex);
+ }
+};
+
+class simple_reading_thread
+{
+ boost::shared_mutex& rwm;
+ boost::mutex& finish_mutex;
+ boost::mutex& unblocked_mutex;
+ unsigned& unblocked_count;
+
+ void operator=(simple_reading_thread&);
+
+public:
+ simple_reading_thread(boost::shared_mutex& rwm_,
+ boost::mutex& finish_mutex_,
+ boost::mutex& unblocked_mutex_,
+ unsigned& unblocked_count_):
+ rwm(rwm_),finish_mutex(finish_mutex_),
+ unblocked_mutex(unblocked_mutex_),unblocked_count(unblocked_count_)
+ {}
+
+ void operator()()
+ {
+ boost::shared_lock<boost::shared_mutex> lk(rwm);
+
+ {
+ boost::mutex::scoped_lock ulk(unblocked_mutex);
+ ++unblocked_count;
+ }
+
+ boost::mutex::scoped_lock flk(finish_mutex);
+ }
+};
+
+
+#endif

Added: sandbox/chrono/libs/thread/test/test.mcp
==============================================================================
Binary file. No diff available.

Added: sandbox/chrono/libs/thread/test/test_barrier.cpp
==============================================================================
--- (empty file)
+++ sandbox/chrono/libs/thread/test/test_barrier.cpp 2010-05-20 03:55:54 EDT (Thu, 20 May 2010)
@@ -0,0 +1,66 @@
+// Copyright (C) 2001-2003
+// William E. Kempf
+//
+// Distributed under 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)
+
+#include <boost/thread/detail/config.hpp>
+
+#include <boost/thread/thread.hpp>
+#include <boost/thread/barrier.hpp>
+
+#include <boost/test/unit_test.hpp>
+#include <vector>
+
+namespace {
+
+// Shared variables for generation barrier test
+const int N_THREADS=10;
+boost::barrier gen_barrier(N_THREADS);
+boost::mutex mutex;
+long global_parameter;
+
+void barrier_thread()
+{
+ for (int i = 0; i < 5; ++i)
+ {
+ if (gen_barrier.wait())
+ {
+ boost::mutex::scoped_lock lock(mutex);
+ global_parameter++;
+ }
+ }
+}
+
+} // namespace
+
+void test_barrier()
+{
+ boost::thread_group g;
+ global_parameter = 0;
+
+ try
+ {
+ for (int i = 0; i < N_THREADS; ++i)
+ g.create_thread(&barrier_thread);
+ g.join_all();
+ }
+ catch(...)
+ {
+ g.interrupt_all();
+ g.join_all();
+ throw;
+ }
+
+ BOOST_CHECK_EQUAL(global_parameter,5);
+}
+
+boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
+{
+ boost::unit_test_framework::test_suite* test =
+ BOOST_TEST_SUITE("Boost.Threads: barrier test suite");
+
+ test->add(BOOST_TEST_CASE(&test_barrier));
+
+ return test;
+}

Added: sandbox/chrono/libs/thread/test/test_condition.cpp
==============================================================================
--- (empty file)
+++ sandbox/chrono/libs/thread/test/test_condition.cpp 2010-05-20 03:55:54 EDT (Thu, 20 May 2010)
@@ -0,0 +1,190 @@
+// Copyright (C) 2001-2003
+// William E. Kempf
+// Copyright (C) 2007 Anthony Williams
+//
+// Distributed under 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)
+
+#include <boost/thread/detail/config.hpp>
+
+#include <boost/thread/condition.hpp>
+#include <boost/thread/thread.hpp>
+#include <boost/thread/xtime.hpp>
+
+#include <boost/test/unit_test.hpp>
+
+#include <libs/thread/test/util.inl>
+
+struct condition_test_data
+{
+ condition_test_data() : notified(0), awoken(0) { }
+
+ boost::mutex mutex;
+ boost::condition_variable condition;
+ int notified;
+ int awoken;
+};
+
+void condition_test_thread(condition_test_data* data)
+{
+ boost::mutex::scoped_lock lock(data->mutex);
+ BOOST_CHECK(lock ? true : false);
+ while (!(data->notified > 0))
+ data->condition.wait(lock);
+ BOOST_CHECK(lock ? true : false);
+ data->awoken++;
+}
+
+struct cond_predicate
+{
+ cond_predicate(int& var, int val) : _var(var), _val(val) { }
+
+ bool operator()() { return _var == _val; }
+
+ int& _var;
+ int _val;
+private:
+ void operator=(cond_predicate&);
+
+};
+
+void condition_test_waits(condition_test_data* data)
+{
+ boost::mutex::scoped_lock lock(data->mutex);
+ BOOST_CHECK(lock ? true : false);
+
+ // Test wait.
+ while (data->notified != 1)
+ data->condition.wait(lock);
+ BOOST_CHECK(lock ? true : false);
+ BOOST_CHECK_EQUAL(data->notified, 1);
+ data->awoken++;
+ data->condition.notify_one();
+
+ // Test predicate wait.
+ data->condition.wait(lock, cond_predicate(data->notified, 2));
+ BOOST_CHECK(lock ? true : false);
+ BOOST_CHECK_EQUAL(data->notified, 2);
+ data->awoken++;
+ data->condition.notify_one();
+
+ // Test timed_wait.
+ boost::xtime xt = delay(10);
+ while (data->notified != 3)
+ data->condition.timed_wait(lock, xt);
+ BOOST_CHECK(lock ? true : false);
+ BOOST_CHECK_EQUAL(data->notified, 3);
+ data->awoken++;
+ data->condition.notify_one();
+
+ // Test predicate timed_wait.
+ xt = delay(10);
+ cond_predicate pred(data->notified, 4);
+ BOOST_CHECK(data->condition.timed_wait(lock, xt, pred));
+ BOOST_CHECK(lock ? true : false);
+ BOOST_CHECK(pred());
+ BOOST_CHECK_EQUAL(data->notified, 4);
+ data->awoken++;
+ data->condition.notify_one();
+
+ // Test predicate timed_wait with relative timeout
+ cond_predicate pred_rel(data->notified, 5);
+ BOOST_CHECK(data->condition.timed_wait(lock, boost::posix_time::seconds(10), pred_rel));
+ BOOST_CHECK(lock ? true : false);
+ BOOST_CHECK(pred_rel());
+ BOOST_CHECK_EQUAL(data->notified, 5);
+ data->awoken++;
+ data->condition.notify_one();
+}
+
+void do_test_condition_waits()
+{
+ condition_test_data data;
+
+ boost::thread thread(bind(&condition_test_waits, &data));
+
+ {
+ boost::mutex::scoped_lock lock(data.mutex);
+ BOOST_CHECK(lock ? true : false);
+
+ boost::thread::sleep(delay(1));
+ data.notified++;
+ data.condition.notify_one();
+ while (data.awoken != 1)
+ data.condition.wait(lock);
+ BOOST_CHECK(lock ? true : false);
+ BOOST_CHECK_EQUAL(data.awoken, 1);
+
+ boost::thread::sleep(delay(1));
+ data.notified++;
+ data.condition.notify_one();
+ while (data.awoken != 2)
+ data.condition.wait(lock);
+ BOOST_CHECK(lock ? true : false);
+ BOOST_CHECK_EQUAL(data.awoken, 2);
+
+ boost::thread::sleep(delay(1));
+ data.notified++;
+ data.condition.notify_one();
+ while (data.awoken != 3)
+ data.condition.wait(lock);
+ BOOST_CHECK(lock ? true : false);
+ BOOST_CHECK_EQUAL(data.awoken, 3);
+
+ boost::thread::sleep(delay(1));
+ data.notified++;
+ data.condition.notify_one();
+ while (data.awoken != 4)
+ data.condition.wait(lock);
+ BOOST_CHECK(lock ? true : false);
+ BOOST_CHECK_EQUAL(data.awoken, 4);
+
+
+ boost::thread::sleep(delay(1));
+ data.notified++;
+ data.condition.notify_one();
+ while (data.awoken != 5)
+ data.condition.wait(lock);
+ BOOST_CHECK(lock ? true : false);
+ BOOST_CHECK_EQUAL(data.awoken, 5);
+ }
+
+ thread.join();
+ BOOST_CHECK_EQUAL(data.awoken, 5);
+}
+
+void test_condition_waits()
+{
+ // We should have already tested notify_one here, so
+ // a timed test with the default execution_monitor::use_condition
+ // should be OK, and gives the fastest performance
+ timed_test(&do_test_condition_waits, 12);
+}
+
+void do_test_condition_wait_is_a_interruption_point()
+{
+ condition_test_data data;
+
+ boost::thread thread(bind(&condition_test_thread, &data));
+
+ thread.interrupt();
+ thread.join();
+ BOOST_CHECK_EQUAL(data.awoken,0);
+}
+
+
+void test_condition_wait_is_a_interruption_point()
+{
+ timed_test(&do_test_condition_wait_is_a_interruption_point, 1);
+}
+
+boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
+{
+ boost::unit_test_framework::test_suite* test =
+ BOOST_TEST_SUITE("Boost.Threads: condition test suite");
+
+ test->add(BOOST_TEST_CASE(&test_condition_waits));
+ test->add(BOOST_TEST_CASE(&test_condition_wait_is_a_interruption_point));
+
+ return test;
+}

Added: sandbox/chrono/libs/thread/test/test_condition_notify_all.cpp
==============================================================================
--- (empty file)
+++ sandbox/chrono/libs/thread/test/test_condition_notify_all.cpp 2010-05-20 03:55:54 EDT (Thu, 20 May 2010)
@@ -0,0 +1,222 @@
+// Copyright (C) 2007 Anthony Williams
+//
+// Distributed under 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)
+
+#include <boost/thread/detail/config.hpp>
+
+#include <boost/thread/thread.hpp>
+
+#include <boost/test/unit_test.hpp>
+
+#include <libs/thread/test/util.inl>
+#include "condition_test_common.hpp"
+
+unsigned const number_of_test_threads=5;
+
+void do_test_condition_notify_all_wakes_from_wait()
+{
+ wait_for_flag data;
+
+ boost::thread_group group;
+
+ try
+ {
+ for(unsigned i=0;i<number_of_test_threads;++i)
+ {
+ group.create_thread(bind(&wait_for_flag::wait_without_predicate, data));
+ }
+
+ {
+ boost::mutex::scoped_lock lock(data.mutex);
+ data.flag=true;
+ data.cond_var.notify_all();
+ }
+
+ group.join_all();
+ BOOST_CHECK_EQUAL(data.woken,number_of_test_threads);
+ }
+ catch(...)
+ {
+ group.join_all();
+ throw;
+ }
+}
+
+void do_test_condition_notify_all_wakes_from_wait_with_predicate()
+{
+ wait_for_flag data;
+
+ boost::thread_group group;
+
+ try
+ {
+ for(unsigned i=0;i<number_of_test_threads;++i)
+ {
+ group.create_thread(bind(&wait_for_flag::wait_with_predicate, data));
+ }
+
+ {
+ boost::mutex::scoped_lock lock(data.mutex);
+ data.flag=true;
+ data.cond_var.notify_all();
+ }
+
+ group.join_all();
+ BOOST_CHECK_EQUAL(data.woken,number_of_test_threads);
+ }
+ catch(...)
+ {
+ group.join_all();
+ throw;
+ }
+}
+
+void do_test_condition_notify_all_wakes_from_timed_wait()
+{
+ wait_for_flag data;
+
+ boost::thread_group group;
+
+ try
+ {
+ for(unsigned i=0;i<number_of_test_threads;++i)
+ {
+ group.create_thread(bind(&wait_for_flag::timed_wait_without_predicate, data));
+ }
+
+ {
+ boost::mutex::scoped_lock lock(data.mutex);
+ data.flag=true;
+ data.cond_var.notify_all();
+ }
+
+ group.join_all();
+ BOOST_CHECK_EQUAL(data.woken,number_of_test_threads);
+ }
+ catch(...)
+ {
+ group.join_all();
+ throw;
+ }
+}
+
+void do_test_condition_notify_all_wakes_from_timed_wait_with_predicate()
+{
+ wait_for_flag data;
+
+ boost::thread_group group;
+
+ try
+ {
+ for(unsigned i=0;i<number_of_test_threads;++i)
+ {
+ group.create_thread(bind(&wait_for_flag::timed_wait_with_predicate, data));
+ }
+
+ {
+ boost::mutex::scoped_lock lock(data.mutex);
+ data.flag=true;
+ data.cond_var.notify_all();
+ }
+
+ group.join_all();
+ BOOST_CHECK_EQUAL(data.woken,number_of_test_threads);
+ }
+ catch(...)
+ {
+ group.join_all();
+ throw;
+ }
+}
+
+void do_test_condition_notify_all_wakes_from_relative_timed_wait_with_predicate()
+{
+ wait_for_flag data;
+
+ boost::thread_group group;
+
+ try
+ {
+ for(unsigned i=0;i<number_of_test_threads;++i)
+ {
+ group.create_thread(bind(&wait_for_flag::relative_timed_wait_with_predicate, data));
+ }
+
+ {
+ boost::mutex::scoped_lock lock(data.mutex);
+ data.flag=true;
+ data.cond_var.notify_all();
+ }
+
+ group.join_all();
+ BOOST_CHECK_EQUAL(data.woken,number_of_test_threads);
+ }
+ catch(...)
+ {
+ group.join_all();
+ throw;
+ }
+}
+
+namespace
+{
+ boost::mutex multiple_wake_mutex;
+ boost::condition_variable multiple_wake_cond;
+ unsigned multiple_wake_count=0;
+
+ void wait_for_condvar_and_increase_count()
+ {
+ boost::mutex::scoped_lock lk(multiple_wake_mutex);
+ multiple_wake_cond.wait(lk);
+ ++multiple_wake_count;
+ }
+
+}
+
+
+void do_test_notify_all_following_notify_one_wakes_all_threads()
+{
+ boost::thread thread1(wait_for_condvar_and_increase_count);
+ boost::thread thread2(wait_for_condvar_and_increase_count);
+
+ boost::this_thread::sleep(boost::posix_time::milliseconds(200));
+ multiple_wake_cond.notify_one();
+
+ boost::thread thread3(wait_for_condvar_and_increase_count);
+
+ boost::this_thread::sleep(boost::posix_time::milliseconds(200));
+ multiple_wake_cond.notify_one();
+ multiple_wake_cond.notify_all();
+ boost::this_thread::sleep(boost::posix_time::milliseconds(200));
+
+ {
+ boost::mutex::scoped_lock lk(multiple_wake_mutex);
+ BOOST_CHECK(multiple_wake_count==3);
+ }
+
+ thread1.join();
+ thread2.join();
+ thread3.join();
+}
+
+void test_condition_notify_all()
+{
+ timed_test(&do_test_condition_notify_all_wakes_from_wait, timeout_seconds);
+ timed_test(&do_test_condition_notify_all_wakes_from_wait_with_predicate, timeout_seconds);
+ timed_test(&do_test_condition_notify_all_wakes_from_timed_wait, timeout_seconds);
+ timed_test(&do_test_condition_notify_all_wakes_from_timed_wait_with_predicate, timeout_seconds);
+ timed_test(&do_test_condition_notify_all_wakes_from_relative_timed_wait_with_predicate, timeout_seconds);
+ timed_test(&do_test_notify_all_following_notify_one_wakes_all_threads, timeout_seconds);
+}
+
+
+boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
+{
+ boost::unit_test_framework::test_suite* test =
+ BOOST_TEST_SUITE("Boost.Threads: condition test suite");
+
+ test->add(BOOST_TEST_CASE(&test_condition_notify_all));
+
+ return test;
+}

Added: sandbox/chrono/libs/thread/test/test_condition_notify_one.cpp
==============================================================================
--- (empty file)
+++ sandbox/chrono/libs/thread/test/test_condition_notify_one.cpp 2010-05-20 03:55:54 EDT (Thu, 20 May 2010)
@@ -0,0 +1,155 @@
+// Copyright (C) 2007 Anthony Williams
+//
+// Distributed under 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)
+
+#include <boost/thread/detail/config.hpp>
+
+#include <boost/thread/thread.hpp>
+
+#include <boost/test/unit_test.hpp>
+
+#include <libs/thread/test/util.inl>
+#include "condition_test_common.hpp"
+
+void do_test_condition_notify_one_wakes_from_wait()
+{
+ wait_for_flag data;
+
+ boost::thread thread(bind(&wait_for_flag::wait_without_predicate, data));
+
+ {
+ boost::mutex::scoped_lock lock(data.mutex);
+ data.flag=true;
+ data.cond_var.notify_one();
+ }
+
+ thread.join();
+ BOOST_CHECK(data.woken);
+}
+
+void do_test_condition_notify_one_wakes_from_wait_with_predicate()
+{
+ wait_for_flag data;
+
+ boost::thread thread(bind(&wait_for_flag::wait_with_predicate, data));
+
+ {
+ boost::mutex::scoped_lock lock(data.mutex);
+ data.flag=true;
+ data.cond_var.notify_one();
+ }
+
+ thread.join();
+ BOOST_CHECK(data.woken);
+}
+
+void do_test_condition_notify_one_wakes_from_timed_wait()
+{
+ wait_for_flag data;
+
+ boost::thread thread(bind(&wait_for_flag::timed_wait_without_predicate, data));
+
+ {
+ boost::mutex::scoped_lock lock(data.mutex);
+ data.flag=true;
+ data.cond_var.notify_one();
+ }
+
+ thread.join();
+ BOOST_CHECK(data.woken);
+}
+
+void do_test_condition_notify_one_wakes_from_timed_wait_with_predicate()
+{
+ wait_for_flag data;
+
+ boost::thread thread(bind(&wait_for_flag::timed_wait_with_predicate, data));
+
+ {
+ boost::mutex::scoped_lock lock(data.mutex);
+ data.flag=true;
+ data.cond_var.notify_one();
+ }
+
+ thread.join();
+ BOOST_CHECK(data.woken);
+}
+
+void do_test_condition_notify_one_wakes_from_relative_timed_wait_with_predicate()
+{
+ wait_for_flag data;
+
+ boost::thread thread(bind(&wait_for_flag::relative_timed_wait_with_predicate, data));
+
+ {
+ boost::mutex::scoped_lock lock(data.mutex);
+ data.flag=true;
+ data.cond_var.notify_one();
+ }
+
+ thread.join();
+ BOOST_CHECK(data.woken);
+}
+
+namespace
+{
+ boost::mutex multiple_wake_mutex;
+ boost::condition_variable multiple_wake_cond;
+ unsigned multiple_wake_count=0;
+
+ void wait_for_condvar_and_increase_count()
+ {
+ boost::mutex::scoped_lock lk(multiple_wake_mutex);
+ multiple_wake_cond.wait(lk);
+ ++multiple_wake_count;
+ }
+
+}
+
+
+void do_test_multiple_notify_one_calls_wakes_multiple_threads()
+{
+ boost::thread thread1(wait_for_condvar_and_increase_count);
+ boost::thread thread2(wait_for_condvar_and_increase_count);
+
+ boost::this_thread::sleep(boost::posix_time::milliseconds(200));
+ multiple_wake_cond.notify_one();
+
+ boost::thread thread3(wait_for_condvar_and_increase_count);
+
+ boost::this_thread::sleep(boost::posix_time::milliseconds(200));
+ multiple_wake_cond.notify_one();
+ multiple_wake_cond.notify_one();
+ boost::this_thread::sleep(boost::posix_time::milliseconds(200));
+
+ {
+ boost::mutex::scoped_lock lk(multiple_wake_mutex);
+ BOOST_CHECK(multiple_wake_count==3);
+ }
+
+ thread1.join();
+ thread2.join();
+ thread3.join();
+}
+
+void test_condition_notify_one()
+{
+ timed_test(&do_test_condition_notify_one_wakes_from_wait, timeout_seconds, execution_monitor::use_mutex);
+ timed_test(&do_test_condition_notify_one_wakes_from_wait_with_predicate, timeout_seconds, execution_monitor::use_mutex);
+ timed_test(&do_test_condition_notify_one_wakes_from_timed_wait, timeout_seconds, execution_monitor::use_mutex);
+ timed_test(&do_test_condition_notify_one_wakes_from_timed_wait_with_predicate, timeout_seconds, execution_monitor::use_mutex);
+ timed_test(&do_test_condition_notify_one_wakes_from_relative_timed_wait_with_predicate, timeout_seconds, execution_monitor::use_mutex);
+ timed_test(&do_test_multiple_notify_one_calls_wakes_multiple_threads, timeout_seconds, execution_monitor::use_mutex);
+}
+
+
+boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
+{
+ boost::unit_test_framework::test_suite* test =
+ BOOST_TEST_SUITE("Boost.Threads: condition test suite");
+
+ test->add(BOOST_TEST_CASE(&test_condition_notify_one));
+
+ return test;
+}

Added: sandbox/chrono/libs/thread/test/test_condition_timed_wait_times_out.cpp
==============================================================================
--- (empty file)
+++ sandbox/chrono/libs/thread/test/test_condition_timed_wait_times_out.cpp 2010-05-20 03:55:54 EDT (Thu, 20 May 2010)
@@ -0,0 +1,173 @@
+// Copyright (C) 2007-8 Anthony Williams
+//
+// Distributed under 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)
+
+#include <boost/thread/detail/config.hpp>
+
+#include <boost/thread/condition.hpp>
+#include <boost/thread/thread.hpp>
+
+#include <boost/test/unit_test.hpp>
+#include "util.inl"
+
+bool fake_predicate()
+{
+ return false;
+}
+
+unsigned const timeout_seconds=2;
+unsigned const timeout_grace=1;
+boost::posix_time::milliseconds const timeout_resolution(100);
+
+
+void do_test_timed_wait_times_out()
+{
+ boost::condition_variable cond;
+ boost::mutex m;
+
+ boost::posix_time::seconds const delay(timeout_seconds);
+ boost::mutex::scoped_lock lock(m);
+ boost::system_time const start=boost::get_system_time();
+ boost::system_time const timeout=start+delay;
+
+ while(cond.timed_wait(lock,timeout));
+
+ boost::system_time const end=boost::get_system_time();
+ BOOST_CHECK((delay-timeout_resolution)<=(end-start));
+}
+
+void do_test_timed_wait_with_predicate_times_out()
+{
+ boost::condition_variable cond;
+ boost::mutex m;
+
+ boost::posix_time::seconds const delay(timeout_seconds);
+ boost::mutex::scoped_lock lock(m);
+ boost::system_time const start=boost::get_system_time();
+ boost::system_time const timeout=start+delay;
+
+ bool const res=cond.timed_wait(lock,timeout,fake_predicate);
+
+ boost::system_time const end=boost::get_system_time();
+ BOOST_CHECK(!res);
+ BOOST_CHECK((delay-timeout_resolution)<=(end-start));
+}
+
+void do_test_relative_timed_wait_with_predicate_times_out()
+{
+ boost::condition_variable cond;
+ boost::mutex m;
+
+ boost::posix_time::seconds const delay(timeout_seconds);
+ boost::mutex::scoped_lock lock(m);
+ boost::system_time const start=boost::get_system_time();
+
+ bool const res=cond.timed_wait(lock,delay,fake_predicate);
+
+ boost::system_time const end=boost::get_system_time();
+ BOOST_CHECK(!res);
+ BOOST_CHECK((delay-timeout_resolution)<=(end-start));
+}
+
+void do_test_timed_wait_relative_times_out()
+{
+ boost::condition_variable cond;
+ boost::mutex m;
+
+ boost::posix_time::seconds const delay(timeout_seconds);
+ boost::mutex::scoped_lock lock(m);
+ boost::system_time const start=boost::get_system_time();
+
+ while(cond.timed_wait(lock,delay));
+
+ boost::system_time const end=boost::get_system_time();
+ BOOST_CHECK((delay-timeout_resolution)<=(end-start));
+}
+
+void do_test_cv_any_timed_wait_times_out()
+{
+ boost::condition_variable_any cond;
+ boost::mutex m;
+
+ boost::posix_time::seconds const delay(timeout_seconds);
+ boost::mutex::scoped_lock lock(m);
+ boost::system_time const start=boost::get_system_time();
+ boost::system_time const timeout=start+delay;
+
+ while(cond.timed_wait(lock,timeout));
+
+ boost::system_time const end=boost::get_system_time();
+ BOOST_CHECK((delay-timeout_resolution)<=(end-start));
+}
+
+void do_test_cv_any_timed_wait_with_predicate_times_out()
+{
+ boost::condition_variable_any cond;
+ boost::mutex m;
+
+ boost::posix_time::seconds const delay(timeout_seconds);
+ boost::mutex::scoped_lock lock(m);
+ boost::system_time const start=boost::get_system_time();
+ boost::system_time const timeout=start+delay;
+
+ bool const res=cond.timed_wait(lock,timeout,fake_predicate);
+
+ boost::system_time const end=boost::get_system_time();
+ BOOST_CHECK(!res);
+ BOOST_CHECK((delay-timeout_resolution)<=(end-start));
+}
+
+void do_test_cv_any_relative_timed_wait_with_predicate_times_out()
+{
+ boost::condition_variable_any cond;
+ boost::mutex m;
+
+ boost::posix_time::seconds const delay(timeout_seconds);
+ boost::mutex::scoped_lock lock(m);
+ boost::system_time const start=boost::get_system_time();
+
+ bool const res=cond.timed_wait(lock,delay,fake_predicate);
+
+ boost::system_time const end=boost::get_system_time();
+ BOOST_CHECK(!res);
+ BOOST_CHECK((delay-timeout_resolution)<=(end-start));
+}
+
+void do_test_cv_any_timed_wait_relative_times_out()
+{
+ boost::condition_variable_any cond;
+ boost::mutex m;
+
+ boost::posix_time::seconds const delay(timeout_seconds);
+ boost::mutex::scoped_lock lock(m);
+ boost::system_time const start=boost::get_system_time();
+
+ while(cond.timed_wait(lock,delay));
+
+ boost::system_time const end=boost::get_system_time();
+ BOOST_CHECK((delay-timeout_resolution)<=(end-start));
+}
+
+
+void test_timed_wait_times_out()
+{
+ timed_test(&do_test_timed_wait_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex);
+ timed_test(&do_test_timed_wait_with_predicate_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex);
+ timed_test(&do_test_relative_timed_wait_with_predicate_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex);
+ timed_test(&do_test_timed_wait_relative_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex);
+ timed_test(&do_test_cv_any_timed_wait_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex);
+ timed_test(&do_test_cv_any_timed_wait_with_predicate_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex);
+ timed_test(&do_test_cv_any_relative_timed_wait_with_predicate_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex);
+ timed_test(&do_test_cv_any_timed_wait_relative_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex);
+}
+
+boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
+{
+ boost::unit_test_framework::test_suite* test =
+ BOOST_TEST_SUITE("Boost.Threads: condition test suite");
+
+ test->add(BOOST_TEST_CASE(&test_timed_wait_times_out));
+
+ return test;
+}

Added: sandbox/chrono/libs/thread/test/test_futures.cpp
==============================================================================
--- (empty file)
+++ sandbox/chrono/libs/thread/test/test_futures.cpp 2010-05-20 03:55:54 EDT (Thu, 20 May 2010)
@@ -0,0 +1,1218 @@
+// (C) Copyright 2008-10 Anthony Williams
+//
+// Distributed under 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)
+
+#include "boost/thread/thread.hpp"
+#include "boost/thread/mutex.hpp"
+#include "boost/thread/condition.hpp"
+#include "boost/thread/future.hpp"
+#include <utility>
+#include <memory>
+#include <string>
+
+#include <boost/test/unit_test.hpp>
+
+#ifndef BOOST_NO_RVALUE_REFERENCES
+ template<typename T>
+ typename boost::remove_reference<T>::type&& cast_to_rval(T&& t)
+ {
+ return t;
+ }
+#else
+ template<typename T>
+ boost::detail::thread_move_t<T> cast_to_rval(T& t)
+ {
+ return boost::move(t);
+ }
+#endif
+
+struct X
+{
+private:
+
+ X(X& other);
+
+public:
+
+ int i;
+
+ X():
+ i(42)
+ {}
+#ifndef BOOST_NO_RVALUE_REFERENCES
+ X(X&& other):
+ i(other.i)
+ {
+ other.i=0;
+ }
+#else
+ X(boost::detail::thread_move_t<X> other):
+ i(other->i)
+ {
+ other->i=0;
+ }
+ operator boost::detail::thread_move_t<X>()
+ {
+ return boost::detail::thread_move_t<X>(*this);
+ }
+#endif
+ ~X()
+ {}
+};
+
+int make_int()
+{
+ return 42;
+}
+
+int throw_runtime_error()
+{
+ throw std::runtime_error("42");
+}
+
+void set_promise_thread(boost::promise<int>* p)
+{
+ p->set_value(42);
+}
+
+struct my_exception
+{};
+
+void set_promise_exception_thread(boost::promise<int>* p)
+{
+ p->set_exception(boost::copy_exception(my_exception()));
+}
+
+
+void test_store_value_from_thread()
+{
+ boost::promise<int> pi2;
+ boost::unique_future<int> fi2(pi2.get_future());
+ boost::thread(set_promise_thread,&pi2);
+ int j=fi2.get();
+ BOOST_CHECK(j==42);
+ BOOST_CHECK(fi2.is_ready());
+ BOOST_CHECK(fi2.has_value());
+ BOOST_CHECK(!fi2.has_exception());
+ BOOST_CHECK(fi2.get_state()==boost::future_state::ready);
+}
+
+
+void test_store_exception()
+{
+ boost::promise<int> pi3;
+ boost::unique_future<int> fi3=pi3.get_future();
+ boost::thread(set_promise_exception_thread,&pi3);
+ try
+ {
+ fi3.get();
+ BOOST_CHECK(false);
+ }
+ catch(my_exception)
+ {
+ BOOST_CHECK(true);
+ }
+
+ BOOST_CHECK(fi3.is_ready());
+ BOOST_CHECK(!fi3.has_value());
+ BOOST_CHECK(fi3.has_exception());
+ BOOST_CHECK(fi3.get_state()==boost::future_state::ready);
+}
+
+void test_initial_state()
+{
+ boost::unique_future<int> fi;
+ BOOST_CHECK(!fi.is_ready());
+ BOOST_CHECK(!fi.has_value());
+ BOOST_CHECK(!fi.has_exception());
+ BOOST_CHECK(fi.get_state()==boost::future_state::uninitialized);
+ int i;
+ try
+ {
+ i=fi.get();
+ BOOST_CHECK(false);
+ }
+ catch(boost::future_uninitialized)
+ {
+ BOOST_CHECK(true);
+ }
+}
+
+void test_waiting_future()
+{
+ boost::promise<int> pi;
+ boost::unique_future<int> fi;
+ fi=pi.get_future();
+
+ int i=0;
+ BOOST_CHECK(!fi.is_ready());
+ BOOST_CHECK(!fi.has_value());
+ BOOST_CHECK(!fi.has_exception());
+ BOOST_CHECK(fi.get_state()==boost::future_state::waiting);
+ BOOST_CHECK(i==0);
+}
+
+void test_cannot_get_future_twice()
+{
+ boost::promise<int> pi;
+ pi.get_future();
+
+ try
+ {
+ pi.get_future();
+ BOOST_CHECK(false);
+ }
+ catch(boost::future_already_retrieved&)
+ {
+ BOOST_CHECK(true);
+ }
+}
+
+void test_set_value_updates_future_state()
+{
+ boost::promise<int> pi;
+ boost::unique_future<int> fi;
+ fi=pi.get_future();
+
+ pi.set_value(42);
+
+ BOOST_CHECK(fi.is_ready());
+ BOOST_CHECK(fi.has_value());
+ BOOST_CHECK(!fi.has_exception());
+ BOOST_CHECK(fi.get_state()==boost::future_state::ready);
+}
+
+void test_set_value_can_be_retrieved()
+{
+ boost::promise<int> pi;
+ boost::unique_future<int> fi;
+ fi=pi.get_future();
+
+ pi.set_value(42);
+
+ int i=0;
+ BOOST_CHECK(i=fi.get());
+ BOOST_CHECK(i==42);
+ BOOST_CHECK(fi.is_ready());
+ BOOST_CHECK(fi.has_value());
+ BOOST_CHECK(!fi.has_exception());
+ BOOST_CHECK(fi.get_state()==boost::future_state::ready);
+}
+
+void test_set_value_can_be_moved()
+{
+// boost::promise<int> pi;
+// boost::unique_future<int> fi;
+// fi=pi.get_future();
+
+// pi.set_value(42);
+
+// int i=0;
+// BOOST_CHECK(i=fi.get());
+// BOOST_CHECK(i==42);
+// BOOST_CHECK(fi.is_ready());
+// BOOST_CHECK(fi.has_value());
+// BOOST_CHECK(!fi.has_exception());
+// BOOST_CHECK(fi.get_state()==boost::future_state::ready);
+}
+
+void test_future_from_packaged_task_is_waiting()
+{
+ boost::packaged_task<int> pt(make_int);
+ boost::unique_future<int> fi=pt.get_future();
+ int i=0;
+ BOOST_CHECK(!fi.is_ready());
+ BOOST_CHECK(!fi.has_value());
+ BOOST_CHECK(!fi.has_exception());
+ BOOST_CHECK(fi.get_state()==boost::future_state::waiting);
+ BOOST_CHECK(i==0);
+}
+
+void test_invoking_a_packaged_task_populates_future()
+{
+ boost::packaged_task<int> pt(make_int);
+ boost::unique_future<int> fi=pt.get_future();
+
+ pt();
+
+ int i=0;
+ BOOST_CHECK(fi.is_ready());
+ BOOST_CHECK(fi.has_value());
+ BOOST_CHECK(!fi.has_exception());
+ BOOST_CHECK(fi.get_state()==boost::future_state::ready);
+ BOOST_CHECK(i=fi.get());
+ BOOST_CHECK(i==42);
+}
+
+void test_invoking_a_packaged_task_twice_throws()
+{
+ boost::packaged_task<int> pt(make_int);
+
+ pt();
+ try
+ {
+ pt();
+ BOOST_CHECK(false);
+ }
+ catch(boost::task_already_started)
+ {
+ BOOST_CHECK(true);
+ }
+}
+
+
+void test_cannot_get_future_twice_from_task()
+{
+ boost::packaged_task<int> pt(make_int);
+ pt.get_future();
+ try
+ {
+ pt.get_future();
+ BOOST_CHECK(false);
+ }
+ catch(boost::future_already_retrieved)
+ {
+ BOOST_CHECK(true);
+ }
+}
+
+void test_task_stores_exception_if_function_throws()
+{
+ boost::packaged_task<int> pt(throw_runtime_error);
+ boost::unique_future<int> fi=pt.get_future();
+
+ pt();
+
+ BOOST_CHECK(fi.is_ready());
+ BOOST_CHECK(!fi.has_value());
+ BOOST_CHECK(fi.has_exception());
+ BOOST_CHECK(fi.get_state()==boost::future_state::ready);
+ try
+ {
+ fi.get();
+ BOOST_CHECK(false);
+ }
+ catch(std::exception&)
+ {
+ BOOST_CHECK(true);
+ }
+ catch(...)
+ {
+ BOOST_CHECK(!"Unknown exception thrown");
+ }
+
+}
+
+void test_void_promise()
+{
+ boost::promise<void> p;
+ boost::unique_future<void> f=p.get_future();
+ p.set_value();
+ BOOST_CHECK(f.is_ready());
+ BOOST_CHECK(f.has_value());
+ BOOST_CHECK(!f.has_exception());
+ BOOST_CHECK(f.get_state()==boost::future_state::ready);
+ f.get();
+}
+
+void test_reference_promise()
+{
+ boost::promise<int&> p;
+ boost::unique_future<int&> f=p.get_future();
+ int i=42;
+ p.set_value(i);
+ BOOST_CHECK(f.is_ready());
+ BOOST_CHECK(f.has_value());
+ BOOST_CHECK(!f.has_exception());
+ BOOST_CHECK(f.get_state()==boost::future_state::ready);
+ BOOST_CHECK(&f.get()==&i);
+}
+
+void do_nothing()
+{}
+
+void test_task_returning_void()
+{
+ boost::packaged_task<void> pt(do_nothing);
+ boost::unique_future<void> fi=pt.get_future();
+
+ pt();
+
+ BOOST_CHECK(fi.is_ready());
+ BOOST_CHECK(fi.has_value());
+ BOOST_CHECK(!fi.has_exception());
+ BOOST_CHECK(fi.get_state()==boost::future_state::ready);
+}
+
+int global_ref_target=0;
+
+int& return_ref()
+{
+ return global_ref_target;
+}
+
+void test_task_returning_reference()
+{
+ boost::packaged_task<int&> pt(return_ref);
+ boost::unique_future<int&> fi=pt.get_future();
+
+ pt();
+
+ BOOST_CHECK(fi.is_ready());
+ BOOST_CHECK(fi.has_value());
+ BOOST_CHECK(!fi.has_exception());
+ BOOST_CHECK(fi.get_state()==boost::future_state::ready);
+ int& i=fi.get();
+ BOOST_CHECK(&i==&global_ref_target);
+}
+
+void test_shared_future()
+{
+ boost::packaged_task<int> pt(make_int);
+ boost::unique_future<int> fi=pt.get_future();
+
+ boost::shared_future<int> sf(::cast_to_rval(fi));
+ BOOST_CHECK(fi.get_state()==boost::future_state::uninitialized);
+
+ pt();
+
+ int i=0;
+ BOOST_CHECK(sf.is_ready());
+ BOOST_CHECK(sf.has_value());
+ BOOST_CHECK(!sf.has_exception());
+ BOOST_CHECK(sf.get_state()==boost::future_state::ready);
+ BOOST_CHECK(i=sf.get());
+ BOOST_CHECK(i==42);
+}
+
+void test_copies_of_shared_future_become_ready_together()
+{
+ boost::packaged_task<int> pt(make_int);
+ boost::unique_future<int> fi=pt.get_future();
+
+ boost::shared_future<int> sf(::cast_to_rval(fi));
+ boost::shared_future<int> sf2(sf);
+ boost::shared_future<int> sf3;
+ sf3=sf;
+ BOOST_CHECK(sf.get_state()==boost::future_state::waiting);
+ BOOST_CHECK(sf2.get_state()==boost::future_state::waiting);
+ BOOST_CHECK(sf3.get_state()==boost::future_state::waiting);
+
+ pt();
+
+ int i=0;
+ BOOST_CHECK(sf.is_ready());
+ BOOST_CHECK(sf.has_value());
+ BOOST_CHECK(!sf.has_exception());
+ BOOST_CHECK(sf.get_state()==boost::future_state::ready);
+ BOOST_CHECK(i=sf.get());
+ BOOST_CHECK(i==42);
+ i=0;
+ BOOST_CHECK(sf2.is_ready());
+ BOOST_CHECK(sf2.has_value());
+ BOOST_CHECK(!sf2.has_exception());
+ BOOST_CHECK(sf2.get_state()==boost::future_state::ready);
+ BOOST_CHECK(i=sf2.get());
+ BOOST_CHECK(i==42);
+ i=0;
+ BOOST_CHECK(sf3.is_ready());
+ BOOST_CHECK(sf3.has_value());
+ BOOST_CHECK(!sf3.has_exception());
+ BOOST_CHECK(sf3.get_state()==boost::future_state::ready);
+ BOOST_CHECK(i=sf3.get());
+ BOOST_CHECK(i==42);
+}
+
+void test_shared_future_can_be_move_assigned_from_unique_future()
+{
+ boost::packaged_task<int> pt(make_int);
+ boost::unique_future<int> fi=pt.get_future();
+
+ boost::shared_future<int> sf;
+ sf=::cast_to_rval(fi);
+ BOOST_CHECK(fi.get_state()==boost::future_state::uninitialized);
+
+ BOOST_CHECK(!sf.is_ready());
+ BOOST_CHECK(!sf.has_value());
+ BOOST_CHECK(!sf.has_exception());
+ BOOST_CHECK(sf.get_state()==boost::future_state::waiting);
+}
+
+void test_shared_future_void()
+{
+ boost::packaged_task<void> pt(do_nothing);
+ boost::unique_future<void> fi=pt.get_future();
+
+ boost::shared_future<void> sf(::cast_to_rval(fi));
+ BOOST_CHECK(fi.get_state()==boost::future_state::uninitialized);
+
+ pt();
+
+ BOOST_CHECK(sf.is_ready());
+ BOOST_CHECK(sf.has_value());
+ BOOST_CHECK(!sf.has_exception());
+ BOOST_CHECK(sf.get_state()==boost::future_state::ready);
+ sf.get();
+}
+
+void test_shared_future_ref()
+{
+ boost::promise<int&> p;
+ boost::shared_future<int&> f(p.get_future());
+ int i=42;
+ p.set_value(i);
+ BOOST_CHECK(f.is_ready());
+ BOOST_CHECK(f.has_value());
+ BOOST_CHECK(!f.has_exception());
+ BOOST_CHECK(f.get_state()==boost::future_state::ready);
+ BOOST_CHECK(&f.get()==&i);
+}
+
+void test_can_get_a_second_future_from_a_moved_promise()
+{
+ boost::promise<int> pi;
+ boost::unique_future<int> fi=pi.get_future();
+
+ boost::promise<int> pi2(::cast_to_rval(pi));
+ boost::unique_future<int> fi2=pi.get_future();
+
+ pi2.set_value(3);
+ BOOST_CHECK(fi.is_ready());
+ BOOST_CHECK(!fi2.is_ready());
+ BOOST_CHECK(fi.get()==3);
+ pi.set_value(42);
+ BOOST_CHECK(fi2.is_ready());
+ BOOST_CHECK(fi2.get()==42);
+}
+
+void test_can_get_a_second_future_from_a_moved_void_promise()
+{
+ boost::promise<void> pi;
+ boost::unique_future<void> fi=pi.get_future();
+
+ boost::promise<void> pi2(::cast_to_rval(pi));
+ boost::unique_future<void> fi2=pi.get_future();
+
+ pi2.set_value();
+ BOOST_CHECK(fi.is_ready());
+ BOOST_CHECK(!fi2.is_ready());
+ pi.set_value();
+ BOOST_CHECK(fi2.is_ready());
+}
+
+void test_unique_future_for_move_only_udt()
+{
+ boost::promise<X> pt;
+ boost::unique_future<X> fi=pt.get_future();
+
+ pt.set_value(X());
+ X res(fi.get());
+ BOOST_CHECK(res.i==42);
+}
+
+void test_unique_future_for_string()
+{
+ boost::promise<std::string> pt;
+ boost::unique_future<std::string> fi=pt.get_future();
+
+ pt.set_value(std::string("hello"));
+ std::string res(fi.get());
+ BOOST_CHECK(res=="hello");
+
+ boost::promise<std::string> pt2;
+ fi=pt2.get_future();
+
+ std::string const s="goodbye";
+
+ pt2.set_value(s);
+ res=fi.get();
+ BOOST_CHECK(res=="goodbye");
+
+ boost::promise<std::string> pt3;
+ fi=pt3.get_future();
+
+ std::string s2="foo";
+
+ pt3.set_value(s2);
+ res=fi.get();
+ BOOST_CHECK(res=="foo");
+}
+
+boost::mutex callback_mutex;
+unsigned callback_called=0;
+
+void wait_callback(boost::promise<int>& pi)
+{
+ boost::lock_guard<boost::mutex> lk(callback_mutex);
+ ++callback_called;
+ try
+ {
+ pi.set_value(42);
+ }
+ catch(...)
+ {
+ }
+}
+
+void do_nothing_callback(boost::promise<int>& pi)
+{
+ boost::lock_guard<boost::mutex> lk(callback_mutex);
+ ++callback_called;
+}
+
+void test_wait_callback()
+{
+ callback_called=0;
+ boost::promise<int> pi;
+ boost::unique_future<int> fi=pi.get_future();
+ pi.set_wait_callback(wait_callback);
+ fi.wait();
+ BOOST_CHECK(callback_called);
+ BOOST_CHECK(fi.get()==42);
+ fi.wait();
+ fi.wait();
+ BOOST_CHECK(callback_called==1);
+}
+
+void test_wait_callback_with_timed_wait()
+{
+ callback_called=0;
+ boost::promise<int> pi;
+ boost::unique_future<int> fi=pi.get_future();
+ pi.set_wait_callback(do_nothing_callback);
+ bool success=fi.timed_wait(boost::posix_time::milliseconds(10));
+ BOOST_CHECK(callback_called);
+ BOOST_CHECK(!success);
+ success=fi.timed_wait(boost::posix_time::milliseconds(10));
+ BOOST_CHECK(!success);
+ success=fi.timed_wait(boost::posix_time::milliseconds(10));
+ BOOST_CHECK(!success);
+ BOOST_CHECK(callback_called==3);
+ pi.set_value(42);
+ success=fi.timed_wait(boost::posix_time::milliseconds(10));
+ BOOST_CHECK(success);
+ BOOST_CHECK(callback_called==3);
+ BOOST_CHECK(fi.get()==42);
+ BOOST_CHECK(callback_called==3);
+}
+
+
+void wait_callback_for_task(boost::packaged_task<int>& pt)
+{
+ boost::lock_guard<boost::mutex> lk(callback_mutex);
+ ++callback_called;
+ try
+ {
+ pt();
+ }
+ catch(...)
+ {
+ }
+}
+
+
+void test_wait_callback_for_packaged_task()
+{
+ callback_called=0;
+ boost::packaged_task<int> pt(make_int);
+ boost::unique_future<int> fi=pt.get_future();
+ pt.set_wait_callback(wait_callback_for_task);
+ fi.wait();
+ BOOST_CHECK(callback_called);
+ BOOST_CHECK(fi.get()==42);
+ fi.wait();
+ fi.wait();
+ BOOST_CHECK(callback_called==1);
+}
+
+void test_packaged_task_can_be_moved()
+{
+ boost::packaged_task<int> pt(make_int);
+
+ boost::unique_future<int> fi=pt.get_future();
+
+ BOOST_CHECK(!fi.is_ready());
+
+ boost::packaged_task<int> pt2(::cast_to_rval(pt));
+
+ BOOST_CHECK(!fi.is_ready());
+ try
+ {
+ pt();
+ BOOST_CHECK(!"Can invoke moved task!");
+ }
+ catch(boost::task_moved&)
+ {
+ }
+
+ BOOST_CHECK(!fi.is_ready());
+
+ pt2();
+
+ BOOST_CHECK(fi.is_ready());
+}
+
+void test_destroying_a_promise_stores_broken_promise()
+{
+ boost::unique_future<int> f;
+
+ {
+ boost::promise<int> p;
+ f=p.get_future();
+ }
+ BOOST_CHECK(f.is_ready());
+ BOOST_CHECK(f.has_exception());
+ try
+ {
+ f.get();
+ }
+ catch(boost::broken_promise&)
+ {
+ }
+}
+
+void test_destroying_a_packaged_task_stores_broken_promise()
+{
+ boost::unique_future<int> f;
+
+ {
+ boost::packaged_task<int> p(make_int);
+ f=p.get_future();
+ }
+ BOOST_CHECK(f.is_ready());
+ BOOST_CHECK(f.has_exception());
+ try
+ {
+ f.get();
+ }
+ catch(boost::broken_promise&)
+ {
+ }
+}
+
+int make_int_slowly()
+{
+ boost::this_thread::sleep(boost::posix_time::seconds(1));
+ return 42;
+}
+
+void test_wait_for_either_of_two_futures_1()
+{
+ boost::packaged_task<int> pt(make_int_slowly);
+ boost::unique_future<int> f1(pt.get_future());
+ boost::packaged_task<int> pt2(make_int_slowly);
+ boost::unique_future<int> f2(pt2.get_future());
+
+ boost::thread(::cast_to_rval(pt));
+
+ unsigned const future=boost::wait_for_any(f1,f2);
+
+ BOOST_CHECK(future==0);
+ BOOST_CHECK(f1.is_ready());
+ BOOST_CHECK(!f2.is_ready());
+ BOOST_CHECK(f1.get()==42);
+}
+
+void test_wait_for_either_of_two_futures_2()
+{
+ boost::packaged_task<int> pt(make_int_slowly);
+ boost::unique_future<int> f1(pt.get_future());
+ boost::packaged_task<int> pt2(make_int_slowly);
+ boost::unique_future<int> f2(pt2.get_future());
+
+ boost::thread(::cast_to_rval(pt2));
+
+ unsigned const future=boost::wait_for_any(f1,f2);
+
+ BOOST_CHECK(future==1);
+ BOOST_CHECK(!f1.is_ready());
+ BOOST_CHECK(f2.is_ready());
+ BOOST_CHECK(f2.get()==42);
+}
+
+void test_wait_for_either_of_three_futures_1()
+{
+ boost::packaged_task<int> pt(make_int_slowly);
+ boost::unique_future<int> f1(pt.get_future());
+ boost::packaged_task<int> pt2(make_int_slowly);
+ boost::unique_future<int> f2(pt2.get_future());
+ boost::packaged_task<int> pt3(make_int_slowly);
+ boost::unique_future<int> f3(pt3.get_future());
+
+ boost::thread(::cast_to_rval(pt));
+
+ unsigned const future=boost::wait_for_any(f1,f2,f3);
+
+ BOOST_CHECK(future==0);
+ BOOST_CHECK(f1.is_ready());
+ BOOST_CHECK(!f2.is_ready());
+ BOOST_CHECK(!f3.is_ready());
+ BOOST_CHECK(f1.get()==42);
+}
+
+void test_wait_for_either_of_three_futures_2()
+{
+ boost::packaged_task<int> pt(make_int_slowly);
+ boost::unique_future<int> f1(pt.get_future());
+ boost::packaged_task<int> pt2(make_int_slowly);
+ boost::unique_future<int> f2(pt2.get_future());
+ boost::packaged_task<int> pt3(make_int_slowly);
+ boost::unique_future<int> f3(pt3.get_future());
+
+ boost::thread(::cast_to_rval(pt2));
+
+ unsigned const future=boost::wait_for_any(f1,f2,f3);
+
+ BOOST_CHECK(future==1);
+ BOOST_CHECK(!f1.is_ready());
+ BOOST_CHECK(f2.is_ready());
+ BOOST_CHECK(!f3.is_ready());
+ BOOST_CHECK(f2.get()==42);
+}
+
+void test_wait_for_either_of_three_futures_3()
+{
+ boost::packaged_task<int> pt(make_int_slowly);
+ boost::unique_future<int> f1(pt.get_future());
+ boost::packaged_task<int> pt2(make_int_slowly);
+ boost::unique_future<int> f2(pt2.get_future());
+ boost::packaged_task<int> pt3(make_int_slowly);
+ boost::unique_future<int> f3(pt3.get_future());
+
+ boost::thread(::cast_to_rval(pt3));
+
+ unsigned const future=boost::wait_for_any(f1,f2,f3);
+
+ BOOST_CHECK(future==2);
+ BOOST_CHECK(!f1.is_ready());
+ BOOST_CHECK(!f2.is_ready());
+ BOOST_CHECK(f3.is_ready());
+ BOOST_CHECK(f3.get()==42);
+}
+
+void test_wait_for_either_of_four_futures_1()
+{
+ boost::packaged_task<int> pt(make_int_slowly);
+ boost::unique_future<int> f1(pt.get_future());
+ boost::packaged_task<int> pt2(make_int_slowly);
+ boost::unique_future<int> f2(pt2.get_future());
+ boost::packaged_task<int> pt3(make_int_slowly);
+ boost::unique_future<int> f3(pt3.get_future());
+ boost::packaged_task<int> pt4(make_int_slowly);
+ boost::unique_future<int> f4(pt4.get_future());
+
+ boost::thread(::cast_to_rval(pt));
+
+ unsigned const future=boost::wait_for_any(f1,f2,f3,f4);
+
+ BOOST_CHECK(future==0);
+ BOOST_CHECK(f1.is_ready());
+ BOOST_CHECK(!f2.is_ready());
+ BOOST_CHECK(!f3.is_ready());
+ BOOST_CHECK(!f4.is_ready());
+ BOOST_CHECK(f1.get()==42);
+}
+
+void test_wait_for_either_of_four_futures_2()
+{
+ boost::packaged_task<int> pt(make_int_slowly);
+ boost::unique_future<int> f1(pt.get_future());
+ boost::packaged_task<int> pt2(make_int_slowly);
+ boost::unique_future<int> f2(pt2.get_future());
+ boost::packaged_task<int> pt3(make_int_slowly);
+ boost::unique_future<int> f3(pt3.get_future());
+ boost::packaged_task<int> pt4(make_int_slowly);
+ boost::unique_future<int> f4(pt4.get_future());
+
+ boost::thread(::cast_to_rval(pt2));
+
+ unsigned const future=boost::wait_for_any(f1,f2,f3,f4);
+
+ BOOST_CHECK(future==1);
+ BOOST_CHECK(!f1.is_ready());
+ BOOST_CHECK(f2.is_ready());
+ BOOST_CHECK(!f3.is_ready());
+ BOOST_CHECK(!f4.is_ready());
+ BOOST_CHECK(f2.get()==42);
+}
+
+void test_wait_for_either_of_four_futures_3()
+{
+ boost::packaged_task<int> pt(make_int_slowly);
+ boost::unique_future<int> f1(pt.get_future());
+ boost::packaged_task<int> pt2(make_int_slowly);
+ boost::unique_future<int> f2(pt2.get_future());
+ boost::packaged_task<int> pt3(make_int_slowly);
+ boost::unique_future<int> f3(pt3.get_future());
+ boost::packaged_task<int> pt4(make_int_slowly);
+ boost::unique_future<int> f4(pt4.get_future());
+
+ boost::thread(::cast_to_rval(pt3));
+
+ unsigned const future=boost::wait_for_any(f1,f2,f3,f4);
+
+ BOOST_CHECK(future==2);
+ BOOST_CHECK(!f1.is_ready());
+ BOOST_CHECK(!f2.is_ready());
+ BOOST_CHECK(f3.is_ready());
+ BOOST_CHECK(!f4.is_ready());
+ BOOST_CHECK(f3.get()==42);
+}
+
+void test_wait_for_either_of_four_futures_4()
+{
+ boost::packaged_task<int> pt(make_int_slowly);
+ boost::unique_future<int> f1(pt.get_future());
+ boost::packaged_task<int> pt2(make_int_slowly);
+ boost::unique_future<int> f2(pt2.get_future());
+ boost::packaged_task<int> pt3(make_int_slowly);
+ boost::unique_future<int> f3(pt3.get_future());
+ boost::packaged_task<int> pt4(make_int_slowly);
+ boost::unique_future<int> f4(pt4.get_future());
+
+ boost::thread(::cast_to_rval(pt4));
+
+ unsigned const future=boost::wait_for_any(f1,f2,f3,f4);
+
+ BOOST_CHECK(future==3);
+ BOOST_CHECK(!f1.is_ready());
+ BOOST_CHECK(!f2.is_ready());
+ BOOST_CHECK(!f3.is_ready());
+ BOOST_CHECK(f4.is_ready());
+ BOOST_CHECK(f4.get()==42);
+}
+
+void test_wait_for_either_of_five_futures_1()
+{
+ boost::packaged_task<int> pt(make_int_slowly);
+ boost::unique_future<int> f1(pt.get_future());
+ boost::packaged_task<int> pt2(make_int_slowly);
+ boost::unique_future<int> f2(pt2.get_future());
+ boost::packaged_task<int> pt3(make_int_slowly);
+ boost::unique_future<int> f3(pt3.get_future());
+ boost::packaged_task<int> pt4(make_int_slowly);
+ boost::unique_future<int> f4(pt4.get_future());
+ boost::packaged_task<int> pt5(make_int_slowly);
+ boost::unique_future<int> f5(pt5.get_future());
+
+ boost::thread(::cast_to_rval(pt));
+
+ unsigned const future=boost::wait_for_any(f1,f2,f3,f4,f5);
+
+ BOOST_CHECK(future==0);
+ BOOST_CHECK(f1.is_ready());
+ BOOST_CHECK(!f2.is_ready());
+ BOOST_CHECK(!f3.is_ready());
+ BOOST_CHECK(!f4.is_ready());
+ BOOST_CHECK(!f5.is_ready());
+ BOOST_CHECK(f1.get()==42);
+}
+
+void test_wait_for_either_of_five_futures_2()
+{
+ boost::packaged_task<int> pt(make_int_slowly);
+ boost::unique_future<int> f1(pt.get_future());
+ boost::packaged_task<int> pt2(make_int_slowly);
+ boost::unique_future<int> f2(pt2.get_future());
+ boost::packaged_task<int> pt3(make_int_slowly);
+ boost::unique_future<int> f3(pt3.get_future());
+ boost::packaged_task<int> pt4(make_int_slowly);
+ boost::unique_future<int> f4(pt4.get_future());
+ boost::packaged_task<int> pt5(make_int_slowly);
+ boost::unique_future<int> f5(pt5.get_future());
+
+ boost::thread(::cast_to_rval(pt2));
+
+ unsigned const future=boost::wait_for_any(f1,f2,f3,f4,f5);
+
+ BOOST_CHECK(future==1);
+ BOOST_CHECK(!f1.is_ready());
+ BOOST_CHECK(f2.is_ready());
+ BOOST_CHECK(!f3.is_ready());
+ BOOST_CHECK(!f4.is_ready());
+ BOOST_CHECK(!f5.is_ready());
+ BOOST_CHECK(f2.get()==42);
+}
+void test_wait_for_either_of_five_futures_3()
+{
+ boost::packaged_task<int> pt(make_int_slowly);
+ boost::unique_future<int> f1(pt.get_future());
+ boost::packaged_task<int> pt2(make_int_slowly);
+ boost::unique_future<int> f2(pt2.get_future());
+ boost::packaged_task<int> pt3(make_int_slowly);
+ boost::unique_future<int> f3(pt3.get_future());
+ boost::packaged_task<int> pt4(make_int_slowly);
+ boost::unique_future<int> f4(pt4.get_future());
+ boost::packaged_task<int> pt5(make_int_slowly);
+ boost::unique_future<int> f5(pt5.get_future());
+
+ boost::thread(::cast_to_rval(pt3));
+
+ unsigned const future=boost::wait_for_any(f1,f2,f3,f4,f5);
+
+ BOOST_CHECK(future==2);
+ BOOST_CHECK(!f1.is_ready());
+ BOOST_CHECK(!f2.is_ready());
+ BOOST_CHECK(f3.is_ready());
+ BOOST_CHECK(!f4.is_ready());
+ BOOST_CHECK(!f5.is_ready());
+ BOOST_CHECK(f3.get()==42);
+}
+void test_wait_for_either_of_five_futures_4()
+{
+ boost::packaged_task<int> pt(make_int_slowly);
+ boost::unique_future<int> f1(pt.get_future());
+ boost::packaged_task<int> pt2(make_int_slowly);
+ boost::unique_future<int> f2(pt2.get_future());
+ boost::packaged_task<int> pt3(make_int_slowly);
+ boost::unique_future<int> f3(pt3.get_future());
+ boost::packaged_task<int> pt4(make_int_slowly);
+ boost::unique_future<int> f4(pt4.get_future());
+ boost::packaged_task<int> pt5(make_int_slowly);
+ boost::unique_future<int> f5(pt5.get_future());
+
+ boost::thread(::cast_to_rval(pt4));
+
+ unsigned const future=boost::wait_for_any(f1,f2,f3,f4,f5);
+
+ BOOST_CHECK(future==3);
+ BOOST_CHECK(!f1.is_ready());
+ BOOST_CHECK(!f2.is_ready());
+ BOOST_CHECK(!f3.is_ready());
+ BOOST_CHECK(f4.is_ready());
+ BOOST_CHECK(!f5.is_ready());
+ BOOST_CHECK(f4.get()==42);
+}
+void test_wait_for_either_of_five_futures_5()
+{
+ boost::packaged_task<int> pt(make_int_slowly);
+ boost::unique_future<int> f1(pt.get_future());
+ boost::packaged_task<int> pt2(make_int_slowly);
+ boost::unique_future<int> f2(pt2.get_future());
+ boost::packaged_task<int> pt3(make_int_slowly);
+ boost::unique_future<int> f3(pt3.get_future());
+ boost::packaged_task<int> pt4(make_int_slowly);
+ boost::unique_future<int> f4(pt4.get_future());
+ boost::packaged_task<int> pt5(make_int_slowly);
+ boost::unique_future<int> f5(pt5.get_future());
+
+ boost::thread(::cast_to_rval(pt5));
+
+ unsigned const future=boost::wait_for_any(f1,f2,f3,f4,f5);
+
+ BOOST_CHECK(future==4);
+ BOOST_CHECK(!f1.is_ready());
+ BOOST_CHECK(!f2.is_ready());
+ BOOST_CHECK(!f3.is_ready());
+ BOOST_CHECK(!f4.is_ready());
+ BOOST_CHECK(f5.is_ready());
+ BOOST_CHECK(f5.get()==42);
+}
+
+void test_wait_for_either_invokes_callbacks()
+{
+ callback_called=0;
+ boost::packaged_task<int> pt(make_int_slowly);
+ boost::unique_future<int> fi=pt.get_future();
+ boost::packaged_task<int> pt2(make_int_slowly);
+ boost::unique_future<int> fi2=pt2.get_future();
+ pt.set_wait_callback(wait_callback_for_task);
+
+ boost::thread(::cast_to_rval(pt));
+
+ boost::wait_for_any(fi,fi2);
+ BOOST_CHECK(callback_called==1);
+ BOOST_CHECK(fi.get()==42);
+}
+
+void test_wait_for_any_from_range()
+{
+ unsigned const count=10;
+ for(unsigned i=0;i<count;++i)
+ {
+ boost::packaged_task<int> tasks[count];
+ boost::unique_future<int> futures[count];
+ for(unsigned j=0;j<count;++j)
+ {
+ tasks[j]=boost::packaged_task<int>(make_int_slowly);
+ futures[j]=tasks[j].get_future();
+ }
+ boost::thread(::cast_to_rval(tasks[i]));
+
+ boost::unique_future<int>* const future=boost::wait_for_any(futures,futures+count);
+
+ BOOST_CHECK(future==(futures+i));
+ for(unsigned j=0;j<count;++j)
+ {
+ if(j!=i)
+ {
+ BOOST_CHECK(!futures[j].is_ready());
+ }
+ else
+ {
+ BOOST_CHECK(futures[j].is_ready());
+ }
+ }
+ BOOST_CHECK(futures[i].get()==42);
+ }
+}
+
+void test_wait_for_all_from_range()
+{
+ unsigned const count=10;
+ boost::unique_future<int> futures[count];
+ for(unsigned j=0;j<count;++j)
+ {
+ boost::packaged_task<int> task(make_int_slowly);
+ futures[j]=task.get_future();
+ boost::thread(::cast_to_rval(task));
+ }
+
+ boost::wait_for_all(futures,futures+count);
+
+ for(unsigned j=0;j<count;++j)
+ {
+ BOOST_CHECK(futures[j].is_ready());
+ }
+}
+
+void test_wait_for_all_two_futures()
+{
+ unsigned const count=2;
+ boost::unique_future<int> futures[count];
+ for(unsigned j=0;j<count;++j)
+ {
+ boost::packaged_task<int> task(make_int_slowly);
+ futures[j]=task.get_future();
+ boost::thread(::cast_to_rval(task));
+ }
+
+ boost::wait_for_all(futures[0],futures[1]);
+
+ for(unsigned j=0;j<count;++j)
+ {
+ BOOST_CHECK(futures[j].is_ready());
+ }
+}
+
+void test_wait_for_all_three_futures()
+{
+ unsigned const count=3;
+ boost::unique_future<int> futures[count];
+ for(unsigned j=0;j<count;++j)
+ {
+ boost::packaged_task<int> task(make_int_slowly);
+ futures[j]=task.get_future();
+ boost::thread(::cast_to_rval(task));
+ }
+
+ boost::wait_for_all(futures[0],futures[1],futures[2]);
+
+ for(unsigned j=0;j<count;++j)
+ {
+ BOOST_CHECK(futures[j].is_ready());
+ }
+}
+
+void test_wait_for_all_four_futures()
+{
+ unsigned const count=4;
+ boost::unique_future<int> futures[count];
+ for(unsigned j=0;j<count;++j)
+ {
+ boost::packaged_task<int> task(make_int_slowly);
+ futures[j]=task.get_future();
+ boost::thread(::cast_to_rval(task));
+ }
+
+ boost::wait_for_all(futures[0],futures[1],futures[2],futures[3]);
+
+ for(unsigned j=0;j<count;++j)
+ {
+ BOOST_CHECK(futures[j].is_ready());
+ }
+}
+
+void test_wait_for_all_five_futures()
+{
+ unsigned const count=5;
+ boost::unique_future<int> futures[count];
+ for(unsigned j=0;j<count;++j)
+ {
+ boost::packaged_task<int> task(make_int_slowly);
+ futures[j]=task.get_future();
+ boost::thread(::cast_to_rval(task));
+ }
+
+ boost::wait_for_all(futures[0],futures[1],futures[2],futures[3],futures[4]);
+
+ for(unsigned j=0;j<count;++j)
+ {
+ BOOST_CHECK(futures[j].is_ready());
+ }
+}
+
+
+boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
+{
+ boost::unit_test_framework::test_suite* test =
+ BOOST_TEST_SUITE("Boost.Threads: futures test suite");
+
+ test->add(BOOST_TEST_CASE(test_initial_state));
+ test->add(BOOST_TEST_CASE(test_waiting_future));
+ test->add(BOOST_TEST_CASE(test_cannot_get_future_twice));
+ test->add(BOOST_TEST_CASE(test_set_value_updates_future_state));
+ test->add(BOOST_TEST_CASE(test_set_value_can_be_retrieved));
+ test->add(BOOST_TEST_CASE(test_set_value_can_be_moved));
+ test->add(BOOST_TEST_CASE(test_store_value_from_thread));
+ test->add(BOOST_TEST_CASE(test_store_exception));
+ test->add(BOOST_TEST_CASE(test_future_from_packaged_task_is_waiting));
+ test->add(BOOST_TEST_CASE(test_invoking_a_packaged_task_populates_future));
+ test->add(BOOST_TEST_CASE(test_invoking_a_packaged_task_twice_throws));
+ test->add(BOOST_TEST_CASE(test_cannot_get_future_twice_from_task));
+ test->add(BOOST_TEST_CASE(test_task_stores_exception_if_function_throws));
+ test->add(BOOST_TEST_CASE(test_void_promise));
+ test->add(BOOST_TEST_CASE(test_reference_promise));
+ test->add(BOOST_TEST_CASE(test_task_returning_void));
+ test->add(BOOST_TEST_CASE(test_task_returning_reference));
+ test->add(BOOST_TEST_CASE(test_shared_future));
+ test->add(BOOST_TEST_CASE(test_copies_of_shared_future_become_ready_together));
+ test->add(BOOST_TEST_CASE(test_shared_future_can_be_move_assigned_from_unique_future));
+ test->add(BOOST_TEST_CASE(test_shared_future_void));
+ test->add(BOOST_TEST_CASE(test_shared_future_ref));
+ test->add(BOOST_TEST_CASE(test_can_get_a_second_future_from_a_moved_promise));
+ test->add(BOOST_TEST_CASE(test_can_get_a_second_future_from_a_moved_void_promise));
+ test->add(BOOST_TEST_CASE(test_unique_future_for_move_only_udt));
+ test->add(BOOST_TEST_CASE(test_unique_future_for_string));
+ test->add(BOOST_TEST_CASE(test_wait_callback));
+ test->add(BOOST_TEST_CASE(test_wait_callback_with_timed_wait));
+ test->add(BOOST_TEST_CASE(test_wait_callback_for_packaged_task));
+ test->add(BOOST_TEST_CASE(test_packaged_task_can_be_moved));
+ test->add(BOOST_TEST_CASE(test_destroying_a_promise_stores_broken_promise));
+ test->add(BOOST_TEST_CASE(test_destroying_a_packaged_task_stores_broken_promise));
+ test->add(BOOST_TEST_CASE(test_wait_for_either_of_two_futures_1));
+ test->add(BOOST_TEST_CASE(test_wait_for_either_of_two_futures_2));
+ test->add(BOOST_TEST_CASE(test_wait_for_either_of_three_futures_1));
+ test->add(BOOST_TEST_CASE(test_wait_for_either_of_three_futures_2));
+ test->add(BOOST_TEST_CASE(test_wait_for_either_of_three_futures_3));
+ test->add(BOOST_TEST_CASE(test_wait_for_either_of_four_futures_1));
+ test->add(BOOST_TEST_CASE(test_wait_for_either_of_four_futures_2));
+ test->add(BOOST_TEST_CASE(test_wait_for_either_of_four_futures_3));
+ test->add(BOOST_TEST_CASE(test_wait_for_either_of_four_futures_4));
+ test->add(BOOST_TEST_CASE(test_wait_for_either_of_five_futures_1));
+ test->add(BOOST_TEST_CASE(test_wait_for_either_of_five_futures_2));
+ test->add(BOOST_TEST_CASE(test_wait_for_either_of_five_futures_3));
+ test->add(BOOST_TEST_CASE(test_wait_for_either_of_five_futures_4));
+ test->add(BOOST_TEST_CASE(test_wait_for_either_of_five_futures_5));
+ test->add(BOOST_TEST_CASE(test_wait_for_either_invokes_callbacks));
+ test->add(BOOST_TEST_CASE(test_wait_for_any_from_range));
+ test->add(BOOST_TEST_CASE(test_wait_for_all_from_range));
+ test->add(BOOST_TEST_CASE(test_wait_for_all_two_futures));
+ test->add(BOOST_TEST_CASE(test_wait_for_all_three_futures));
+ test->add(BOOST_TEST_CASE(test_wait_for_all_four_futures));
+ test->add(BOOST_TEST_CASE(test_wait_for_all_five_futures));
+
+ return test;
+}

Added: sandbox/chrono/libs/thread/test/test_generic_locks.cpp
==============================================================================
--- (empty file)
+++ sandbox/chrono/libs/thread/test/test_generic_locks.cpp 2010-05-20 03:55:54 EDT (Thu, 20 May 2010)
@@ -0,0 +1,523 @@
+// (C) Copyright 2008 Anthony Williams
+// Distributed under 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)
+
+#include <boost/test/unit_test.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/thread.hpp>
+#include <boost/thread/locks.hpp>
+#include <boost/thread/condition_variable.hpp>
+
+void test_lock_two_uncontended()
+{
+ boost::mutex m1,m2;
+
+ boost::mutex::scoped_lock l1(m1,boost::defer_lock),
+ l2(m2,boost::defer_lock);
+
+ BOOST_CHECK(!l1.owns_lock());
+ BOOST_CHECK(!l2.owns_lock());
+
+ boost::lock(l1,l2);
+
+ BOOST_CHECK(l1.owns_lock());
+ BOOST_CHECK(l2.owns_lock());
+}
+
+struct wait_data
+{
+ boost::mutex m;
+ bool flag;
+ boost::condition_variable cond;
+
+ wait_data():
+ flag(false)
+ {}
+
+ void wait()
+ {
+ boost::mutex::scoped_lock l(m);
+ while(!flag)
+ {
+ cond.wait(l);
+ }
+ }
+
+ template<typename Duration>
+ bool timed_wait(Duration d)
+ {
+ boost::system_time const target=boost::get_system_time()+d;
+
+ boost::mutex::scoped_lock l(m);
+ while(!flag)
+ {
+ if(!cond.timed_wait(l,target))
+ {
+ return flag;
+ }
+ }
+ return true;
+ }
+
+ void signal()
+ {
+ boost::mutex::scoped_lock l(m);
+ flag=true;
+ cond.notify_all();
+ }
+};
+
+
+void lock_mutexes_slowly(boost::mutex* m1,boost::mutex* m2,wait_data* locked,wait_data* quit)
+{
+ boost::lock_guard<boost::mutex> l1(*m1);
+ boost::this_thread::sleep(boost::posix_time::milliseconds(500));
+ boost::lock_guard<boost::mutex> l2(*m2);
+ locked->signal();
+ quit->wait();
+}
+
+void lock_pair(boost::mutex* m1,boost::mutex* m2)
+{
+ boost::lock(*m1,*m2);
+ boost::mutex::scoped_lock l1(*m1,boost::adopt_lock),
+ l2(*m2,boost::adopt_lock);
+}
+
+void test_lock_two_other_thread_locks_in_order()
+{
+ boost::mutex m1,m2;
+ wait_data locked;
+ wait_data release;
+
+ boost::thread t(lock_mutexes_slowly,&m1,&m2,&locked,&release);
+ boost::this_thread::sleep(boost::posix_time::milliseconds(10));
+
+ boost::thread t2(lock_pair,&m1,&m2);
+ BOOST_CHECK(locked.timed_wait(boost::posix_time::seconds(1)));
+
+ release.signal();
+
+ BOOST_CHECK(t2.timed_join(boost::posix_time::seconds(1)));
+
+ t.join();
+}
+
+void test_lock_two_other_thread_locks_in_opposite_order()
+{
+ boost::mutex m1,m2;
+ wait_data locked;
+ wait_data release;
+
+ boost::thread t(lock_mutexes_slowly,&m1,&m2,&locked,&release);
+ boost::this_thread::sleep(boost::posix_time::milliseconds(10));
+
+ boost::thread t2(lock_pair,&m2,&m1);
+ BOOST_CHECK(locked.timed_wait(boost::posix_time::seconds(1)));
+
+ release.signal();
+
+ BOOST_CHECK(t2.timed_join(boost::posix_time::seconds(1)));
+
+ t.join();
+}
+
+void test_lock_five_uncontended()
+{
+ boost::mutex m1,m2,m3,m4,m5;
+
+ boost::mutex::scoped_lock l1(m1,boost::defer_lock),
+ l2(m2,boost::defer_lock),
+ l3(m3,boost::defer_lock),
+ l4(m4,boost::defer_lock),
+ l5(m5,boost::defer_lock);
+
+ BOOST_CHECK(!l1.owns_lock());
+ BOOST_CHECK(!l2.owns_lock());
+ BOOST_CHECK(!l3.owns_lock());
+ BOOST_CHECK(!l4.owns_lock());
+ BOOST_CHECK(!l5.owns_lock());
+
+ boost::lock(l1,l2,l3,l4,l5);
+
+ BOOST_CHECK(l1.owns_lock());
+ BOOST_CHECK(l2.owns_lock());
+ BOOST_CHECK(l3.owns_lock());
+ BOOST_CHECK(l4.owns_lock());
+ BOOST_CHECK(l5.owns_lock());
+}
+
+void lock_five_mutexes_slowly(boost::mutex* m1,boost::mutex* m2,boost::mutex* m3,boost::mutex* m4,boost::mutex* m5,
+ wait_data* locked,wait_data* quit)
+{
+ boost::lock_guard<boost::mutex> l1(*m1);
+ boost::this_thread::sleep(boost::posix_time::milliseconds(500));
+ boost::lock_guard<boost::mutex> l2(*m2);
+ boost::this_thread::sleep(boost::posix_time::milliseconds(500));
+ boost::lock_guard<boost::mutex> l3(*m3);
+ boost::this_thread::sleep(boost::posix_time::milliseconds(500));
+ boost::lock_guard<boost::mutex> l4(*m4);
+ boost::this_thread::sleep(boost::posix_time::milliseconds(500));
+ boost::lock_guard<boost::mutex> l5(*m5);
+ locked->signal();
+ quit->wait();
+}
+
+void lock_five(boost::mutex* m1,boost::mutex* m2,boost::mutex* m3,boost::mutex* m4,boost::mutex* m5)
+{
+ boost::lock(*m1,*m2,*m3,*m4,*m5);
+ m1->unlock();
+ m2->unlock();
+ m3->unlock();
+ m4->unlock();
+ m5->unlock();
+}
+
+void test_lock_five_other_thread_locks_in_order()
+{
+ boost::mutex m1,m2,m3,m4,m5;
+ wait_data locked;
+ wait_data release;
+
+ boost::thread t(lock_five_mutexes_slowly,&m1,&m2,&m3,&m4,&m5,&locked,&release);
+ boost::this_thread::sleep(boost::posix_time::milliseconds(10));
+
+ boost::thread t2(lock_five,&m1,&m2,&m3,&m4,&m5);
+ BOOST_CHECK(locked.timed_wait(boost::posix_time::seconds(3)));
+
+ release.signal();
+
+ BOOST_CHECK(t2.timed_join(boost::posix_time::seconds(3)));
+
+ t.join();
+}
+
+void test_lock_five_other_thread_locks_in_different_order()
+{
+ boost::mutex m1,m2,m3,m4,m5;
+ wait_data locked;
+ wait_data release;
+
+ boost::thread t(lock_five_mutexes_slowly,&m1,&m2,&m3,&m4,&m5,&locked,&release);
+ boost::this_thread::sleep(boost::posix_time::milliseconds(10));
+
+ boost::thread t2(lock_five,&m5,&m1,&m4,&m2,&m3);
+ BOOST_CHECK(locked.timed_wait(boost::posix_time::seconds(3)));
+
+ release.signal();
+
+ BOOST_CHECK(t2.timed_join(boost::posix_time::seconds(3)));
+
+ t.join();
+}
+
+void lock_n(boost::mutex* mutexes,unsigned count)
+{
+ boost::lock(mutexes,mutexes+count);
+ for(unsigned i=0;i<count;++i)
+ {
+ mutexes[i].unlock();
+ }
+}
+
+
+void test_lock_ten_other_thread_locks_in_different_order()
+{
+ unsigned const num_mutexes=10;
+
+ boost::mutex mutexes[num_mutexes];
+ wait_data locked;
+ wait_data release;
+
+ boost::thread t(lock_five_mutexes_slowly,&mutexes[6],&mutexes[3],&mutexes[8],&mutexes[0],&mutexes[2],&locked,&release);
+ boost::this_thread::sleep(boost::posix_time::milliseconds(10));
+
+ boost::thread t2(lock_n,mutexes,num_mutexes);
+ BOOST_CHECK(locked.timed_wait(boost::posix_time::seconds(3)));
+
+ release.signal();
+
+ BOOST_CHECK(t2.timed_join(boost::posix_time::seconds(3)));
+
+ t.join();
+}
+
+struct dummy_mutex
+{
+ bool is_locked;
+
+ dummy_mutex():
+ is_locked(false)
+ {}
+
+ void lock()
+ {
+ is_locked=true;
+ }
+
+ bool try_lock()
+ {
+ if(is_locked)
+ {
+ return false;
+ }
+ is_locked=true;
+ return true;
+ }
+
+ void unlock()
+ {
+ is_locked=false;
+ }
+};
+
+namespace boost
+{
+ template<>
+ struct is_mutex_type<dummy_mutex>
+ {
+ BOOST_STATIC_CONSTANT(bool, value = true);
+ };
+}
+
+
+
+void test_lock_five_in_range()
+{
+ unsigned const num_mutexes=5;
+ dummy_mutex mutexes[num_mutexes];
+
+ boost::lock(mutexes,mutexes+num_mutexes);
+
+ for(unsigned i=0;i<num_mutexes;++i)
+ {
+ BOOST_CHECK(mutexes[i].is_locked);
+ }
+}
+
+void test_lock_ten_in_range()
+{
+ unsigned const num_mutexes=10;
+ dummy_mutex mutexes[num_mutexes];
+
+ boost::lock(mutexes,mutexes+num_mutexes);
+
+ for(unsigned i=0;i<num_mutexes;++i)
+ {
+ BOOST_CHECK(mutexes[i].is_locked);
+ }
+}
+
+void test_try_lock_two_uncontended()
+{
+ dummy_mutex m1,m2;
+
+ int const res=boost::try_lock(m1,m2);
+
+ BOOST_CHECK(res==-1);
+ BOOST_CHECK(m1.is_locked);
+ BOOST_CHECK(m2.is_locked);
+}
+void test_try_lock_two_first_locked()
+{
+ dummy_mutex m1,m2;
+ m1.lock();
+
+ boost::unique_lock<dummy_mutex> l1(m1,boost::defer_lock),
+ l2(m2,boost::defer_lock);
+
+ int const res=boost::try_lock(l1,l2);
+
+ BOOST_CHECK(res==0);
+ BOOST_CHECK(m1.is_locked);
+ BOOST_CHECK(!m2.is_locked);
+ BOOST_CHECK(!l1.owns_lock());
+ BOOST_CHECK(!l2.owns_lock());
+}
+void test_try_lock_two_second_locked()
+{
+ dummy_mutex m1,m2;
+ m2.lock();
+
+ boost::unique_lock<dummy_mutex> l1(m1,boost::defer_lock),
+ l2(m2,boost::defer_lock);
+
+ int const res=boost::try_lock(l1,l2);
+
+ BOOST_CHECK(res==1);
+ BOOST_CHECK(!m1.is_locked);
+ BOOST_CHECK(m2.is_locked);
+ BOOST_CHECK(!l1.owns_lock());
+ BOOST_CHECK(!l2.owns_lock());
+}
+
+void test_try_lock_three()
+{
+ int const num_mutexes=3;
+
+ for(int i=-1;i<num_mutexes;++i)
+ {
+ dummy_mutex mutexes[num_mutexes];
+
+ if(i>=0)
+ {
+ mutexes[i].lock();
+ }
+ boost::unique_lock<dummy_mutex> l1(mutexes[0],boost::defer_lock),
+ l2(mutexes[1],boost::defer_lock),
+ l3(mutexes[2],boost::defer_lock);
+
+ int const res=boost::try_lock(l1,l2,l3);
+
+ BOOST_CHECK(res==i);
+ for(int j=0;j<num_mutexes;++j)
+ {
+ if((i==j) || (i==-1))
+ {
+ BOOST_CHECK(mutexes[j].is_locked);
+ }
+ else
+ {
+ BOOST_CHECK(!mutexes[j].is_locked);
+ }
+ }
+ if(i==-1)
+ {
+ BOOST_CHECK(l1.owns_lock());
+ BOOST_CHECK(l2.owns_lock());
+ BOOST_CHECK(l3.owns_lock());
+ }
+ else
+ {
+ BOOST_CHECK(!l1.owns_lock());
+ BOOST_CHECK(!l2.owns_lock());
+ BOOST_CHECK(!l3.owns_lock());
+ }
+ }
+}
+
+void test_try_lock_four()
+{
+ int const num_mutexes=4;
+
+ for(int i=-1;i<num_mutexes;++i)
+ {
+ dummy_mutex mutexes[num_mutexes];
+
+ if(i>=0)
+ {
+ mutexes[i].lock();
+ }
+ boost::unique_lock<dummy_mutex> l1(mutexes[0],boost::defer_lock),
+ l2(mutexes[1],boost::defer_lock),
+ l3(mutexes[2],boost::defer_lock),
+ l4(mutexes[3],boost::defer_lock);
+
+ int const res=boost::try_lock(l1,l2,l3,l4);
+
+ BOOST_CHECK(res==i);
+ for(int j=0;j<num_mutexes;++j)
+ {
+ if((i==j) || (i==-1))
+ {
+ BOOST_CHECK(mutexes[j].is_locked);
+ }
+ else
+ {
+ BOOST_CHECK(!mutexes[j].is_locked);
+ }
+ }
+ if(i==-1)
+ {
+ BOOST_CHECK(l1.owns_lock());
+ BOOST_CHECK(l2.owns_lock());
+ BOOST_CHECK(l3.owns_lock());
+ BOOST_CHECK(l4.owns_lock());
+ }
+ else
+ {
+ BOOST_CHECK(!l1.owns_lock());
+ BOOST_CHECK(!l2.owns_lock());
+ BOOST_CHECK(!l3.owns_lock());
+ BOOST_CHECK(!l4.owns_lock());
+ }
+ }
+}
+
+void test_try_lock_five()
+{
+ int const num_mutexes=5;
+
+ for(int i=-1;i<num_mutexes;++i)
+ {
+ dummy_mutex mutexes[num_mutexes];
+
+ if(i>=0)
+ {
+ mutexes[i].lock();
+ }
+ boost::unique_lock<dummy_mutex> l1(mutexes[0],boost::defer_lock),
+ l2(mutexes[1],boost::defer_lock),
+ l3(mutexes[2],boost::defer_lock),
+ l4(mutexes[3],boost::defer_lock),
+ l5(mutexes[4],boost::defer_lock);
+
+ int const res=boost::try_lock(l1,l2,l3,l4,l5);
+
+ BOOST_CHECK(res==i);
+ for(int j=0;j<num_mutexes;++j)
+ {
+ if((i==j) || (i==-1))
+ {
+ BOOST_CHECK(mutexes[j].is_locked);
+ }
+ else
+ {
+ BOOST_CHECK(!mutexes[j].is_locked);
+ }
+ }
+ if(i==-1)
+ {
+ BOOST_CHECK(l1.owns_lock());
+ BOOST_CHECK(l2.owns_lock());
+ BOOST_CHECK(l3.owns_lock());
+ BOOST_CHECK(l4.owns_lock());
+ BOOST_CHECK(l5.owns_lock());
+ }
+ else
+ {
+ BOOST_CHECK(!l1.owns_lock());
+ BOOST_CHECK(!l2.owns_lock());
+ BOOST_CHECK(!l3.owns_lock());
+ BOOST_CHECK(!l4.owns_lock());
+ BOOST_CHECK(!l5.owns_lock());
+ }
+ }
+}
+
+
+
+boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
+{
+ boost::unit_test_framework::test_suite* test =
+ BOOST_TEST_SUITE("Boost.Threads: generic locks test suite");
+
+ test->add(BOOST_TEST_CASE(&test_lock_two_uncontended));
+ test->add(BOOST_TEST_CASE(&test_lock_two_other_thread_locks_in_order));
+ test->add(BOOST_TEST_CASE(&test_lock_two_other_thread_locks_in_opposite_order));
+ test->add(BOOST_TEST_CASE(&test_lock_five_uncontended));
+ test->add(BOOST_TEST_CASE(&test_lock_five_other_thread_locks_in_order));
+ test->add(BOOST_TEST_CASE(&test_lock_five_other_thread_locks_in_different_order));
+ test->add(BOOST_TEST_CASE(&test_lock_five_in_range));
+ test->add(BOOST_TEST_CASE(&test_lock_ten_in_range));
+ test->add(BOOST_TEST_CASE(&test_lock_ten_other_thread_locks_in_different_order));
+ test->add(BOOST_TEST_CASE(&test_try_lock_two_uncontended));
+ test->add(BOOST_TEST_CASE(&test_try_lock_two_first_locked));
+ test->add(BOOST_TEST_CASE(&test_try_lock_two_second_locked));
+ test->add(BOOST_TEST_CASE(&test_try_lock_three));
+ test->add(BOOST_TEST_CASE(&test_try_lock_four));
+ test->add(BOOST_TEST_CASE(&test_try_lock_five));
+
+ return test;
+}

Added: sandbox/chrono/libs/thread/test/test_hardware_concurrency.cpp
==============================================================================
--- (empty file)
+++ sandbox/chrono/libs/thread/test/test_hardware_concurrency.cpp 2010-05-20 03:55:54 EDT (Thu, 20 May 2010)
@@ -0,0 +1,21 @@
+// Copyright (C) 2007 Anthony Williams
+//
+// Distributed under 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)
+#include <boost/thread/thread.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/thread/mutex.hpp>
+
+void test_hardware_concurrency_is_non_zero()
+{
+ BOOST_CHECK(boost::thread::hardware_concurrency()!=0);
+}
+
+boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
+{
+ boost::unit_test_framework::test_suite* test =
+ BOOST_TEST_SUITE("Boost.Threads: hardware concurrency test suite");
+
+ test->add(BOOST_TEST_CASE(test_hardware_concurrency_is_non_zero));
+ return test;
+}

Added: sandbox/chrono/libs/thread/test/test_lock_concept.cpp
==============================================================================
--- (empty file)
+++ sandbox/chrono/libs/thread/test/test_lock_concept.cpp 2010-05-20 03:55:54 EDT (Thu, 20 May 2010)
@@ -0,0 +1,571 @@
+// (C) Copyright 2006-8 Anthony Williams
+// Distributed under 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)
+
+#include <boost/test/unit_test.hpp>
+#include <boost/test/test_case_template.hpp>
+#include <boost/mpl/vector.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/shared_mutex.hpp>
+#include <boost/thread/thread.hpp>
+#include <boost/thread/recursive_mutex.hpp>
+#include <boost/thread/condition_variable.hpp>
+
+template<typename Mutex,typename Lock>
+struct test_initially_locked
+{
+ void operator()() const
+ {
+ Mutex m;
+ Lock lock(m);
+
+ BOOST_CHECK(lock);
+ BOOST_CHECK(lock.owns_lock());
+ }
+};
+
+template<typename Mutex,typename Lock>
+struct test_initially_unlocked_if_other_thread_has_lock
+{
+ Mutex m;
+ boost::mutex done_mutex;
+ bool done;
+ bool locked;
+ boost::condition_variable done_cond;
+
+ test_initially_unlocked_if_other_thread_has_lock():
+ 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;
+ }
+
+
+ void operator()()
+ {
+ Lock lock(m);
+
+ typedef test_initially_unlocked_if_other_thread_has_lock<Mutex,Lock> this_type;
+
+ boost::thread t(&this_type::locking_thread,this);
+
+ try
+ {
+ {
+ boost::mutex::scoped_lock lk(done_mutex);
+ BOOST_CHECK(done_cond.timed_wait(lk,boost::posix_time::seconds(2),
+ boost::bind(&this_type::is_done,this)));
+ BOOST_CHECK(!locked);
+ }
+
+ lock.unlock();
+ t.join();
+ }
+ catch(...)
+ {
+ lock.unlock();
+ t.join();
+ throw;
+ }
+ }
+};
+
+template<typename Mutex,typename Lock>
+struct test_initially_unlocked_with_try_lock_if_other_thread_has_unique_lock
+{
+ Mutex m;
+ boost::mutex done_mutex;
+ bool done;
+ bool locked;
+ boost::condition_variable done_cond;
+
+ test_initially_unlocked_with_try_lock_if_other_thread_has_unique_lock():
+ done(false),locked(false)
+ {}
+
+ void locking_thread()
+ {
+ Lock lock(m,boost::try_to_lock);
+
+ boost::lock_guard<boost::mutex> lk(done_mutex);
+ locked=lock.owns_lock();
+ done=true;
+ done_cond.notify_one();
+ }
+
+ bool is_done() const
+ {
+ return done;
+ }
+
+
+ void operator()()
+ {
+ boost::unique_lock<Mutex> lock(m);
+
+ typedef test_initially_unlocked_with_try_lock_if_other_thread_has_unique_lock<Mutex,Lock> this_type;
+
+ boost::thread t(&this_type::locking_thread,this);
+
+ try
+ {
+ {
+ boost::mutex::scoped_lock lk(done_mutex);
+ BOOST_CHECK(done_cond.timed_wait(lk,boost::posix_time::seconds(2),
+ boost::bind(&this_type::is_done,this)));
+ BOOST_CHECK(!locked);
+ }
+
+ lock.unlock();
+ t.join();
+ }
+ catch(...)
+ {
+ lock.unlock();
+ t.join();
+ throw;
+ }
+ }
+};
+
+template<typename Mutex,typename Lock>
+struct test_initially_locked_if_other_thread_has_shared_lock
+{
+ Mutex m;
+ boost::mutex done_mutex;
+ bool done;
+ bool locked;
+ boost::condition_variable done_cond;
+
+ test_initially_locked_if_other_thread_has_shared_lock():
+ 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;
+ }
+
+
+ void operator()()
+ {
+ boost::shared_lock<Mutex> lock(m);
+
+ typedef test_initially_locked_if_other_thread_has_shared_lock<Mutex,Lock> this_type;
+
+ boost::thread t(&this_type::locking_thread,this);
+
+ try
+ {
+ {
+ boost::mutex::scoped_lock lk(done_mutex);
+ BOOST_CHECK(done_cond.timed_wait(lk,boost::posix_time::seconds(2),
+ boost::bind(&this_type::is_done,this)));
+ BOOST_CHECK(locked);
+ }
+
+ lock.unlock();
+ t.join();
+ }
+ catch(...)
+ {
+ lock.unlock();
+ t.join();
+ throw;
+ }
+ }
+};
+
+template<typename Mutex,typename Lock>
+struct test_initially_unlocked_with_defer_lock_parameter
+{
+ void operator()() const
+ {
+ Mutex m;
+ Lock lock(m,boost::defer_lock);
+
+ BOOST_CHECK(!lock);
+ BOOST_CHECK(!lock.owns_lock());
+ }
+};
+
+template<typename Mutex,typename Lock>
+struct test_initially_locked_with_adopt_lock_parameter
+{
+ void operator()() const
+ {
+ Mutex m;
+ m.lock();
+ Lock lock(m,boost::adopt_lock);
+
+ BOOST_CHECK(lock);
+ BOOST_CHECK(lock.owns_lock());
+ }
+};
+
+
+template<typename Mutex,typename Lock>
+struct test_unlocked_after_unlock_called
+{
+ void operator()() const
+ {
+ Mutex m;
+ Lock lock(m);
+ lock.unlock();
+ BOOST_CHECK(!lock);
+ BOOST_CHECK(!lock.owns_lock());
+ }
+};
+
+template<typename Mutex,typename Lock>
+struct test_locked_after_lock_called
+{
+ void operator()() const
+ {
+ Mutex m;
+ Lock lock(m,boost::defer_lock);
+ lock.lock();
+ BOOST_CHECK(lock);
+ BOOST_CHECK(lock.owns_lock());
+ }
+};
+
+template<typename Mutex,typename Lock>
+struct test_locked_after_try_lock_called
+{
+ void operator()() const
+ {
+ Mutex m;
+ Lock lock(m,boost::defer_lock);
+ lock.try_lock();
+ BOOST_CHECK(lock);
+ BOOST_CHECK(lock.owns_lock());
+ }
+};
+
+template<typename Mutex,typename Lock>
+struct test_unlocked_after_try_lock_if_other_thread_has_lock
+{
+ Mutex m;
+ boost::mutex done_mutex;
+ bool done;
+ bool locked;
+ boost::condition_variable done_cond;
+
+ test_unlocked_after_try_lock_if_other_thread_has_lock():
+ done(false),locked(false)
+ {}
+
+ void locking_thread()
+ {
+ Lock lock(m,boost::defer_lock);
+
+ boost::lock_guard<boost::mutex> lk(done_mutex);
+ locked=lock.owns_lock();
+ done=true;
+ done_cond.notify_one();
+ }
+
+ bool is_done() const
+ {
+ return done;
+ }
+
+
+ void operator()()
+ {
+ Lock lock(m);
+
+ typedef test_unlocked_after_try_lock_if_other_thread_has_lock<Mutex,Lock> this_type;
+
+ boost::thread t(&this_type::locking_thread,this);
+
+ try
+ {
+ {
+ boost::mutex::scoped_lock lk(done_mutex);
+ BOOST_CHECK(done_cond.timed_wait(lk,boost::posix_time::seconds(2),
+ boost::bind(&this_type::is_done,this)));
+ BOOST_CHECK(!locked);
+ }
+
+ lock.unlock();
+ t.join();
+ }
+ catch(...)
+ {
+ lock.unlock();
+ t.join();
+ throw;
+ }
+ }
+};
+
+template<typename Mutex,typename Lock>
+struct test_throws_if_lock_called_when_already_locked
+{
+ void operator()() const
+ {
+ Mutex m;
+ Lock lock(m);
+
+ BOOST_CHECK_THROW( lock.lock(), boost::lock_error );
+ }
+};
+
+template<typename Mutex,typename Lock>
+struct test_throws_if_try_lock_called_when_already_locked
+{
+ void operator()() const
+ {
+ Mutex m;
+ Lock lock(m);
+
+ BOOST_CHECK_THROW( lock.try_lock(), boost::lock_error );
+ }
+};
+
+template<typename Mutex,typename Lock>
+struct test_throws_if_unlock_called_when_already_unlocked
+{
+ void operator()() const
+ {
+ Mutex m;
+ Lock lock(m);
+ lock.unlock();
+
+ BOOST_CHECK_THROW( lock.unlock(), boost::lock_error );
+ }
+};
+template<typename Lock>
+struct test_default_constructed_has_no_mutex_and_unlocked
+{
+ void operator()() const
+ {
+ Lock l;
+ BOOST_CHECK(!l.mutex());
+ BOOST_CHECK(!l.owns_lock());
+ };
+};
+
+
+template<typename Mutex,typename Lock>
+struct test_locks_can_be_swapped
+{
+ void operator()() const
+ {
+ Mutex m1;
+ Mutex m2;
+ Mutex m3;
+
+ Lock l1(m1);
+ Lock l2(m2);
+
+ BOOST_CHECK_EQUAL(l1.mutex(),&m1);
+ BOOST_CHECK_EQUAL(l2.mutex(),&m2);
+
+ l1.swap(l2);
+
+ BOOST_CHECK_EQUAL(l1.mutex(),&m2);
+ BOOST_CHECK_EQUAL(l2.mutex(),&m1);
+
+ swap(l1,l2);
+
+ BOOST_CHECK_EQUAL(l1.mutex(),&m1);
+ BOOST_CHECK_EQUAL(l2.mutex(),&m2);
+
+ l1.swap(Lock(m3));
+
+ BOOST_CHECK_EQUAL(l1.mutex(),&m3);
+ }
+};
+
+template<typename Mutex,typename Lock>
+void test_lock_is_scoped_lock_concept_for_mutex()
+{
+ test_default_constructed_has_no_mutex_and_unlocked<Lock>()();
+ test_initially_locked<Mutex,Lock>()();
+ test_initially_unlocked_with_defer_lock_parameter<Mutex,Lock>()();
+ test_initially_locked_with_adopt_lock_parameter<Mutex,Lock>()();
+ test_unlocked_after_unlock_called<Mutex,Lock>()();
+ test_locked_after_lock_called<Mutex,Lock>()();
+ test_throws_if_lock_called_when_already_locked<Mutex,Lock>()();
+ test_throws_if_unlock_called_when_already_unlocked<Mutex,Lock>()();
+ test_locks_can_be_swapped<Mutex,Lock>()();
+ test_locked_after_try_lock_called<Mutex,Lock>()();
+ test_throws_if_try_lock_called_when_already_locked<Mutex,Lock>()();
+ test_unlocked_after_try_lock_if_other_thread_has_lock<Mutex,Lock>()();
+}
+
+
+BOOST_TEST_CASE_TEMPLATE_FUNCTION(test_scoped_lock_concept,Mutex)
+{
+ typedef typename Mutex::scoped_lock Lock;
+
+ test_lock_is_scoped_lock_concept_for_mutex<Mutex,Lock>();
+}
+
+BOOST_TEST_CASE_TEMPLATE_FUNCTION(test_unique_lock_is_scoped_lock,Mutex)
+{
+ typedef boost::unique_lock<Mutex> Lock;
+
+ test_lock_is_scoped_lock_concept_for_mutex<Mutex,Lock>();
+}
+
+BOOST_TEST_CASE_TEMPLATE_FUNCTION(test_scoped_try_lock_concept,Mutex)
+{
+ typedef typename Mutex::scoped_try_lock Lock;
+
+ test_default_constructed_has_no_mutex_and_unlocked<Lock>()();
+ test_initially_locked<Mutex,Lock>()();
+ test_initially_unlocked_if_other_thread_has_lock<Mutex,Lock>()();
+ test_initially_unlocked_with_defer_lock_parameter<Mutex,Lock>()();
+ test_initially_locked_with_adopt_lock_parameter<Mutex,Lock>()();
+ test_unlocked_after_unlock_called<Mutex,Lock>()();
+ test_locked_after_lock_called<Mutex,Lock>()();
+ test_locked_after_try_lock_called<Mutex,Lock>()();
+ test_unlocked_after_try_lock_if_other_thread_has_lock<Mutex,Lock>()();
+ test_throws_if_lock_called_when_already_locked<Mutex,Lock>()();
+ test_throws_if_try_lock_called_when_already_locked<Mutex,Lock>()();
+ test_throws_if_unlock_called_when_already_unlocked<Mutex,Lock>()();
+ test_locks_can_be_swapped<Mutex,Lock>()();
+}
+
+struct dummy_shared_mutex
+{
+ bool locked;
+ bool shared_locked;
+ bool shared_unlocked;
+ bool shared_timed_locked_relative;
+ bool shared_timed_locked_absolute;
+ bool timed_locked_relative;
+ bool timed_locked_absolute;
+
+ dummy_shared_mutex():
+ locked(false),shared_locked(false),shared_unlocked(false),
+ shared_timed_locked_relative(false),
+ shared_timed_locked_absolute(false),
+ timed_locked_relative(false),
+ timed_locked_absolute(false)
+ {}
+
+ void lock()
+ {
+ locked=true;
+ }
+
+ void lock_shared()
+ {
+ shared_locked=true;
+ }
+
+ void unlock()
+ {}
+
+ void unlock_shared()
+ {
+ shared_unlocked=true;
+ }
+
+ bool timed_lock_shared(boost::system_time)
+ {
+ shared_timed_locked_absolute=true;
+ return false;
+ }
+ template<typename Duration>
+ bool timed_lock_shared(Duration)
+ {
+ shared_timed_locked_relative=true;
+ return false;
+ }
+ bool timed_lock(boost::system_time)
+ {
+ timed_locked_absolute=true;
+ return false;
+ }
+ template<typename Duration>
+ bool timed_lock(Duration)
+ {
+ timed_locked_relative=true;
+ return false;
+ }
+
+};
+
+
+void test_shared_lock()
+{
+ typedef boost::shared_mutex Mutex;
+ typedef boost::shared_lock<Mutex> Lock;
+
+ test_default_constructed_has_no_mutex_and_unlocked<Lock>()();
+ test_initially_locked<Mutex,Lock>()();
+ test_initially_unlocked_with_try_lock_if_other_thread_has_unique_lock<Mutex,Lock>()();
+ test_initially_locked_if_other_thread_has_shared_lock<Mutex,Lock>()();
+ test_initially_unlocked_with_defer_lock_parameter<Mutex,Lock>()();
+ test_initially_locked_with_adopt_lock_parameter<Mutex,Lock>()();
+ test_unlocked_after_unlock_called<Mutex,Lock>()();
+ test_locked_after_lock_called<Mutex,Lock>()();
+ test_locked_after_try_lock_called<Mutex,Lock>()();
+ test_throws_if_lock_called_when_already_locked<Mutex,Lock>()();
+ test_throws_if_try_lock_called_when_already_locked<Mutex,Lock>()();
+ test_throws_if_unlock_called_when_already_unlocked<Mutex,Lock>()();
+ test_locks_can_be_swapped<Mutex,Lock>()();
+
+ dummy_shared_mutex dummy;
+ boost::shared_lock<dummy_shared_mutex> lk(dummy);
+ BOOST_CHECK(dummy.shared_locked);
+ lk.unlock();
+ BOOST_CHECK(dummy.shared_unlocked);
+ lk.timed_lock(boost::posix_time::milliseconds(5));
+ BOOST_CHECK(dummy.shared_timed_locked_relative);
+ lk.timed_lock(boost::get_system_time());
+ BOOST_CHECK(dummy.shared_timed_locked_absolute);
+}
+
+boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
+{
+ boost::unit_test_framework::test_suite* test =
+ BOOST_TEST_SUITE("Boost.Threads: lock concept test suite");
+
+ typedef boost::mpl::vector<boost::mutex,boost::try_mutex,boost::timed_mutex,
+ boost::recursive_mutex,boost::recursive_try_mutex,boost::recursive_timed_mutex> mutex_types_with_scoped_lock;
+
+ test->add(BOOST_TEST_CASE_TEMPLATE(test_scoped_lock_concept,mutex_types_with_scoped_lock));
+
+ typedef boost::mpl::vector<boost::try_mutex,boost::timed_mutex,
+ boost::recursive_try_mutex,boost::recursive_timed_mutex> mutex_types_with_scoped_try_lock;
+
+ test->add(BOOST_TEST_CASE_TEMPLATE(test_scoped_try_lock_concept,mutex_types_with_scoped_try_lock));
+
+ typedef boost::mpl::vector<boost::mutex,boost::try_mutex,boost::timed_mutex,
+ boost::recursive_mutex,boost::recursive_try_mutex,boost::recursive_timed_mutex,boost::shared_mutex> all_mutex_types;
+
+ test->add(BOOST_TEST_CASE_TEMPLATE(test_unique_lock_is_scoped_lock,all_mutex_types));
+ test->add(BOOST_TEST_CASE(&test_shared_lock));
+
+ return test;
+}

Added: sandbox/chrono/libs/thread/test/test_move_function.cpp
==============================================================================
--- (empty file)
+++ sandbox/chrono/libs/thread/test/test_move_function.cpp 2010-05-20 03:55:54 EDT (Thu, 20 May 2010)
@@ -0,0 +1,124 @@
+// Copyright (C) 2007-8 Anthony Williams
+//
+// Distributed under 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)
+#include <boost/thread/thread.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/shared_ptr.hpp>
+
+void do_nothing()
+{}
+
+void test_thread_move_from_lvalue_on_construction()
+{
+ boost::thread src(do_nothing);
+ boost::thread::id src_id=src.get_id();
+ boost::thread dest(boost::move(src));
+ boost::thread::id dest_id=dest.get_id();
+ BOOST_CHECK(src_id==dest_id);
+ BOOST_CHECK(src.get_id()==boost::thread::id());
+ dest.join();
+}
+
+void test_thread_move_from_lvalue_on_assignment()
+{
+ boost::thread src(do_nothing);
+ boost::thread::id src_id=src.get_id();
+ boost::thread dest;
+ dest=boost::move(src);
+ boost::thread::id dest_id=dest.get_id();
+ BOOST_CHECK(src_id==dest_id);
+ BOOST_CHECK(src.get_id()==boost::thread::id());
+ dest.join();
+}
+
+boost::thread start_thread()
+{
+ return boost::thread(do_nothing);
+}
+
+void test_thread_move_from_rvalue_on_construction()
+{
+ boost::thread x(start_thread());
+ BOOST_CHECK(x.get_id()!=boost::thread::id());
+ x.join();
+}
+
+void test_thread_move_from_rvalue_using_explicit_move()
+{
+ boost::thread x(boost::move(start_thread()));
+ BOOST_CHECK(x.get_id()!=boost::thread::id());
+ x.join();
+}
+
+void test_unique_lock_move_from_lvalue_on_construction()
+{
+ boost::mutex m;
+ boost::unique_lock<boost::mutex> l(m);
+ BOOST_CHECK(l.owns_lock());
+ BOOST_CHECK(l.mutex()==&m);
+
+ boost::unique_lock<boost::mutex> l2(boost::move(l));
+ BOOST_CHECK(!l.owns_lock());
+ BOOST_CHECK(!l.mutex());
+ BOOST_CHECK(l2.owns_lock());
+ BOOST_CHECK(l2.mutex()==&m);
+}
+
+boost::unique_lock<boost::mutex> get_lock(boost::mutex& m)
+{
+ return boost::unique_lock<boost::mutex>(m);
+}
+
+
+void test_unique_lock_move_from_rvalue_on_construction()
+{
+ boost::mutex m;
+ boost::unique_lock<boost::mutex> l(get_lock(m));
+ BOOST_CHECK(l.owns_lock());
+ BOOST_CHECK(l.mutex()==&m);
+}
+
+namespace user_test_ns
+{
+ template<typename T>
+ T move(T& t)
+ {
+ return t.move();
+ }
+
+ bool move_called=false;
+
+ struct nc:
+ public boost::shared_ptr<int>
+ {
+ nc move()
+ {
+ move_called=true;
+ return nc();
+ }
+ };
+}
+
+void test_move_for_user_defined_type_unaffected()
+{
+ user_test_ns::nc src;
+ user_test_ns::nc dest=move(src);
+ BOOST_CHECK(user_test_ns::move_called);
+}
+
+boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
+{
+ boost::unit_test_framework::test_suite* test =
+ BOOST_TEST_SUITE("Boost.Threads: thread move test suite");
+
+ test->add(BOOST_TEST_CASE(test_thread_move_from_lvalue_on_construction));
+ test->add(BOOST_TEST_CASE(test_thread_move_from_rvalue_on_construction));
+ test->add(BOOST_TEST_CASE(test_thread_move_from_rvalue_using_explicit_move));
+ test->add(BOOST_TEST_CASE(test_thread_move_from_lvalue_on_assignment));
+ test->add(BOOST_TEST_CASE(test_unique_lock_move_from_lvalue_on_construction));
+ test->add(BOOST_TEST_CASE(test_unique_lock_move_from_rvalue_on_construction));
+ test->add(BOOST_TEST_CASE(test_move_for_user_defined_type_unaffected));
+ return test;
+}

Added: sandbox/chrono/libs/thread/test/test_mutex.cpp
==============================================================================
--- (empty file)
+++ sandbox/chrono/libs/thread/test/test_mutex.cpp 2010-05-20 03:55:54 EDT (Thu, 20 May 2010)
@@ -0,0 +1,347 @@
+// Copyright (C) 2001-2003
+// William E. Kempf
+//
+// Distributed under 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)
+
+#include <boost/thread/detail/config.hpp>
+
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/thread.hpp>
+#include <boost/thread/recursive_mutex.hpp>
+#include <boost/thread/thread_time.hpp>
+#include <boost/thread/condition.hpp>
+
+#include <boost/test/unit_test.hpp>
+
+#define DEFAULT_EXECUTION_MONITOR_TYPE execution_monitor::use_sleep_only
+#include <libs/thread/test/util.inl>
+
+template <typename M>
+struct test_lock
+{
+ typedef M mutex_type;
+ typedef typename M::scoped_lock 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 and initialize an xtime for a fast time out.
+ boost::xtime xt = delay(0, 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, xt));
+ 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 M::scoped_try_lock try_lock_type;
+
+ void operator()()
+ {
+ mutex_type mutex;
+ boost::condition condition;
+
+ // Test the lock's constructors.
+ {
+ try_lock_type lock(mutex);
+ BOOST_CHECK(lock ? true : false);
+ }
+ {
+ try_lock_type lock(mutex, boost::defer_lock);
+ BOOST_CHECK(!lock);
+ }
+ try_lock_type lock(mutex);
+ BOOST_CHECK(lock ? true : false);
+
+ // Construct and initialize an xtime for a fast time out.
+ boost::xtime xt = delay(0, 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, xt));
+ 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_times_out_if_other_thread_has_lock
+{
+ typedef boost::unique_lock<Mutex> Lock;
+
+ Mutex m;
+ boost::mutex done_mutex;
+ bool done;
+ bool locked;
+ boost::condition_variable done_cond;
+
+ test_lock_times_out_if_other_thread_has_lock():
+ done(false),locked(false)
+ {}
+
+ void locking_thread()
+ {
+ Lock lock(m,boost::defer_lock);
+ lock.timed_lock(boost::posix_time::milliseconds(50));
+
+ boost::lock_guard<boost::mutex> lk(done_mutex);
+ locked=lock.owns_lock();
+ done=true;
+ done_cond.notify_one();
+ }
+
+ void locking_thread_through_constructor()
+ {
+ Lock lock(m,boost::posix_time::milliseconds(50));
+
+ 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_times_out_if_other_thread_has_lock<Mutex> this_type;
+
+ void do_test(void (this_type::*test_func)())
+ {
+ Lock lock(m);
+
+ 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(2),
+ boost::bind(&this_type::is_done,this)));
+ BOOST_CHECK(!locked);
+ }
+
+ lock.unlock();
+ t.join();
+ }
+ catch(...)
+ {
+ lock.unlock();
+ t.join();
+ throw;
+ }
+ }
+
+
+ void operator()()
+ {
+ do_test(&this_type::locking_thread);
+ do_test(&this_type::locking_thread_through_constructor);
+ }
+};
+
+template <typename M>
+struct test_timedlock
+{
+ typedef M mutex_type;
+ typedef typename M::scoped_timed_lock timed_lock_type;
+
+ static bool fake_predicate()
+ {
+ return false;
+ }
+
+ void operator()()
+ {
+ test_lock_times_out_if_other_thread_has_lock<mutex_type>()();
+
+ mutex_type mutex;
+ boost::condition condition;
+
+ // Test the lock's constructors.
+ {
+ // Construct and initialize an xtime for a fast time out.
+ boost::system_time xt = boost::get_system_time()+boost::posix_time::milliseconds(100);
+
+ timed_lock_type lock(mutex, xt);
+ BOOST_CHECK(lock ? true : false);
+ }
+ {
+ timed_lock_type lock(mutex, boost::defer_lock);
+ BOOST_CHECK(!lock);
+ }
+ timed_lock_type lock(mutex);
+ BOOST_CHECK(lock ? true : false);
+
+ // Construct and initialize an xtime for a fast time out.
+ boost::system_time timeout = boost::get_system_time()+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, fake_predicate));
+ BOOST_CHECK(lock ? true : false);
+
+ boost::system_time now=boost::get_system_time();
+ boost::posix_time::milliseconds const timeout_resolution(20);
+ BOOST_CHECK((timeout-timeout_resolution)<now);
+
+ // Test the lock, unlock and timedlock methods.
+ lock.unlock();
+ BOOST_CHECK(!lock);
+ lock.lock();
+ BOOST_CHECK(lock ? true : false);
+ lock.unlock();
+ BOOST_CHECK(!lock);
+ boost::system_time target = boost::get_system_time()+boost::posix_time::milliseconds(100);
+ BOOST_CHECK(lock.timed_lock(target));
+ BOOST_CHECK(lock ? true : false);
+ lock.unlock();
+ BOOST_CHECK(!lock);
+
+ BOOST_CHECK(mutex.timed_lock(boost::posix_time::milliseconds(100)));
+ mutex.unlock();
+
+ BOOST_CHECK(lock.timed_lock(boost::posix_time::milliseconds(100)));
+ BOOST_CHECK(lock ? true : false);
+ lock.unlock();
+ BOOST_CHECK(!lock);
+
+ }
+};
+
+template <typename M>
+struct test_recursive_lock
+{
+ typedef M mutex_type;
+ typedef typename M::scoped_lock lock_type;
+
+ void operator()()
+ {
+ mutex_type mx;
+ lock_type lock1(mx);
+ lock_type lock2(mx);
+ }
+};
+
+
+void do_test_mutex()
+{
+ test_lock<boost::mutex>()();
+}
+
+void test_mutex()
+{
+ timed_test(&do_test_mutex, 3);
+}
+
+void do_test_try_mutex()
+{
+ test_lock<boost::try_mutex>()();
+ test_trylock<boost::try_mutex>()();
+}
+
+void test_try_mutex()
+{
+ timed_test(&do_test_try_mutex, 3);
+}
+
+void do_test_timed_mutex()
+{
+ test_lock<boost::timed_mutex>()();
+ test_trylock<boost::timed_mutex>()();
+ test_timedlock<boost::timed_mutex>()();
+}
+
+void test_timed_mutex()
+{
+ timed_test(&do_test_timed_mutex, 3);
+}
+
+void do_test_recursive_mutex()
+{
+ test_lock<boost::recursive_mutex>()();
+ test_recursive_lock<boost::recursive_mutex>()();
+}
+
+void test_recursive_mutex()
+{
+ timed_test(&do_test_recursive_mutex, 3);
+}
+
+void do_test_recursive_try_mutex()
+{
+ test_lock<boost::recursive_try_mutex>()();
+ test_trylock<boost::recursive_try_mutex>()();
+ test_recursive_lock<boost::recursive_try_mutex>()();
+}
+
+void test_recursive_try_mutex()
+{
+ timed_test(&do_test_recursive_try_mutex, 3);
+}
+
+void do_test_recursive_timed_mutex()
+{
+ test_lock<boost::recursive_timed_mutex>()();
+ test_trylock<boost::recursive_timed_mutex>()();
+ test_timedlock<boost::recursive_timed_mutex>()();
+ test_recursive_lock<boost::recursive_timed_mutex>()();
+}
+
+void test_recursive_timed_mutex()
+{
+ timed_test(&do_test_recursive_timed_mutex, 3);
+}
+
+boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
+{
+ boost::unit_test_framework::test_suite* test =
+ BOOST_TEST_SUITE("Boost.Threads: mutex test suite");
+
+ test->add(BOOST_TEST_CASE(&test_mutex));
+ test->add(BOOST_TEST_CASE(&test_try_mutex));
+ test->add(BOOST_TEST_CASE(&test_timed_mutex));
+ test->add(BOOST_TEST_CASE(&test_recursive_mutex));
+ test->add(BOOST_TEST_CASE(&test_recursive_try_mutex));
+ test->add(BOOST_TEST_CASE(&test_recursive_timed_mutex));
+
+ return test;
+}

Added: sandbox/chrono/libs/thread/test/test_once.cpp
==============================================================================
--- (empty file)
+++ sandbox/chrono/libs/thread/test/test_once.cpp 2010-05-20 03:55:54 EDT (Thu, 20 May 2010)
@@ -0,0 +1,191 @@
+// (C) Copyright 2006-7 Anthony Williams
+// Distributed under 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)
+
+#include <boost/test/unit_test.hpp>
+#include <boost/thread/thread.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/once.hpp>
+
+boost::once_flag flag=BOOST_ONCE_INIT;
+int var_to_init=0;
+boost::mutex m;
+
+void initialize_variable()
+{
+ // ensure that if multiple threads get in here, they are serialized, so we can see the effect
+ boost::mutex::scoped_lock lock(m);
+ ++var_to_init;
+}
+
+
+void call_once_thread()
+{
+ unsigned const loop_count=100;
+ int my_once_value=0;
+ for(unsigned i=0;i<loop_count;++i)
+ {
+ boost::call_once(flag, initialize_variable);
+ my_once_value=var_to_init;
+ if(my_once_value!=1)
+ {
+ break;
+ }
+ }
+ boost::mutex::scoped_lock lock(m);
+ BOOST_CHECK_EQUAL(my_once_value, 1);
+}
+
+void test_call_once()
+{
+ unsigned const num_threads=20;
+ boost::thread_group group;
+
+ try
+ {
+ for(unsigned i=0;i<num_threads;++i)
+ {
+ group.create_thread(&call_once_thread);
+ }
+ group.join_all();
+ }
+ catch(...)
+ {
+ group.interrupt_all();
+ group.join_all();
+ throw;
+ }
+
+ BOOST_CHECK_EQUAL(var_to_init,1);
+}
+
+int var_to_init_with_functor=0;
+
+struct increment_value
+{
+ int* value;
+ explicit increment_value(int* value_):
+ value(value_)
+ {}
+
+ void operator()() const
+ {
+ boost::mutex::scoped_lock lock(m);
+ ++(*value);
+ }
+};
+
+void call_once_with_functor()
+{
+ unsigned const loop_count=100;
+ int my_once_value=0;
+ static boost::once_flag functor_flag=BOOST_ONCE_INIT;
+ for(unsigned i=0;i<loop_count;++i)
+ {
+ boost::call_once(functor_flag, increment_value(&var_to_init_with_functor));
+ my_once_value=var_to_init_with_functor;
+ if(my_once_value!=1)
+ {
+ break;
+ }
+ }
+ boost::mutex::scoped_lock lock(m);
+ BOOST_CHECK_EQUAL(my_once_value, 1);
+}
+
+void test_call_once_arbitrary_functor()
+{
+ unsigned const num_threads=20;
+ boost::thread_group group;
+
+ try
+ {
+ for(unsigned i=0;i<num_threads;++i)
+ {
+ group.create_thread(&call_once_with_functor);
+ }
+ group.join_all();
+ }
+ catch(...)
+ {
+ group.interrupt_all();
+ group.join_all();
+ throw;
+ }
+
+ BOOST_CHECK_EQUAL(var_to_init_with_functor,1);
+}
+
+
+struct throw_before_third_pass
+{
+ struct my_exception
+ {};
+
+ static unsigned pass_counter;
+
+ void operator()() const
+ {
+ boost::mutex::scoped_lock lock(m);
+ ++pass_counter;
+ if(pass_counter<3)
+ {
+ throw my_exception();
+ }
+ }
+};
+
+unsigned throw_before_third_pass::pass_counter=0;
+unsigned exception_counter=0;
+
+void call_once_with_exception()
+{
+ static boost::once_flag functor_flag=BOOST_ONCE_INIT;
+ try
+ {
+ boost::call_once(functor_flag, throw_before_third_pass());
+ }
+ catch(throw_before_third_pass::my_exception)
+ {
+ boost::mutex::scoped_lock lock(m);
+ ++exception_counter;
+ }
+}
+
+void test_call_once_retried_on_exception()
+{
+ unsigned const num_threads=20;
+ boost::thread_group group;
+
+ try
+ {
+ for(unsigned i=0;i<num_threads;++i)
+ {
+ group.create_thread(&call_once_with_exception);
+ }
+ group.join_all();
+ }
+ catch(...)
+ {
+ group.interrupt_all();
+ group.join_all();
+ throw;
+ }
+
+ BOOST_CHECK_EQUAL(throw_before_third_pass::pass_counter,3u);
+ BOOST_CHECK_EQUAL(exception_counter,2u);
+}
+
+
+boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
+{
+ boost::unit_test_framework::test_suite* test =
+ BOOST_TEST_SUITE("Boost.Threads: call_once test suite");
+
+ test->add(BOOST_TEST_CASE(test_call_once));
+ test->add(BOOST_TEST_CASE(test_call_once_arbitrary_functor));
+ test->add(BOOST_TEST_CASE(test_call_once_retried_on_exception));
+
+ return test;
+}

Added: sandbox/chrono/libs/thread/test/test_shared_mutex.cpp
==============================================================================
--- (empty file)
+++ sandbox/chrono/libs/thread/test/test_shared_mutex.cpp 2010-05-20 03:55:54 EDT (Thu, 20 May 2010)
@@ -0,0 +1,285 @@
+// (C) Copyright 2006-7 Anthony Williams
+// Distributed under 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)
+
+#include <boost/test/unit_test.hpp>
+#include <boost/thread/thread.hpp>
+#include <boost/thread/xtime.hpp>
+#include "util.inl"
+#include "shared_mutex_locking_thread.hpp"
+
+#define CHECK_LOCKED_VALUE_EQUAL(mutex_name,value,expected_value) \
+ { \
+ boost::mutex::scoped_lock lock(mutex_name); \
+ BOOST_CHECK_EQUAL(value,expected_value); \
+ }
+
+void test_multiple_readers()
+{
+ unsigned const number_of_threads=10;
+
+ boost::thread_group pool;
+
+ boost::shared_mutex rw_mutex;
+ unsigned unblocked_count=0;
+ unsigned simultaneous_running_count=0;
+ unsigned max_simultaneous_running=0;
+ boost::mutex unblocked_count_mutex;
+ boost::condition_variable unblocked_condition;
+ boost::mutex finish_mutex;
+ boost::mutex::scoped_lock finish_lock(finish_mutex);
+
+ try
+ {
+ for(unsigned i=0;i<number_of_threads;++i)
+ {
+ pool.create_thread(locking_thread<boost::shared_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
+ finish_mutex,simultaneous_running_count,max_simultaneous_running));
+ }
+
+ {
+ boost::mutex::scoped_lock lk(unblocked_count_mutex);
+ while(unblocked_count<number_of_threads)
+ {
+ unblocked_condition.wait(lk);
+ }
+ }
+
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,number_of_threads);
+
+ finish_lock.unlock();
+
+ pool.join_all();
+ }
+ catch(...)
+ {
+ pool.interrupt_all();
+ pool.join_all();
+ throw;
+ }
+
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,number_of_threads);
+}
+
+void test_only_one_writer_permitted()
+{
+ unsigned const number_of_threads=10;
+
+ boost::thread_group pool;
+
+ boost::shared_mutex rw_mutex;
+ unsigned unblocked_count=0;
+ unsigned simultaneous_running_count=0;
+ unsigned max_simultaneous_running=0;
+ boost::mutex unblocked_count_mutex;
+ boost::condition_variable unblocked_condition;
+ boost::mutex finish_mutex;
+ boost::mutex::scoped_lock finish_lock(finish_mutex);
+
+ try
+ {
+ for(unsigned i=0;i<number_of_threads;++i)
+ {
+ pool.create_thread(locking_thread<boost::unique_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
+ finish_mutex,simultaneous_running_count,max_simultaneous_running));
+ }
+
+ boost::thread::sleep(delay(2));
+
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U);
+
+ finish_lock.unlock();
+
+ pool.join_all();
+ }
+ catch(...)
+ {
+ pool.interrupt_all();
+ pool.join_all();
+ throw;
+ }
+
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,number_of_threads);
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,1u);
+}
+
+void test_reader_blocks_writer()
+{
+ boost::thread_group pool;
+
+ boost::shared_mutex rw_mutex;
+ unsigned unblocked_count=0;
+ unsigned simultaneous_running_count=0;
+ unsigned max_simultaneous_running=0;
+ boost::mutex unblocked_count_mutex;
+ boost::condition_variable unblocked_condition;
+ boost::mutex finish_mutex;
+ boost::mutex::scoped_lock finish_lock(finish_mutex);
+
+ try
+ {
+
+ pool.create_thread(locking_thread<boost::shared_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
+ finish_mutex,simultaneous_running_count,max_simultaneous_running));
+ {
+ boost::mutex::scoped_lock lk(unblocked_count_mutex);
+ while(unblocked_count<1)
+ {
+ unblocked_condition.wait(lk);
+ }
+ }
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U);
+ pool.create_thread(locking_thread<boost::unique_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
+ finish_mutex,simultaneous_running_count,max_simultaneous_running));
+ boost::thread::sleep(delay(1));
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U);
+
+ finish_lock.unlock();
+
+ pool.join_all();
+ }
+ catch(...)
+ {
+ pool.interrupt_all();
+ pool.join_all();
+ throw;
+ }
+
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,2U);
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,1u);
+}
+
+void test_unlocking_writer_unblocks_all_readers()
+{
+ boost::thread_group pool;
+
+ boost::shared_mutex rw_mutex;
+ boost::unique_lock<boost::shared_mutex> write_lock(rw_mutex);
+ unsigned unblocked_count=0;
+ unsigned simultaneous_running_count=0;
+ unsigned max_simultaneous_running=0;
+ boost::mutex unblocked_count_mutex;
+ boost::condition_variable unblocked_condition;
+ boost::mutex finish_mutex;
+ boost::mutex::scoped_lock finish_lock(finish_mutex);
+
+ unsigned const reader_count=10;
+
+ try
+ {
+ for(unsigned i=0;i<reader_count;++i)
+ {
+ pool.create_thread(locking_thread<boost::shared_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
+ finish_mutex,simultaneous_running_count,max_simultaneous_running));
+ }
+ boost::thread::sleep(delay(1));
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,0U);
+
+ write_lock.unlock();
+
+ {
+ boost::mutex::scoped_lock lk(unblocked_count_mutex);
+ while(unblocked_count<reader_count)
+ {
+ unblocked_condition.wait(lk);
+ }
+ }
+
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count);
+
+ finish_lock.unlock();
+ pool.join_all();
+ }
+ catch(...)
+ {
+ pool.interrupt_all();
+ pool.join_all();
+ throw;
+ }
+
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,reader_count);
+}
+
+void test_unlocking_last_reader_only_unblocks_one_writer()
+{
+ boost::thread_group pool;
+
+ boost::shared_mutex rw_mutex;
+ unsigned unblocked_count=0;
+ unsigned simultaneous_running_readers=0;
+ unsigned max_simultaneous_readers=0;
+ unsigned simultaneous_running_writers=0;
+ unsigned max_simultaneous_writers=0;
+ boost::mutex unblocked_count_mutex;
+ boost::condition_variable unblocked_condition;
+ boost::mutex finish_reading_mutex;
+ boost::mutex::scoped_lock finish_reading_lock(finish_reading_mutex);
+ boost::mutex finish_writing_mutex;
+ boost::mutex::scoped_lock finish_writing_lock(finish_writing_mutex);
+
+ unsigned const reader_count=10;
+ unsigned const writer_count=10;
+
+ try
+ {
+ for(unsigned i=0;i<reader_count;++i)
+ {
+ pool.create_thread(locking_thread<boost::shared_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
+ finish_reading_mutex,simultaneous_running_readers,max_simultaneous_readers));
+ }
+ boost::thread::sleep(delay(1));
+ for(unsigned i=0;i<writer_count;++i)
+ {
+ pool.create_thread(locking_thread<boost::unique_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
+ finish_writing_mutex,simultaneous_running_writers,max_simultaneous_writers));
+ }
+ {
+ boost::mutex::scoped_lock lk(unblocked_count_mutex);
+ while(unblocked_count<reader_count)
+ {
+ unblocked_condition.wait(lk);
+ }
+ }
+ boost::thread::sleep(delay(1));
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count);
+
+ finish_reading_lock.unlock();
+
+ {
+ boost::mutex::scoped_lock lk(unblocked_count_mutex);
+ while(unblocked_count<(reader_count+1))
+ {
+ unblocked_condition.wait(lk);
+ }
+ }
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count+1);
+
+ finish_writing_lock.unlock();
+ pool.join_all();
+ }
+ catch(...)
+ {
+ pool.interrupt_all();
+ pool.join_all();
+ throw;
+ }
+
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count+writer_count);
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_readers,reader_count);
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_writers,1u);
+}
+
+boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
+{
+ boost::unit_test_framework::test_suite* test =
+ BOOST_TEST_SUITE("Boost.Threads: shared_mutex test suite");
+
+ test->add(BOOST_TEST_CASE(&test_multiple_readers));
+ test->add(BOOST_TEST_CASE(&test_only_one_writer_permitted));
+ test->add(BOOST_TEST_CASE(&test_reader_blocks_writer));
+ test->add(BOOST_TEST_CASE(&test_unlocking_writer_unblocks_all_readers));
+ test->add(BOOST_TEST_CASE(&test_unlocking_last_reader_only_unblocks_one_writer));
+
+ return test;
+}

Added: sandbox/chrono/libs/thread/test/test_shared_mutex_part_2.cpp
==============================================================================
--- (empty file)
+++ sandbox/chrono/libs/thread/test/test_shared_mutex_part_2.cpp 2010-05-20 03:55:54 EDT (Thu, 20 May 2010)
@@ -0,0 +1,290 @@
+// (C) Copyright 2006-7 Anthony Williams
+// Distributed under 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)
+
+#include <boost/test/unit_test.hpp>
+#include <boost/thread/thread.hpp>
+#include <boost/thread/xtime.hpp>
+#include "util.inl"
+#include "shared_mutex_locking_thread.hpp"
+
+#define CHECK_LOCKED_VALUE_EQUAL(mutex_name,value,expected_value) \
+ { \
+ boost::mutex::scoped_lock lock(mutex_name); \
+ BOOST_CHECK_EQUAL(value,expected_value); \
+ }
+
+class simple_upgrade_thread
+{
+ boost::shared_mutex& rwm;
+ boost::mutex& finish_mutex;
+ boost::mutex& unblocked_mutex;
+ unsigned& unblocked_count;
+
+ void operator=(simple_upgrade_thread&);
+
+public:
+ simple_upgrade_thread(boost::shared_mutex& rwm_,
+ boost::mutex& finish_mutex_,
+ boost::mutex& unblocked_mutex_,
+ unsigned& unblocked_count_):
+ rwm(rwm_),finish_mutex(finish_mutex_),
+ unblocked_mutex(unblocked_mutex_),unblocked_count(unblocked_count_)
+ {}
+
+ void operator()()
+ {
+ boost::upgrade_lock<boost::shared_mutex> lk(rwm);
+
+ {
+ boost::mutex::scoped_lock ulk(unblocked_mutex);
+ ++unblocked_count;
+ }
+
+ boost::mutex::scoped_lock flk(finish_mutex);
+ }
+};
+
+
+void test_only_one_upgrade_lock_permitted()
+{
+ unsigned const number_of_threads=10;
+
+ boost::thread_group pool;
+
+ boost::shared_mutex rw_mutex;
+ unsigned unblocked_count=0;
+ unsigned simultaneous_running_count=0;
+ unsigned max_simultaneous_running=0;
+ boost::mutex unblocked_count_mutex;
+ boost::condition_variable unblocked_condition;
+ boost::mutex finish_mutex;
+ boost::mutex::scoped_lock finish_lock(finish_mutex);
+
+ try
+ {
+ for(unsigned i=0;i<number_of_threads;++i)
+ {
+ pool.create_thread(locking_thread<boost::upgrade_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
+ finish_mutex,simultaneous_running_count,max_simultaneous_running));
+ }
+
+ boost::thread::sleep(delay(1));
+
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U);
+
+ finish_lock.unlock();
+
+ pool.join_all();
+ }
+ catch(...)
+ {
+ pool.interrupt_all();
+ pool.join_all();
+ throw;
+ }
+
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,number_of_threads);
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,1u);
+}
+
+void test_can_lock_upgrade_if_currently_locked_shared()
+{
+ boost::thread_group pool;
+
+ boost::shared_mutex rw_mutex;
+ unsigned unblocked_count=0;
+ unsigned simultaneous_running_count=0;
+ unsigned max_simultaneous_running=0;
+ boost::mutex unblocked_count_mutex;
+ boost::condition_variable unblocked_condition;
+ boost::mutex finish_mutex;
+ boost::mutex::scoped_lock finish_lock(finish_mutex);
+
+ unsigned const reader_count=10;
+
+ try
+ {
+ for(unsigned i=0;i<reader_count;++i)
+ {
+ pool.create_thread(locking_thread<boost::shared_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
+ finish_mutex,simultaneous_running_count,max_simultaneous_running));
+ }
+ boost::thread::sleep(delay(1));
+ pool.create_thread(locking_thread<boost::upgrade_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
+ finish_mutex,simultaneous_running_count,max_simultaneous_running));
+ {
+ boost::mutex::scoped_lock lk(unblocked_count_mutex);
+ while(unblocked_count<(reader_count+1))
+ {
+ unblocked_condition.wait(lk);
+ }
+ }
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count+1);
+
+ finish_lock.unlock();
+ pool.join_all();
+ }
+ catch(...)
+ {
+ pool.interrupt_all();
+ pool.join_all();
+ throw;
+ }
+
+
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count+1);
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,reader_count+1);
+}
+
+void test_if_other_thread_has_write_lock_try_lock_shared_returns_false()
+{
+
+ boost::shared_mutex rw_mutex;
+ boost::mutex finish_mutex;
+ boost::mutex unblocked_mutex;
+ unsigned unblocked_count=0;
+ boost::mutex::scoped_lock finish_lock(finish_mutex);
+ boost::thread writer(simple_writing_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
+ boost::this_thread::sleep(boost::posix_time::seconds(1));
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
+
+ bool const try_succeeded=rw_mutex.try_lock_shared();
+ BOOST_CHECK(!try_succeeded);
+ if(try_succeeded)
+ {
+ rw_mutex.unlock_shared();
+ }
+
+ finish_lock.unlock();
+ writer.join();
+}
+
+void test_if_other_thread_has_write_lock_try_lock_upgrade_returns_false()
+{
+
+ boost::shared_mutex rw_mutex;
+ boost::mutex finish_mutex;
+ boost::mutex unblocked_mutex;
+ unsigned unblocked_count=0;
+ boost::mutex::scoped_lock finish_lock(finish_mutex);
+ boost::thread writer(simple_writing_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
+ boost::this_thread::sleep(boost::posix_time::seconds(1));
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
+
+ bool const try_succeeded=rw_mutex.try_lock_upgrade();
+ BOOST_CHECK(!try_succeeded);
+ if(try_succeeded)
+ {
+ rw_mutex.unlock_upgrade();
+ }
+
+ finish_lock.unlock();
+ writer.join();
+}
+
+void test_if_no_thread_has_lock_try_lock_shared_returns_true()
+{
+ boost::shared_mutex rw_mutex;
+ bool const try_succeeded=rw_mutex.try_lock_shared();
+ BOOST_CHECK(try_succeeded);
+ if(try_succeeded)
+ {
+ rw_mutex.unlock_shared();
+ }
+}
+
+void test_if_no_thread_has_lock_try_lock_upgrade_returns_true()
+{
+ boost::shared_mutex rw_mutex;
+ bool const try_succeeded=rw_mutex.try_lock_upgrade();
+ BOOST_CHECK(try_succeeded);
+ if(try_succeeded)
+ {
+ rw_mutex.unlock_upgrade();
+ }
+}
+
+void test_if_other_thread_has_shared_lock_try_lock_shared_returns_true()
+{
+
+ boost::shared_mutex rw_mutex;
+ boost::mutex finish_mutex;
+ boost::mutex unblocked_mutex;
+ unsigned unblocked_count=0;
+ boost::mutex::scoped_lock finish_lock(finish_mutex);
+ boost::thread writer(simple_reading_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
+ boost::thread::sleep(delay(1));
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
+
+ bool const try_succeeded=rw_mutex.try_lock_shared();
+ BOOST_CHECK(try_succeeded);
+ if(try_succeeded)
+ {
+ rw_mutex.unlock_shared();
+ }
+
+ finish_lock.unlock();
+ writer.join();
+}
+
+void test_if_other_thread_has_shared_lock_try_lock_upgrade_returns_true()
+{
+
+ boost::shared_mutex rw_mutex;
+ boost::mutex finish_mutex;
+ boost::mutex unblocked_mutex;
+ unsigned unblocked_count=0;
+ boost::mutex::scoped_lock finish_lock(finish_mutex);
+ boost::thread writer(simple_reading_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
+ boost::thread::sleep(delay(1));
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
+
+ bool const try_succeeded=rw_mutex.try_lock_upgrade();
+ BOOST_CHECK(try_succeeded);
+ if(try_succeeded)
+ {
+ rw_mutex.unlock_upgrade();
+ }
+
+ finish_lock.unlock();
+ writer.join();
+}
+
+void test_if_other_thread_has_upgrade_lock_try_lock_upgrade_returns_false()
+{
+
+ boost::shared_mutex rw_mutex;
+ boost::mutex finish_mutex;
+ boost::mutex unblocked_mutex;
+ unsigned unblocked_count=0;
+ boost::mutex::scoped_lock finish_lock(finish_mutex);
+ boost::thread writer(simple_upgrade_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
+ boost::this_thread::sleep(boost::posix_time::seconds(1));
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
+
+ bool const try_succeeded=rw_mutex.try_lock_upgrade();
+ BOOST_CHECK(!try_succeeded);
+ if(try_succeeded)
+ {
+ rw_mutex.unlock_upgrade();
+ }
+
+ finish_lock.unlock();
+ writer.join();
+}
+
+boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
+{
+ boost::unit_test_framework::test_suite* test =
+ BOOST_TEST_SUITE("Boost.Threads: shared_mutex test suite");
+
+ test->add(BOOST_TEST_CASE(&test_only_one_upgrade_lock_permitted));
+ test->add(BOOST_TEST_CASE(&test_can_lock_upgrade_if_currently_locked_shared));
+ test->add(BOOST_TEST_CASE(&test_if_other_thread_has_write_lock_try_lock_shared_returns_false));
+ test->add(BOOST_TEST_CASE(&test_if_no_thread_has_lock_try_lock_shared_returns_true));
+ test->add(BOOST_TEST_CASE(&test_if_other_thread_has_shared_lock_try_lock_shared_returns_true));
+
+ return test;
+}

Added: sandbox/chrono/libs/thread/test/test_shared_mutex_timed_locks.cpp
==============================================================================
--- (empty file)
+++ sandbox/chrono/libs/thread/test/test_shared_mutex_timed_locks.cpp 2010-05-20 03:55:54 EDT (Thu, 20 May 2010)
@@ -0,0 +1,268 @@
+// (C) Copyright 2006-7 Anthony Williams
+// Distributed under 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)
+
+#include <boost/test/unit_test.hpp>
+#include <boost/thread/thread.hpp>
+#include <boost/thread/xtime.hpp>
+#include "util.inl"
+#include "shared_mutex_locking_thread.hpp"
+
+#define CHECK_LOCKED_VALUE_EQUAL(mutex_name,value,expected_value) \
+ { \
+ boost::mutex::scoped_lock lock(mutex_name); \
+ BOOST_CHECK_EQUAL(value,expected_value); \
+ }
+
+
+void test_timed_lock_shared_times_out_if_write_lock_held()
+{
+ boost::shared_mutex rw_mutex;
+ boost::mutex finish_mutex;
+ boost::mutex unblocked_mutex;
+ unsigned unblocked_count=0;
+ boost::mutex::scoped_lock finish_lock(finish_mutex);
+ boost::thread writer(simple_writing_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
+ boost::thread::sleep(delay(1));
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
+
+ boost::system_time const start=boost::get_system_time();
+ boost::system_time const timeout=start+boost::posix_time::milliseconds(500);
+ boost::posix_time::milliseconds const timeout_resolution(50);
+ bool timed_lock_succeeded=rw_mutex.timed_lock_shared(timeout);
+ BOOST_CHECK((timeout-timeout_resolution)<boost::get_system_time());
+ BOOST_CHECK(!timed_lock_succeeded);
+ if(timed_lock_succeeded)
+ {
+ rw_mutex.unlock_shared();
+ }
+
+ boost::posix_time::milliseconds const wait_duration(500);
+ boost::system_time const timeout2=boost::get_system_time()+wait_duration;
+ timed_lock_succeeded=rw_mutex.timed_lock_shared(wait_duration);
+ BOOST_CHECK((timeout2-timeout_resolution)<boost::get_system_time());
+ BOOST_CHECK(!timed_lock_succeeded);
+ if(timed_lock_succeeded)
+ {
+ rw_mutex.unlock_shared();
+ }
+
+ finish_lock.unlock();
+ writer.join();
+}
+
+void test_timed_lock_shared_succeeds_if_no_lock_held()
+{
+ boost::shared_mutex rw_mutex;
+ boost::mutex finish_mutex;
+ boost::mutex unblocked_mutex;
+
+ boost::system_time const start=boost::get_system_time();
+ boost::system_time const timeout=start+boost::posix_time::milliseconds(500);
+ boost::posix_time::milliseconds const timeout_resolution(50);
+ bool timed_lock_succeeded=rw_mutex.timed_lock_shared(timeout);
+ BOOST_CHECK(boost::get_system_time()<timeout);
+ BOOST_CHECK(timed_lock_succeeded);
+ if(timed_lock_succeeded)
+ {
+ rw_mutex.unlock_shared();
+ }
+
+ boost::posix_time::milliseconds const wait_duration(500);
+ boost::system_time const timeout2=boost::get_system_time()+wait_duration;
+ timed_lock_succeeded=rw_mutex.timed_lock_shared(wait_duration);
+ BOOST_CHECK(boost::get_system_time()<timeout2);
+ BOOST_CHECK(timed_lock_succeeded);
+ if(timed_lock_succeeded)
+ {
+ rw_mutex.unlock_shared();
+ }
+
+}
+
+void test_timed_lock_shared_succeeds_if_read_lock_held()
+{
+ boost::shared_mutex rw_mutex;
+ boost::mutex finish_mutex;
+ boost::mutex unblocked_mutex;
+ unsigned unblocked_count=0;
+ boost::mutex::scoped_lock finish_lock(finish_mutex);
+ boost::thread reader(simple_reading_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
+ boost::thread::sleep(delay(1));
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
+
+ boost::system_time const start=boost::get_system_time();
+ boost::system_time const timeout=start+boost::posix_time::milliseconds(500);
+ boost::posix_time::milliseconds const timeout_resolution(50);
+ bool timed_lock_succeeded=rw_mutex.timed_lock_shared(timeout);
+ BOOST_CHECK(boost::get_system_time()<timeout);
+ BOOST_CHECK(timed_lock_succeeded);
+ if(timed_lock_succeeded)
+ {
+ rw_mutex.unlock_shared();
+ }
+
+ boost::posix_time::milliseconds const wait_duration(500);
+ boost::system_time const timeout2=boost::get_system_time()+wait_duration;
+ timed_lock_succeeded=rw_mutex.timed_lock_shared(wait_duration);
+ BOOST_CHECK(boost::get_system_time()<timeout2);
+ BOOST_CHECK(timed_lock_succeeded);
+ if(timed_lock_succeeded)
+ {
+ rw_mutex.unlock_shared();
+ }
+
+ finish_lock.unlock();
+ reader.join();
+}
+
+void test_timed_lock_times_out_if_write_lock_held()
+{
+ boost::shared_mutex rw_mutex;
+ boost::mutex finish_mutex;
+ boost::mutex unblocked_mutex;
+ unsigned unblocked_count=0;
+ boost::mutex::scoped_lock finish_lock(finish_mutex);
+ boost::thread writer(simple_writing_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
+ boost::thread::sleep(delay(1));
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
+
+ boost::system_time const start=boost::get_system_time();
+ boost::system_time const timeout=start+boost::posix_time::milliseconds(500);
+ boost::posix_time::milliseconds const timeout_resolution(50);
+ bool timed_lock_succeeded=rw_mutex.timed_lock(timeout);
+ BOOST_CHECK((timeout-timeout_resolution)<boost::get_system_time());
+ BOOST_CHECK(!timed_lock_succeeded);
+ if(timed_lock_succeeded)
+ {
+ rw_mutex.unlock();
+ }
+
+ boost::posix_time::milliseconds const wait_duration(500);
+ boost::system_time const timeout2=boost::get_system_time()+wait_duration;
+ timed_lock_succeeded=rw_mutex.timed_lock(wait_duration);
+ BOOST_CHECK((timeout2-timeout_resolution)<boost::get_system_time());
+ BOOST_CHECK(!timed_lock_succeeded);
+ if(timed_lock_succeeded)
+ {
+ rw_mutex.unlock();
+ }
+
+ finish_lock.unlock();
+ writer.join();
+}
+
+void test_timed_lock_succeeds_if_no_lock_held()
+{
+ boost::shared_mutex rw_mutex;
+ boost::mutex finish_mutex;
+ boost::mutex unblocked_mutex;
+
+ boost::system_time const start=boost::get_system_time();
+ boost::system_time const timeout=start+boost::posix_time::milliseconds(500);
+ boost::posix_time::milliseconds const timeout_resolution(50);
+ bool timed_lock_succeeded=rw_mutex.timed_lock(timeout);
+ BOOST_CHECK(boost::get_system_time()<timeout);
+ BOOST_CHECK(timed_lock_succeeded);
+ if(timed_lock_succeeded)
+ {
+ rw_mutex.unlock();
+ }
+
+ boost::posix_time::milliseconds const wait_duration(500);
+ boost::system_time const timeout2=boost::get_system_time()+wait_duration;
+ timed_lock_succeeded=rw_mutex.timed_lock(wait_duration);
+ BOOST_CHECK(boost::get_system_time()<timeout2);
+ BOOST_CHECK(timed_lock_succeeded);
+ if(timed_lock_succeeded)
+ {
+ rw_mutex.unlock();
+ }
+
+}
+
+void test_timed_lock_times_out_if_read_lock_held()
+{
+ boost::shared_mutex rw_mutex;
+ boost::mutex finish_mutex;
+ boost::mutex unblocked_mutex;
+ unsigned unblocked_count=0;
+ boost::mutex::scoped_lock finish_lock(finish_mutex);
+ boost::thread reader(simple_reading_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
+ boost::thread::sleep(delay(1));
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
+
+ boost::system_time const start=boost::get_system_time();
+ boost::system_time const timeout=start+boost::posix_time::milliseconds(500);
+ boost::posix_time::milliseconds const timeout_resolution(50);
+ bool timed_lock_succeeded=rw_mutex.timed_lock(timeout);
+ BOOST_CHECK((timeout-timeout_resolution)<boost::get_system_time());
+ BOOST_CHECK(!timed_lock_succeeded);
+ if(timed_lock_succeeded)
+ {
+ rw_mutex.unlock();
+ }
+
+ boost::posix_time::milliseconds const wait_duration(500);
+ boost::system_time const timeout2=boost::get_system_time()+wait_duration;
+ timed_lock_succeeded=rw_mutex.timed_lock(wait_duration);
+ BOOST_CHECK((timeout2-timeout_resolution)<boost::get_system_time());
+ BOOST_CHECK(!timed_lock_succeeded);
+ if(timed_lock_succeeded)
+ {
+ rw_mutex.unlock();
+ }
+
+ finish_lock.unlock();
+ reader.join();
+}
+
+void test_timed_lock_times_out_but_read_lock_succeeds_if_read_lock_held()
+{
+ boost::shared_mutex rw_mutex;
+ boost::mutex finish_mutex;
+ boost::mutex unblocked_mutex;
+ unsigned unblocked_count=0;
+ boost::mutex::scoped_lock finish_lock(finish_mutex);
+ boost::thread reader(simple_reading_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
+ boost::this_thread::sleep(boost::posix_time::seconds(1));
+ CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
+
+ boost::system_time const start=boost::get_system_time();
+ boost::system_time const timeout=start+boost::posix_time::milliseconds(500);
+ bool timed_lock_succeeded=rw_mutex.timed_lock(timeout);
+ BOOST_CHECK(!timed_lock_succeeded);
+ if(timed_lock_succeeded)
+ {
+ rw_mutex.unlock();
+ }
+
+ boost::posix_time::milliseconds const wait_duration(500);
+ timed_lock_succeeded=rw_mutex.timed_lock_shared(wait_duration);
+ BOOST_CHECK(timed_lock_succeeded);
+ if(timed_lock_succeeded)
+ {
+ rw_mutex.unlock_shared();
+ }
+
+ finish_lock.unlock();
+ reader.join();
+}
+
+
+boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
+{
+ boost::unit_test_framework::test_suite* test =
+ BOOST_TEST_SUITE("Boost.Threads: shared_mutex test suite");
+
+ test->add(BOOST_TEST_CASE(&test_timed_lock_shared_times_out_if_write_lock_held));
+ test->add(BOOST_TEST_CASE(&test_timed_lock_shared_succeeds_if_no_lock_held));
+ test->add(BOOST_TEST_CASE(&test_timed_lock_shared_succeeds_if_read_lock_held));
+ test->add(BOOST_TEST_CASE(&test_timed_lock_times_out_if_write_lock_held));
+ test->add(BOOST_TEST_CASE(&test_timed_lock_times_out_if_read_lock_held));
+ test->add(BOOST_TEST_CASE(&test_timed_lock_succeeds_if_no_lock_held));
+ test->add(BOOST_TEST_CASE(&test_timed_lock_times_out_but_read_lock_succeeds_if_read_lock_held));
+
+ return test;
+}

Added: sandbox/chrono/libs/thread/test/test_thread.cpp
==============================================================================
--- (empty file)
+++ sandbox/chrono/libs/thread/test/test_thread.cpp 2010-05-20 03:55:54 EDT (Thu, 20 May 2010)
@@ -0,0 +1,234 @@
+// Copyright (C) 2001-2003
+// William E. Kempf
+// Copyright (C) 2008 Anthony Williams
+//
+// Distributed under 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)
+
+#include <boost/thread/detail/config.hpp>
+
+#include <boost/thread/thread.hpp>
+#include <boost/thread/xtime.hpp>
+#include <boost/bind.hpp>
+#include <boost/ref.hpp>
+#include <boost/utility.hpp>
+
+#include <boost/test/unit_test.hpp>
+
+#define DEFAULT_EXECUTION_MONITOR_TYPE execution_monitor::use_sleep_only
+#include <libs/thread/test/util.inl>
+
+int test_value;
+
+void simple_thread()
+{
+ test_value = 999;
+}
+
+void comparison_thread(boost::thread::id parent)
+{
+ boost::thread::id const my_id=boost::this_thread::get_id();
+
+ BOOST_CHECK(my_id != parent);
+ boost::thread::id const my_id2=boost::this_thread::get_id();
+ BOOST_CHECK(my_id == my_id2);
+
+ boost::thread::id const no_thread_id=boost::thread::id();
+ BOOST_CHECK(my_id != no_thread_id);
+}
+
+void test_sleep()
+{
+ boost::xtime xt = delay(3);
+ boost::thread::sleep(xt);
+
+ // Ensure it's in a range instead of checking actual equality due to time
+ // lapse
+ BOOST_CHECK(in_range(xt, 2));
+}
+
+void do_test_creation()
+{
+ test_value = 0;
+ boost::thread thrd(&simple_thread);
+ thrd.join();
+ BOOST_CHECK_EQUAL(test_value, 999);
+}
+
+void test_creation()
+{
+ timed_test(&do_test_creation, 1);
+}
+
+void do_test_id_comparison()
+{
+ boost::thread::id const self=boost::this_thread::get_id();
+ boost::thread thrd(boost::bind(&comparison_thread, self));
+ thrd.join();
+}
+
+void test_id_comparison()
+{
+ timed_test(&do_test_id_comparison, 1);
+}
+
+void interruption_point_thread(boost::mutex* m,bool* failed)
+{
+ boost::mutex::scoped_lock lk(*m);
+ boost::this_thread::interruption_point();
+ *failed=true;
+}
+
+void do_test_thread_interrupts_at_interruption_point()
+{
+ boost::mutex m;
+ bool failed=false;
+ boost::mutex::scoped_lock lk(m);
+ boost::thread thrd(boost::bind(&interruption_point_thread,&m,&failed));
+ thrd.interrupt();
+ lk.unlock();
+ thrd.join();
+ BOOST_CHECK(!failed);
+}
+
+void test_thread_interrupts_at_interruption_point()
+{
+ timed_test(&do_test_thread_interrupts_at_interruption_point, 1);
+}
+
+void disabled_interruption_point_thread(boost::mutex* m,bool* failed)
+{
+ boost::mutex::scoped_lock lk(*m);
+ boost::this_thread::disable_interruption dc;
+ boost::this_thread::interruption_point();
+ *failed=false;
+}
+
+void do_test_thread_no_interrupt_if_interrupts_disabled_at_interruption_point()
+{
+ boost::mutex m;
+ bool failed=true;
+ boost::mutex::scoped_lock lk(m);
+ boost::thread thrd(boost::bind(&disabled_interruption_point_thread,&m,&failed));
+ thrd.interrupt();
+ lk.unlock();
+ thrd.join();
+ BOOST_CHECK(!failed);
+}
+
+void test_thread_no_interrupt_if_interrupts_disabled_at_interruption_point()
+{
+ timed_test(&do_test_thread_no_interrupt_if_interrupts_disabled_at_interruption_point, 1);
+}
+
+struct non_copyable_functor:
+ boost::noncopyable
+{
+ unsigned value;
+
+ non_copyable_functor():
+ value(0)
+ {}
+
+ void operator()()
+ {
+ value=999;
+ }
+};
+
+void do_test_creation_through_reference_wrapper()
+{
+ non_copyable_functor f;
+
+ boost::thread thrd(boost::ref(f));
+ thrd.join();
+ BOOST_CHECK_EQUAL(f.value, 999u);
+}
+
+void test_creation_through_reference_wrapper()
+{
+ timed_test(&do_test_creation_through_reference_wrapper, 1);
+}
+
+struct long_running_thread
+{
+ boost::condition_variable cond;
+ boost::mutex mut;
+ bool done;
+
+ long_running_thread():
+ done(false)
+ {}
+
+ void operator()()
+ {
+ boost::mutex::scoped_lock lk(mut);
+ while(!done)
+ {
+ cond.wait(lk);
+ }
+ }
+};
+
+void do_test_timed_join()
+{
+ long_running_thread f;
+ boost::thread thrd(boost::ref(f));
+ BOOST_CHECK(thrd.joinable());
+ boost::system_time xt=delay(3);
+ bool const joined=thrd.timed_join(xt);
+ BOOST_CHECK(in_range(boost::get_xtime(xt), 2));
+ BOOST_CHECK(!joined);
+ BOOST_CHECK(thrd.joinable());
+ {
+ boost::mutex::scoped_lock lk(f.mut);
+ f.done=true;
+ f.cond.notify_one();
+ }
+
+ xt=delay(3);
+ bool const joined2=thrd.timed_join(xt);
+ boost::system_time const now=boost::get_system_time();
+ BOOST_CHECK(xt>now);
+ BOOST_CHECK(joined2);
+ BOOST_CHECK(!thrd.joinable());
+}
+
+void test_timed_join()
+{
+ timed_test(&do_test_timed_join, 10);
+}
+
+void test_swap()
+{
+ boost::thread t(simple_thread);
+ boost::thread t2(simple_thread);
+ boost::thread::id id1=t.get_id();
+ boost::thread::id id2=t2.get_id();
+
+ t.swap(t2);
+ BOOST_CHECK(t.get_id()==id2);
+ BOOST_CHECK(t2.get_id()==id1);
+
+ swap(t,t2);
+ BOOST_CHECK(t.get_id()==id1);
+ BOOST_CHECK(t2.get_id()==id2);
+}
+
+
+boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
+{
+ boost::unit_test_framework::test_suite* test =
+ BOOST_TEST_SUITE("Boost.Threads: thread test suite");
+
+ test->add(BOOST_TEST_CASE(test_sleep));
+ test->add(BOOST_TEST_CASE(test_creation));
+ test->add(BOOST_TEST_CASE(test_id_comparison));
+ test->add(BOOST_TEST_CASE(test_thread_interrupts_at_interruption_point));
+ test->add(BOOST_TEST_CASE(test_thread_no_interrupt_if_interrupts_disabled_at_interruption_point));
+ test->add(BOOST_TEST_CASE(test_creation_through_reference_wrapper));
+ test->add(BOOST_TEST_CASE(test_timed_join));
+ test->add(BOOST_TEST_CASE(test_swap));
+
+ return test;
+}

Added: sandbox/chrono/libs/thread/test/test_thread_exit.cpp
==============================================================================
--- (empty file)
+++ sandbox/chrono/libs/thread/test/test_thread_exit.cpp 2010-05-20 03:55:54 EDT (Thu, 20 May 2010)
@@ -0,0 +1,73 @@
+// (C) Copyright 2009 Anthony Williams
+//
+// Distributed under 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)
+
+#include "boost/thread/thread.hpp"
+#include "boost/thread/mutex.hpp"
+#include "boost/thread/condition.hpp"
+#include "boost/thread/future.hpp"
+#include <utility>
+#include <memory>
+#include <string>
+
+#include <boost/test/unit_test.hpp>
+
+boost::thread::id exit_func_thread_id;
+
+void exit_func()
+{
+ exit_func_thread_id=boost::this_thread::get_id();
+}
+
+void tf1()
+{
+ boost::this_thread::at_thread_exit(exit_func);
+ BOOST_CHECK(exit_func_thread_id!=boost::this_thread::get_id());
+}
+
+void test_thread_exit_func_runs_when_thread_exits()
+{
+ exit_func_thread_id=boost::thread::id();
+ boost::thread t(tf1);
+ boost::thread::id const t_id=t.get_id();
+ t.join();
+ BOOST_CHECK(exit_func_thread_id==t_id);
+}
+
+struct fo
+{
+ void operator()()
+ {
+ exit_func_thread_id=boost::this_thread::get_id();
+ }
+};
+
+void tf2()
+{
+ boost::this_thread::at_thread_exit(fo());
+ BOOST_CHECK(exit_func_thread_id!=boost::this_thread::get_id());
+}
+
+
+void test_can_use_function_object_for_exit_func()
+{
+ exit_func_thread_id=boost::thread::id();
+ boost::thread t(tf2);
+ boost::thread::id const t_id=t.get_id();
+ t.join();
+ BOOST_CHECK(exit_func_thread_id==t_id);
+}
+
+
+boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
+{
+ boost::unit_test_framework::test_suite* test =
+ BOOST_TEST_SUITE("Boost.Threads: futures test suite");
+
+ test->add(BOOST_TEST_CASE(test_thread_exit_func_runs_when_thread_exits));
+ test->add(BOOST_TEST_CASE(test_can_use_function_object_for_exit_func));
+
+ return test;
+}

Added: sandbox/chrono/libs/thread/test/test_thread_id.cpp
==============================================================================
--- (empty file)
+++ sandbox/chrono/libs/thread/test/test_thread_id.cpp 2010-05-20 03:55:54 EDT (Thu, 20 May 2010)
@@ -0,0 +1,149 @@
+// Copyright (C) 2007 Anthony Williams
+//
+// Distributed under 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)
+#include <boost/thread/thread.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/bind.hpp>
+
+void do_nothing()
+{}
+
+void test_thread_id_for_default_constructed_thread_is_default_constructed_id()
+{
+ boost::thread t;
+ BOOST_CHECK(t.get_id()==boost::thread::id());
+}
+
+void test_thread_id_for_running_thread_is_not_default_constructed_id()
+{
+ boost::thread t(do_nothing);
+ BOOST_CHECK(t.get_id()!=boost::thread::id());
+ t.join();
+}
+
+void test_different_threads_have_different_ids()
+{
+ boost::thread t(do_nothing);
+ boost::thread t2(do_nothing);
+ BOOST_CHECK(t.get_id()!=t2.get_id());
+ t.join();
+ t2.join();
+}
+
+void test_thread_ids_have_a_total_order()
+{
+ boost::thread t(do_nothing);
+ boost::thread t2(do_nothing);
+ boost::thread t3(do_nothing);
+ BOOST_CHECK(t.get_id()!=t2.get_id());
+ BOOST_CHECK(t.get_id()!=t3.get_id());
+ BOOST_CHECK(t2.get_id()!=t3.get_id());
+
+ BOOST_CHECK((t.get_id()<t2.get_id()) != (t2.get_id()<t.get_id()));
+ BOOST_CHECK((t.get_id()<t3.get_id()) != (t3.get_id()<t.get_id()));
+ BOOST_CHECK((t2.get_id()<t3.get_id()) != (t3.get_id()<t2.get_id()));
+
+ BOOST_CHECK((t.get_id()>t2.get_id()) != (t2.get_id()>t.get_id()));
+ BOOST_CHECK((t.get_id()>t3.get_id()) != (t3.get_id()>t.get_id()));
+ BOOST_CHECK((t2.get_id()>t3.get_id()) != (t3.get_id()>t2.get_id()));
+
+ BOOST_CHECK((t.get_id()<t2.get_id()) == (t2.get_id()>t.get_id()));
+ BOOST_CHECK((t2.get_id()<t.get_id()) == (t.get_id()>t2.get_id()));
+ BOOST_CHECK((t.get_id()<t3.get_id()) == (t3.get_id()>t.get_id()));
+ BOOST_CHECK((t3.get_id()<t.get_id()) == (t.get_id()>t3.get_id()));
+ BOOST_CHECK((t2.get_id()<t3.get_id()) == (t3.get_id()>t2.get_id()));
+ BOOST_CHECK((t3.get_id()<t2.get_id()) == (t2.get_id()>t3.get_id()));
+
+ BOOST_CHECK((t.get_id()<t2.get_id()) == (t2.get_id()>=t.get_id()));
+ BOOST_CHECK((t2.get_id()<t.get_id()) == (t.get_id()>=t2.get_id()));
+ BOOST_CHECK((t.get_id()<t3.get_id()) == (t3.get_id()>=t.get_id()));
+ BOOST_CHECK((t3.get_id()<t.get_id()) == (t.get_id()>=t3.get_id()));
+ BOOST_CHECK((t2.get_id()<t3.get_id()) == (t3.get_id()>=t2.get_id()));
+ BOOST_CHECK((t3.get_id()<t2.get_id()) == (t2.get_id()>=t3.get_id()));
+
+ BOOST_CHECK((t.get_id()<=t2.get_id()) == (t2.get_id()>t.get_id()));
+ BOOST_CHECK((t2.get_id()<=t.get_id()) == (t.get_id()>t2.get_id()));
+ BOOST_CHECK((t.get_id()<=t3.get_id()) == (t3.get_id()>t.get_id()));
+ BOOST_CHECK((t3.get_id()<=t.get_id()) == (t.get_id()>t3.get_id()));
+ BOOST_CHECK((t2.get_id()<=t3.get_id()) == (t3.get_id()>t2.get_id()));
+ BOOST_CHECK((t3.get_id()<=t2.get_id()) == (t2.get_id()>t3.get_id()));
+
+ if((t.get_id()<t2.get_id()) && (t2.get_id()<t3.get_id()))
+ {
+ BOOST_CHECK(t.get_id()<t3.get_id());
+ }
+ else if((t.get_id()<t3.get_id()) && (t3.get_id()<t2.get_id()))
+ {
+ BOOST_CHECK(t.get_id()<t2.get_id());
+ }
+ else if((t2.get_id()<t3.get_id()) && (t3.get_id()<t.get_id()))
+ {
+ BOOST_CHECK(t2.get_id()<t.get_id());
+ }
+ else if((t2.get_id()<t.get_id()) && (t.get_id()<t3.get_id()))
+ {
+ BOOST_CHECK(t2.get_id()<t3.get_id());
+ }
+ else if((t3.get_id()<t.get_id()) && (t.get_id()<t2.get_id()))
+ {
+ BOOST_CHECK(t3.get_id()<t2.get_id());
+ }
+ else if((t3.get_id()<t2.get_id()) && (t2.get_id()<t.get_id()))
+ {
+ BOOST_CHECK(t3.get_id()<t.get_id());
+ }
+ else
+ {
+ BOOST_CHECK(false);
+ }
+
+ boost::thread::id default_id;
+
+ BOOST_CHECK(default_id < t.get_id());
+ BOOST_CHECK(default_id < t2.get_id());
+ BOOST_CHECK(default_id < t3.get_id());
+
+ BOOST_CHECK(default_id <= t.get_id());
+ BOOST_CHECK(default_id <= t2.get_id());
+ BOOST_CHECK(default_id <= t3.get_id());
+
+ BOOST_CHECK(!(default_id > t.get_id()));
+ BOOST_CHECK(!(default_id > t2.get_id()));
+ BOOST_CHECK(!(default_id > t3.get_id()));
+
+ BOOST_CHECK(!(default_id >= t.get_id()));
+ BOOST_CHECK(!(default_id >= t2.get_id()));
+ BOOST_CHECK(!(default_id >= t3.get_id()));
+
+ t.join();
+ t2.join();
+ t3.join();
+}
+
+void get_thread_id(boost::thread::id* id)
+{
+ *id=boost::this_thread::get_id();
+}
+
+void test_thread_id_of_running_thread_returned_by_this_thread_get_id()
+{
+ boost::thread::id id;
+ boost::thread t(boost::bind(get_thread_id,&id));
+ boost::thread::id t_id=t.get_id();
+ t.join();
+ BOOST_CHECK(id==t_id);
+}
+
+boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
+{
+ boost::unit_test_framework::test_suite* test =
+ BOOST_TEST_SUITE("Boost.Threads: thread move test suite");
+
+ test->add(BOOST_TEST_CASE(test_thread_id_for_default_constructed_thread_is_default_constructed_id));
+ test->add(BOOST_TEST_CASE(test_thread_id_for_running_thread_is_not_default_constructed_id));
+ test->add(BOOST_TEST_CASE(test_different_threads_have_different_ids));
+ test->add(BOOST_TEST_CASE(test_thread_ids_have_a_total_order));
+ test->add(BOOST_TEST_CASE(test_thread_id_of_running_thread_returned_by_this_thread_get_id));
+ return test;
+}

Added: sandbox/chrono/libs/thread/test/test_thread_launching.cpp
==============================================================================
--- (empty file)
+++ sandbox/chrono/libs/thread/test/test_thread_launching.cpp 2010-05-20 03:55:54 EDT (Thu, 20 May 2010)
@@ -0,0 +1,226 @@
+// Copyright (C) 2007-8 Anthony Williams
+//
+// Distributed under 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)
+#include <boost/thread/thread.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/ref.hpp>
+#include <boost/utility.hpp>
+#include <string>
+#include <vector>
+
+bool normal_function_called=false;
+
+void normal_function()
+{
+ normal_function_called=true;
+}
+
+void test_thread_function_no_arguments()
+{
+ boost::thread function(normal_function);
+ function.join();
+ BOOST_CHECK(normal_function_called);
+}
+
+int nfoa_res=0;
+
+void normal_function_one_arg(int i)
+{
+ nfoa_res=i;
+}
+
+void test_thread_function_one_argument()
+{
+ boost::thread function(normal_function_one_arg,42);
+ function.join();
+ BOOST_CHECK_EQUAL(42,nfoa_res);
+}
+
+struct callable_no_args
+{
+ static bool called;
+
+ void operator()() const
+ {
+ called=true;
+ }
+};
+
+bool callable_no_args::called=false;
+
+void test_thread_callable_object_no_arguments()
+{
+ callable_no_args func;
+ boost::thread callable(func);
+ callable.join();
+ BOOST_CHECK(callable_no_args::called);
+}
+
+struct callable_noncopyable_no_args:
+ boost::noncopyable
+{
+ static bool called;
+
+ void operator()() const
+ {
+ called=true;
+ }
+};
+
+bool callable_noncopyable_no_args::called=false;
+
+void test_thread_callable_object_ref_no_arguments()
+{
+ callable_noncopyable_no_args func;
+
+ boost::thread callable(boost::ref(func));
+ callable.join();
+ BOOST_CHECK(callable_noncopyable_no_args::called);
+}
+
+struct callable_one_arg
+{
+ static bool called;
+ static int called_arg;
+
+ void operator()(int arg) const
+ {
+ called=true;
+ called_arg=arg;
+ }
+};
+
+bool callable_one_arg::called=false;
+int callable_one_arg::called_arg=0;
+
+void test_thread_callable_object_one_argument()
+{
+ callable_one_arg func;
+ boost::thread callable(func,42);
+ callable.join();
+ BOOST_CHECK(callable_one_arg::called);
+ BOOST_CHECK_EQUAL(callable_one_arg::called_arg,42);
+}
+
+struct callable_multiple_arg
+{
+ static bool called_two;
+ static int called_two_arg1;
+ static double called_two_arg2;
+ static bool called_three;
+ static std::string called_three_arg1;
+ static std::vector<int> called_three_arg2;
+ static int called_three_arg3;
+
+ void operator()(int arg1,double arg2) const
+ {
+ called_two=true;
+ called_two_arg1=arg1;
+ called_two_arg2=arg2;
+ }
+ void operator()(std::string const& arg1,std::vector<int> const& arg2,int arg3) const
+ {
+ called_three=true;
+ called_three_arg1=arg1;
+ called_three_arg2=arg2;
+ called_three_arg3=arg3;
+ }
+};
+
+bool callable_multiple_arg::called_two=false;
+bool callable_multiple_arg::called_three=false;
+int callable_multiple_arg::called_two_arg1;
+double callable_multiple_arg::called_two_arg2;
+std::string callable_multiple_arg::called_three_arg1;
+std::vector<int> callable_multiple_arg::called_three_arg2;
+int callable_multiple_arg::called_three_arg3;
+
+void test_thread_callable_object_multiple_arguments()
+{
+ std::vector<int> x;
+ for(unsigned i=0;i<7;++i)
+ {
+ x.push_back(i*i);
+ }
+
+ callable_multiple_arg func;
+
+ boost::thread callable3(func,"hello",x,1.2);
+ callable3.join();
+ BOOST_CHECK(callable_multiple_arg::called_three);
+ BOOST_CHECK_EQUAL(callable_multiple_arg::called_three_arg1,"hello");
+ BOOST_CHECK_EQUAL(callable_multiple_arg::called_three_arg2.size(),x.size());
+ for(unsigned j=0;j<x.size();++j)
+ {
+ BOOST_CHECK_EQUAL(callable_multiple_arg::called_three_arg2.at(j),x[j]);
+ }
+
+ BOOST_CHECK_EQUAL(callable_multiple_arg::called_three_arg3,1);
+
+ double const dbl=1.234;
+
+ boost::thread callable2(func,19,dbl);
+ callable2.join();
+ BOOST_CHECK(callable_multiple_arg::called_two);
+ BOOST_CHECK_EQUAL(callable_multiple_arg::called_two_arg1,19);
+ BOOST_CHECK_EQUAL(callable_multiple_arg::called_two_arg2,dbl);
+}
+
+struct X
+{
+ bool function_called;
+ int arg_value;
+
+ X():
+ function_called(false),
+ arg_value(0)
+ {}
+
+
+ void f0()
+ {
+ function_called=true;
+ }
+
+ void f1(int i)
+ {
+ arg_value=i;
+ }
+
+};
+
+void test_thread_member_function_no_arguments()
+{
+ X x;
+
+ boost::thread function(&X::f0,&x);
+ function.join();
+ BOOST_CHECK(x.function_called);
+}
+
+
+void test_thread_member_function_one_argument()
+{
+ X x;
+ boost::thread function(&X::f1,&x,42);
+ function.join();
+ BOOST_CHECK_EQUAL(42,x.arg_value);
+}
+
+
+boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
+{
+ boost::unit_test_framework::test_suite* test =
+ BOOST_TEST_SUITE("Boost.Threads: thread launching test suite");
+
+ test->add(BOOST_TEST_CASE(test_thread_function_no_arguments));
+ test->add(BOOST_TEST_CASE(test_thread_function_one_argument));
+ test->add(BOOST_TEST_CASE(test_thread_callable_object_no_arguments));
+ test->add(BOOST_TEST_CASE(test_thread_callable_object_ref_no_arguments));
+ test->add(BOOST_TEST_CASE(test_thread_callable_object_one_argument));
+ test->add(BOOST_TEST_CASE(test_thread_callable_object_multiple_arguments));
+ test->add(BOOST_TEST_CASE(test_thread_member_function_no_arguments));
+ test->add(BOOST_TEST_CASE(test_thread_member_function_one_argument));
+ return test;
+}

Added: sandbox/chrono/libs/thread/test/test_thread_mf.cpp
==============================================================================
--- (empty file)
+++ sandbox/chrono/libs/thread/test/test_thread_mf.cpp 2010-05-20 03:55:54 EDT (Thu, 20 May 2010)
@@ -0,0 +1,134 @@
+//
+// Copyright (C) 2008 Peter Dimov
+//
+// Distributed under 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
+//
+
+#include <boost/thread/thread.hpp>
+#include <boost/detail/lightweight_test.hpp>
+
+struct X
+{
+ mutable unsigned int hash;
+
+ X(): hash(0) {}
+
+ int f0() { f1(17); return 0; }
+ int g0() const { g1(17); return 0; }
+
+ int f1(int a1) { hash = (hash * 17041 + a1) % 32768; return 0; }
+ int g1(int a1) const { hash = (hash * 17041 + a1 * 2) % 32768; return 0; }
+
+ int f2(int a1, int a2) { f1(a1); f1(a2); return 0; }
+ int g2(int a1, int a2) const { g1(a1); g1(a2); return 0; }
+
+ int f3(int a1, int a2, int a3) { f2(a1, a2); f1(a3); return 0; }
+ int g3(int a1, int a2, int a3) const { g2(a1, a2); g1(a3); return 0; }
+
+ int f4(int a1, int a2, int a3, int a4) { f3(a1, a2, a3); f1(a4); return 0; }
+ int g4(int a1, int a2, int a3, int a4) const { g3(a1, a2, a3); g1(a4); return 0; }
+
+ int f5(int a1, int a2, int a3, int a4, int a5) { f4(a1, a2, a3, a4); f1(a5); return 0; }
+ int g5(int a1, int a2, int a3, int a4, int a5) const { g4(a1, a2, a3, a4); g1(a5); return 0; }
+
+ int f6(int a1, int a2, int a3, int a4, int a5, int a6) { f5(a1, a2, a3, a4, a5); f1(a6); return 0; }
+ int g6(int a1, int a2, int a3, int a4, int a5, int a6) const { g5(a1, a2, a3, a4, a5); g1(a6); return 0; }
+
+ int f7(int a1, int a2, int a3, int a4, int a5, int a6, int a7) { f6(a1, a2, a3, a4, a5, a6); f1(a7); return 0; }
+ int g7(int a1, int a2, int a3, int a4, int a5, int a6, int a7) const { g6(a1, a2, a3, a4, a5, a6); g1(a7); return 0; }
+
+ int f8(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8) { f7(a1, a2, a3, a4, a5, a6, a7); f1(a8); return 0; }
+ int g8(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8) const { g7(a1, a2, a3, a4, a5, a6, a7); g1(a8); return 0; }
+};
+
+int main()
+{
+ X x;
+
+ // 0
+
+ boost::thread( &X::f0, &x ).join();
+ boost::thread( &X::f0, boost::ref(x) ).join();
+
+ boost::thread( &X::g0, &x ).join();
+ boost::thread( &X::g0, x ).join();
+ boost::thread( &X::g0, boost::ref(x) ).join();
+
+ // 1
+
+ boost::thread( &X::f1, &x, 1 ).join();
+ boost::thread( &X::f1, boost::ref(x), 1 ).join();
+
+ boost::thread( &X::g1, &x, 1 ).join();
+ boost::thread( &X::g1, x, 1 ).join();
+ boost::thread( &X::g1, boost::ref(x), 1 ).join();
+
+ // 2
+
+ boost::thread( &X::f2, &x, 1, 2 ).join();
+ boost::thread( &X::f2, boost::ref(x), 1, 2 ).join();
+
+ boost::thread( &X::g2, &x, 1, 2 ).join();
+ boost::thread( &X::g2, x, 1, 2 ).join();
+ boost::thread( &X::g2, boost::ref(x), 1, 2 ).join();
+
+ // 3
+
+ boost::thread( &X::f3, &x, 1, 2, 3 ).join();
+ boost::thread( &X::f3, boost::ref(x), 1, 2, 3 ).join();
+
+ boost::thread( &X::g3, &x, 1, 2, 3 ).join();
+ boost::thread( &X::g3, x, 1, 2, 3 ).join();
+ boost::thread( &X::g3, boost::ref(x), 1, 2, 3 ).join();
+
+ // 4
+
+ boost::thread( &X::f4, &x, 1, 2, 3, 4 ).join();
+ boost::thread( &X::f4, boost::ref(x), 1, 2, 3, 4 ).join();
+
+ boost::thread( &X::g4, &x, 1, 2, 3, 4 ).join();
+ boost::thread( &X::g4, x, 1, 2, 3, 4 ).join();
+ boost::thread( &X::g4, boost::ref(x), 1, 2, 3, 4 ).join();
+
+ // 5
+
+ boost::thread( &X::f5, &x, 1, 2, 3, 4, 5 ).join();
+ boost::thread( &X::f5, boost::ref(x), 1, 2, 3, 4, 5 ).join();
+
+ boost::thread( &X::g5, &x, 1, 2, 3, 4, 5 ).join();
+ boost::thread( &X::g5, x, 1, 2, 3, 4, 5 ).join();
+ boost::thread( &X::g5, boost::ref(x), 1, 2, 3, 4, 5 ).join();
+
+ // 6
+
+ boost::thread( &X::f6, &x, 1, 2, 3, 4, 5, 6 ).join();
+ boost::thread( &X::f6, boost::ref(x), 1, 2, 3, 4, 5, 6 ).join();
+
+ boost::thread( &X::g6, &x, 1, 2, 3, 4, 5, 6 ).join();
+ boost::thread( &X::g6, x, 1, 2, 3, 4, 5, 6 ).join();
+ boost::thread( &X::g6, boost::ref(x), 1, 2, 3, 4, 5, 6 ).join();
+
+ // 7
+
+ boost::thread( &X::f7, &x, 1, 2, 3, 4, 5, 6, 7).join();
+ boost::thread( &X::f7, boost::ref(x), 1, 2, 3, 4, 5, 6, 7).join();
+
+ boost::thread( &X::g7, &x, 1, 2, 3, 4, 5, 6, 7).join();
+ boost::thread( &X::g7, x, 1, 2, 3, 4, 5, 6, 7).join();
+ boost::thread( &X::g7, boost::ref(x), 1, 2, 3, 4, 5, 6, 7).join();
+
+ // 8
+
+ boost::thread( &X::f8, &x, 1, 2, 3, 4, 5, 6, 7, 8 ).join();
+ boost::thread( &X::f8, boost::ref(x), 1, 2, 3, 4, 5, 6, 7, 8 ).join();
+
+ boost::thread( &X::g8, &x, 1, 2, 3, 4, 5, 6, 7, 8 ).join();
+ boost::thread( &X::g8, x, 1, 2, 3, 4, 5, 6, 7, 8 ).join();
+ boost::thread( &X::g8, boost::ref(x), 1, 2, 3, 4, 5, 6, 7, 8 ).join();
+
+ BOOST_TEST( x.hash == 23558 );
+
+ return boost::report_errors();
+}

Added: sandbox/chrono/libs/thread/test/test_thread_move.cpp
==============================================================================
--- (empty file)
+++ sandbox/chrono/libs/thread/test/test_thread_move.cpp 2010-05-20 03:55:54 EDT (Thu, 20 May 2010)
@@ -0,0 +1,56 @@
+// Copyright (C) 2007-9 Anthony Williams
+//
+// Distributed under 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)
+#include <boost/thread/thread.hpp>
+#include <boost/test/unit_test.hpp>
+
+void do_nothing(boost::thread::id* my_id)
+{
+ *my_id=boost::this_thread::get_id();
+}
+
+void test_move_on_construction()
+{
+ boost::thread::id the_id;
+ boost::thread x=boost::thread(do_nothing,&the_id);
+ boost::thread::id x_id=x.get_id();
+ x.join();
+ BOOST_CHECK_EQUAL(the_id,x_id);
+}
+
+boost::thread make_thread(boost::thread::id* the_id)
+{
+ return boost::thread(do_nothing,the_id);
+}
+
+void test_move_from_function_return()
+{
+ boost::thread::id the_id;
+ boost::thread x=make_thread(&the_id);
+ boost::thread::id x_id=x.get_id();
+ x.join();
+ BOOST_CHECK_EQUAL(the_id,x_id);
+}
+
+void test_move_assign()
+{
+ boost::thread::id the_id;
+ boost::thread x(do_nothing,&the_id);
+ boost::thread y;
+ y=boost::move(x);
+ boost::thread::id y_id=y.get_id();
+ y.join();
+ BOOST_CHECK_EQUAL(the_id,y_id);
+}
+
+boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
+{
+ boost::unit_test_framework::test_suite* test =
+ BOOST_TEST_SUITE("Boost.Threads: thread move test suite");
+
+ test->add(BOOST_TEST_CASE(test_move_on_construction));
+ test->add(BOOST_TEST_CASE(test_move_from_function_return));
+ test->add(BOOST_TEST_CASE(test_move_assign));
+ return test;
+}

Added: sandbox/chrono/libs/thread/test/test_thread_move_return.cpp
==============================================================================
--- (empty file)
+++ sandbox/chrono/libs/thread/test/test_thread_move_return.cpp 2010-05-20 03:55:54 EDT (Thu, 20 May 2010)
@@ -0,0 +1,35 @@
+// Copyright (C) 2009 Anthony Williams
+//
+// Distributed under 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)
+#include <boost/thread/thread.hpp>
+#include <boost/test/unit_test.hpp>
+
+void do_nothing(boost::thread::id* my_id)
+{
+ *my_id=boost::this_thread::get_id();
+}
+
+boost::thread make_thread_move_return(boost::thread::id* the_id)
+{
+ boost::thread t(do_nothing,the_id);
+ return boost::move(t);
+}
+
+void test_move_from_function_move_return()
+{
+ boost::thread::id the_id;
+ boost::thread x=make_thread_move_return(&the_id);
+ boost::thread::id x_id=x.get_id();
+ x.join();
+ BOOST_CHECK_EQUAL(the_id,x_id);
+}
+
+boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
+{
+ boost::unit_test_framework::test_suite* test =
+ BOOST_TEST_SUITE("Boost.Threads: thread move test suite");
+
+ test->add(BOOST_TEST_CASE(test_move_from_function_move_return));
+ return test;
+}

Added: sandbox/chrono/libs/thread/test/test_thread_return_local.cpp
==============================================================================
--- (empty file)
+++ sandbox/chrono/libs/thread/test/test_thread_return_local.cpp 2010-05-20 03:55:54 EDT (Thu, 20 May 2010)
@@ -0,0 +1,35 @@
+// Copyright (C) 2009 Anthony Williams
+//
+// Distributed under 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)
+#include <boost/thread/thread.hpp>
+#include <boost/test/unit_test.hpp>
+
+void do_nothing(boost::thread::id* my_id)
+{
+ *my_id=boost::this_thread::get_id();
+}
+
+boost::thread make_thread_return_local(boost::thread::id* the_id)
+{
+ boost::thread t(do_nothing,the_id);
+ return t;
+}
+
+void test_move_from_function_return_local()
+{
+ boost::thread::id the_id;
+ boost::thread x=make_thread_return_local(&the_id);
+ boost::thread::id x_id=x.get_id();
+ x.join();
+ BOOST_CHECK_EQUAL(the_id,x_id);
+}
+
+boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
+{
+ boost::unit_test_framework::test_suite* test =
+ BOOST_TEST_SUITE("Boost.Threads: thread move test suite");
+
+ test->add(BOOST_TEST_CASE(test_move_from_function_return_local));
+ return test;
+}

Added: sandbox/chrono/libs/thread/test/test_tss.cpp
==============================================================================
--- (empty file)
+++ sandbox/chrono/libs/thread/test/test_tss.cpp 2010-05-20 03:55:54 EDT (Thu, 20 May 2010)
@@ -0,0 +1,359 @@
+// Copyright (C) 2001-2003
+// William E. Kempf
+// Copyright (C) 2007 Anthony Williams
+//
+// Distributed under 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)
+
+#include <boost/thread/detail/config.hpp>
+
+#include <boost/thread/tss.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/thread.hpp>
+
+#include <boost/test/unit_test.hpp>
+
+#include <libs/thread/test/util.inl>
+
+#include <iostream>
+
+#if defined(BOOST_HAS_WINTHREADS)
+ #define WIN32_LEAN_AND_MEAN
+ #include <windows.h>
+#endif
+
+boost::mutex check_mutex;
+boost::mutex tss_mutex;
+int tss_instances = 0;
+int tss_total = 0;
+
+struct tss_value_t
+{
+ tss_value_t()
+ {
+ boost::mutex::scoped_lock lock(tss_mutex);
+ ++tss_instances;
+ ++tss_total;
+ value = 0;
+ }
+ ~tss_value_t()
+ {
+ boost::mutex::scoped_lock lock(tss_mutex);
+ --tss_instances;
+ }
+ int value;
+};
+
+boost::thread_specific_ptr<tss_value_t> tss_value;
+
+void test_tss_thread()
+{
+ tss_value.reset(new tss_value_t());
+ for (int i=0; i<1000; ++i)
+ {
+ int& n = tss_value->value;
+ // Don't call BOOST_CHECK_EQUAL directly, as it doesn't appear to
+ // be thread safe. Must evaluate further.
+ if (n != i)
+ {
+ boost::mutex::scoped_lock lock(check_mutex);
+ BOOST_CHECK_EQUAL(n, i);
+ }
+ ++n;
+ }
+}
+
+#if defined(BOOST_THREAD_PLATFORM_WIN32)
+ typedef HANDLE native_thread_t;
+
+ DWORD WINAPI test_tss_thread_native(LPVOID /*lpParameter*/)
+ {
+ test_tss_thread();
+ return 0;
+ }
+
+ native_thread_t create_native_thread(void)
+ {
+ native_thread_t const res=CreateThread(
+ 0, //security attributes (0 = not inheritable)
+ 0, //stack size (0 = default)
+ &test_tss_thread_native, //function to execute
+ 0, //parameter to pass to function
+ 0, //creation flags (0 = run immediately)
+ 0 //thread id (0 = thread id not returned)
+ );
+ BOOST_CHECK(res!=0);
+ return res;
+ }
+
+ void join_native_thread(native_thread_t thread)
+ {
+ DWORD res = WaitForSingleObject(thread, INFINITE);
+ BOOST_CHECK(res == WAIT_OBJECT_0);
+
+ res = CloseHandle(thread);
+ BOOST_CHECK(SUCCEEDED(res));
+ }
+#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
+ typedef pthread_t native_thread_t;
+
+extern "C"
+{
+ void* test_tss_thread_native(void* lpParameter)
+ {
+ test_tss_thread();
+ return 0;
+ }
+}
+
+ native_thread_t create_native_thread()
+ {
+ native_thread_t thread_handle;
+
+ int const res = pthread_create(&thread_handle, 0, &test_tss_thread_native, 0);
+ BOOST_CHECK(!res);
+ return thread_handle;
+ }
+
+ void join_native_thread(native_thread_t thread)
+ {
+ void* result=0;
+ int const res=pthread_join(thread,&result);
+ BOOST_CHECK(!res);
+ }
+#endif
+
+void do_test_tss()
+{
+ tss_instances = 0;
+ tss_total = 0;
+
+ const int NUMTHREADS=5;
+ boost::thread_group threads;
+ try
+ {
+ for (int i=0; i<NUMTHREADS; ++i)
+ threads.create_thread(&test_tss_thread);
+ threads.join_all();
+ }
+ catch(...)
+ {
+ threads.interrupt_all();
+ threads.join_all();
+ throw;
+ }
+
+
+ std::cout
+ << "tss_instances = " << tss_instances
+ << "; tss_total = " << tss_total
+ << "\n";
+ std::cout.flush();
+
+ BOOST_CHECK_EQUAL(tss_instances, 0);
+ BOOST_CHECK_EQUAL(tss_total, 5);
+
+ tss_instances = 0;
+ tss_total = 0;
+
+ native_thread_t thread1 = create_native_thread();
+ native_thread_t thread2 = create_native_thread();
+ native_thread_t thread3 = create_native_thread();
+ native_thread_t thread4 = create_native_thread();
+ native_thread_t thread5 = create_native_thread();
+
+ join_native_thread(thread5);
+ join_native_thread(thread4);
+ join_native_thread(thread3);
+ join_native_thread(thread2);
+ join_native_thread(thread1);
+
+ std::cout
+ << "tss_instances = " << tss_instances
+ << "; tss_total = " << tss_total
+ << "\n";
+ std::cout.flush();
+
+ // The following is not really an error. TSS cleanup support still is available for boost threads.
+ // Also this usually will be triggered only when bound to the static version of thread lib.
+ // 2006-10-02 Roland Schwarz
+ //BOOST_CHECK_EQUAL(tss_instances, 0);
+ BOOST_CHECK_MESSAGE(tss_instances == 0, "Support of automatic tss cleanup for native threading API not available");
+ BOOST_CHECK_EQUAL(tss_total, 5);
+}
+
+void test_tss()
+{
+ timed_test(&do_test_tss, 2);
+}
+
+bool tss_cleanup_called=false;
+
+struct Dummy
+{};
+
+void tss_custom_cleanup(Dummy* d)
+{
+ delete d;
+ tss_cleanup_called=true;
+}
+
+boost::thread_specific_ptr<Dummy> tss_with_cleanup(tss_custom_cleanup);
+
+void tss_thread_with_custom_cleanup()
+{
+ tss_with_cleanup.reset(new Dummy);
+}
+
+void do_test_tss_with_custom_cleanup()
+{
+ boost::thread t(tss_thread_with_custom_cleanup);
+ try
+ {
+ t.join();
+ }
+ catch(...)
+ {
+ t.interrupt();
+ t.join();
+ throw;
+ }
+
+ BOOST_CHECK(tss_cleanup_called);
+}
+
+
+void test_tss_with_custom_cleanup()
+{
+ timed_test(&do_test_tss_with_custom_cleanup, 2);
+}
+
+Dummy* tss_object=new Dummy;
+
+void tss_thread_with_custom_cleanup_and_release()
+{
+ tss_with_cleanup.reset(tss_object);
+ tss_with_cleanup.release();
+}
+
+void do_test_tss_does_no_cleanup_after_release()
+{
+ tss_cleanup_called=false;
+ boost::thread t(tss_thread_with_custom_cleanup_and_release);
+ try
+ {
+ t.join();
+ }
+ catch(...)
+ {
+ t.interrupt();
+ t.join();
+ throw;
+ }
+
+ BOOST_CHECK(!tss_cleanup_called);
+ if(!tss_cleanup_called)
+ {
+ delete tss_object;
+ }
+}
+
+struct dummy_class_tracks_deletions
+{
+ static unsigned deletions;
+
+ ~dummy_class_tracks_deletions()
+ {
+ ++deletions;
+ }
+
+};
+
+unsigned dummy_class_tracks_deletions::deletions=0;
+
+boost::thread_specific_ptr<dummy_class_tracks_deletions> tss_with_null_cleanup(NULL);
+
+void tss_thread_with_null_cleanup(dummy_class_tracks_deletions* delete_tracker)
+{
+ tss_with_null_cleanup.reset(delete_tracker);
+}
+
+void do_test_tss_does_no_cleanup_with_null_cleanup_function()
+{
+ dummy_class_tracks_deletions* delete_tracker=new dummy_class_tracks_deletions;
+ boost::thread t(tss_thread_with_null_cleanup,delete_tracker);
+ try
+ {
+ t.join();
+ }
+ catch(...)
+ {
+ t.interrupt();
+ t.join();
+ throw;
+ }
+
+ BOOST_CHECK(!dummy_class_tracks_deletions::deletions);
+ if(!dummy_class_tracks_deletions::deletions)
+ {
+ delete delete_tracker;
+ }
+}
+
+void test_tss_does_no_cleanup_after_release()
+{
+ timed_test(&do_test_tss_does_no_cleanup_after_release, 2);
+}
+
+void test_tss_does_no_cleanup_with_null_cleanup_function()
+{
+ timed_test(&do_test_tss_does_no_cleanup_with_null_cleanup_function, 2);
+}
+
+void thread_with_local_tss_ptr()
+{
+ {
+ boost::thread_specific_ptr<Dummy> local_tss(tss_custom_cleanup);
+
+ local_tss.reset(new Dummy);
+ }
+ BOOST_CHECK(tss_cleanup_called);
+ tss_cleanup_called=false;
+}
+
+
+void test_tss_does_not_call_cleanup_after_ptr_destroyed()
+{
+ boost::thread t(thread_with_local_tss_ptr);
+ t.join();
+ BOOST_CHECK(!tss_cleanup_called);
+}
+
+void test_tss_cleanup_not_called_for_null_pointer()
+{
+ boost::thread_specific_ptr<Dummy> local_tss(tss_custom_cleanup);
+ local_tss.reset(new Dummy);
+ tss_cleanup_called=false;
+ local_tss.reset(0);
+ BOOST_CHECK(tss_cleanup_called);
+ tss_cleanup_called=false;
+ local_tss.reset(new Dummy);
+ BOOST_CHECK(!tss_cleanup_called);
+}
+
+
+
+boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
+{
+ boost::unit_test_framework::test_suite* test =
+ BOOST_TEST_SUITE("Boost.Threads: tss test suite");
+
+ test->add(BOOST_TEST_CASE(test_tss));
+ test->add(BOOST_TEST_CASE(test_tss_with_custom_cleanup));
+ test->add(BOOST_TEST_CASE(test_tss_does_no_cleanup_after_release));
+ test->add(BOOST_TEST_CASE(test_tss_does_no_cleanup_with_null_cleanup_function));
+ test->add(BOOST_TEST_CASE(test_tss_does_not_call_cleanup_after_ptr_destroyed));
+ test->add(BOOST_TEST_CASE(test_tss_cleanup_not_called_for_null_pointer));
+
+ return test;
+}

Added: sandbox/chrono/libs/thread/test/test_xtime.cpp
==============================================================================
--- (empty file)
+++ sandbox/chrono/libs/thread/test/test_xtime.cpp 2010-05-20 03:55:54 EDT (Thu, 20 May 2010)
@@ -0,0 +1,109 @@
+// Copyright (C) 2001-2003
+// William E. Kempf
+// Copyright (C) 2008 Anthony Williams
+//
+// Distributed under 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)
+
+#include <boost/thread/detail/config.hpp>
+
+#include <boost/thread/xtime.hpp>
+
+#include <boost/test/unit_test.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/condition.hpp>
+
+void test_xtime_cmp()
+{
+ boost::xtime xt1, xt2, cur;
+ BOOST_CHECK_EQUAL(
+ boost::xtime_get(&cur, boost::TIME_UTC),
+ static_cast<int>(boost::TIME_UTC));
+
+ xt1 = xt2 = cur;
+ xt1.nsec -= 1;
+ xt2.nsec += 1;
+
+ BOOST_CHECK(boost::xtime_cmp(xt1, cur) < 0);
+ BOOST_CHECK(boost::xtime_cmp(xt2, cur) > 0);
+ BOOST_CHECK(boost::xtime_cmp(cur, cur) == 0);
+
+ xt1 = xt2 = cur;
+ xt1.sec -= 1;
+ xt2.sec += 1;
+
+ BOOST_CHECK(boost::xtime_cmp(xt1, cur) < 0);
+ BOOST_CHECK(boost::xtime_cmp(xt2, cur) > 0);
+ BOOST_CHECK(boost::xtime_cmp(cur, cur) == 0);
+}
+
+void test_xtime_get()
+{
+ boost::xtime orig, cur, old;
+ BOOST_CHECK_EQUAL(
+ boost::xtime_get(&orig,
+ boost::TIME_UTC), static_cast<int>(boost::TIME_UTC));
+ old = orig;
+
+ for (int x=0; x < 100; ++x)
+ {
+ BOOST_CHECK_EQUAL(
+ boost::xtime_get(&cur, boost::TIME_UTC),
+ static_cast<int>(boost::TIME_UTC));
+ BOOST_CHECK(boost::xtime_cmp(cur, orig) >= 0);
+ BOOST_CHECK(boost::xtime_cmp(cur, old) >= 0);
+ old = cur;
+ }
+}
+
+void test_xtime_mutex_backwards_compatibility()
+{
+ boost::timed_mutex m;
+ BOOST_CHECK(m.timed_lock(boost::get_xtime(boost::get_system_time()+boost::posix_time::milliseconds(10))));
+ m.unlock();
+ boost::timed_mutex::scoped_timed_lock lk(m,boost::get_xtime(boost::get_system_time()+boost::posix_time::milliseconds(10)));
+ BOOST_CHECK(lk.owns_lock());
+ if(lk.owns_lock())
+ {
+ lk.unlock();
+ }
+ BOOST_CHECK(lk.timed_lock(boost::get_xtime(boost::get_system_time()+boost::posix_time::milliseconds(10))));
+ if(lk.owns_lock())
+ {
+ lk.unlock();
+ }
+}
+
+bool predicate()
+{
+ return false;
+}
+
+
+void test_xtime_condvar_backwards_compatibility()
+{
+ boost::condition_variable cond;
+ boost::condition_variable_any cond_any;
+ boost::mutex m;
+
+ boost::mutex::scoped_lock lk(m);
+ cond.timed_wait(lk,boost::get_xtime(boost::get_system_time()+boost::posix_time::milliseconds(10)));
+ cond.timed_wait(lk,boost::get_xtime(boost::get_system_time()+boost::posix_time::milliseconds(10)),predicate);
+ cond_any.timed_wait(lk,boost::get_xtime(boost::get_system_time()+boost::posix_time::milliseconds(10)));
+ cond_any.timed_wait(lk,boost::get_xtime(boost::get_system_time()+boost::posix_time::milliseconds(10)),predicate);
+}
+
+
+
+boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
+{
+ boost::unit_test_framework::test_suite* test =
+ BOOST_TEST_SUITE("Boost.Threads: xtime test suite");
+
+ test->add(BOOST_TEST_CASE(&test_xtime_cmp));
+ test->add(BOOST_TEST_CASE(&test_xtime_get));
+ test->add(BOOST_TEST_CASE(&test_xtime_mutex_backwards_compatibility));
+ test->add(BOOST_TEST_CASE(&test_xtime_condvar_backwards_compatibility));
+
+ return test;
+}

Added: sandbox/chrono/libs/thread/test/util.inl
==============================================================================
--- (empty file)
+++ sandbox/chrono/libs/thread/test/util.inl 2010-05-20 03:55:54 EDT (Thu, 20 May 2010)
@@ -0,0 +1,183 @@
+// Copyright (C) 2001-2003
+// William E. Kempf
+// Copyright (C) 2007-8 Anthony Williams
+//
+// Distributed under 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)
+
+#if !defined(UTIL_INL_WEK01242003)
+#define UTIL_INL_WEK01242003
+
+#include <boost/thread/xtime.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/condition.hpp>
+#include <boost/thread/thread.hpp>
+
+#ifndef DEFAULT_EXECUTION_MONITOR_TYPE
+# define DEFAULT_EXECUTION_MONITOR_TYPE execution_monitor::use_condition
+#endif
+
+// boostinspect:nounnamed
+
+namespace
+{
+inline boost::xtime delay(int secs, int msecs=0, int nsecs=0)
+{
+ const int MILLISECONDS_PER_SECOND = 1000;
+ const int NANOSECONDS_PER_SECOND = 1000000000;
+ const int NANOSECONDS_PER_MILLISECOND = 1000000;
+
+ boost::xtime xt;
+ if (boost::TIME_UTC != boost::xtime_get (&xt, boost::TIME_UTC))
+ BOOST_ERROR ("boost::xtime_get != boost::TIME_UTC");
+
+ nsecs += xt.nsec;
+ msecs += nsecs / NANOSECONDS_PER_MILLISECOND;
+ secs += msecs / MILLISECONDS_PER_SECOND;
+ nsecs += (msecs % MILLISECONDS_PER_SECOND) * NANOSECONDS_PER_MILLISECOND;
+ xt.nsec = nsecs % NANOSECONDS_PER_SECOND;
+ xt.sec += secs + (nsecs / NANOSECONDS_PER_SECOND);
+
+ return xt;
+}
+
+inline bool in_range(const boost::xtime& xt, int secs=1)
+{
+ boost::xtime min = delay(-secs);
+ boost::xtime max = delay(0);
+ return (boost::xtime_cmp(xt, min) >= 0) &&
+ (boost::xtime_cmp(xt, max) <= 0);
+}
+
+class execution_monitor
+{
+public:
+ enum wait_type { use_sleep_only, use_mutex, use_condition };
+
+ execution_monitor(wait_type type, int secs)
+ : done(false), type(type), secs(secs) { }
+ void start()
+ {
+ if (type != use_sleep_only) {
+ boost::mutex::scoped_lock lock(mutex); done = false;
+ } else {
+ done = false;
+ }
+ }
+ void finish()
+ {
+ if (type != use_sleep_only) {
+ boost::mutex::scoped_lock lock(mutex);
+ done = true;
+ if (type == use_condition)
+ cond.notify_one();
+ } else {
+ done = true;
+ }
+ }
+ bool wait()
+ {
+ boost::xtime xt = delay(secs);
+ if (type != use_condition)
+ boost::thread::sleep(xt);
+ if (type != use_sleep_only) {
+ boost::mutex::scoped_lock lock(mutex);
+ while (type == use_condition && !done) {
+ if (!cond.timed_wait(lock, xt))
+ break;
+ }
+ return done;
+ }
+ return done;
+ }
+
+private:
+ boost::mutex mutex;
+ boost::condition cond;
+ bool done;
+ wait_type type;
+ int secs;
+};
+
+template <typename F>
+class indirect_adapter
+{
+public:
+ indirect_adapter(F func, execution_monitor& monitor)
+ : func(func), monitor(monitor) { }
+ void operator()() const
+ {
+ try
+ {
+ boost::thread thrd(func);
+ thrd.join();
+ }
+ catch (...)
+ {
+ monitor.finish();
+ throw;
+ }
+ monitor.finish();
+ }
+
+private:
+ F func;
+ execution_monitor& monitor;
+ void operator=(indirect_adapter&);
+};
+
+template <typename F>
+void timed_test(F func, int secs,
+ execution_monitor::wait_type type=DEFAULT_EXECUTION_MONITOR_TYPE)
+{
+ execution_monitor monitor(type, secs);
+ indirect_adapter<F> ifunc(func, monitor);
+ monitor.start();
+ boost::thread thrd(ifunc);
+ BOOST_REQUIRE_MESSAGE(monitor.wait(),
+ "Timed test didn't complete in time, possible deadlock.");
+}
+
+template <typename F, typename T>
+class thread_binder
+{
+public:
+ thread_binder(const F& func, const T& param)
+ : func(func), param(param) { }
+ void operator()() const { func(param); }
+
+private:
+ F func;
+ T param;
+};
+
+template <typename F, typename T>
+thread_binder<F, T> bind(const F& func, const T& param)
+{
+ return thread_binder<F, T>(func, param);
+}
+
+template <typename R, typename T>
+class thread_member_binder
+{
+public:
+ thread_member_binder(R (T::*func)(), T& param)
+ : func(func), param(param) { }
+ void operator()() const { (param.*func)(); }
+
+private:
+ void operator=(thread_member_binder&);
+
+ R (T::*func)();
+ T& param;
+};
+
+
+template <typename R, typename T>
+thread_member_binder<R, T> bind(R (T::*func)(), T& param)
+{
+ return thread_member_binder<R, T>(func, param);
+}
+} // namespace
+
+#endif


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk