summaryrefslogtreecommitdiffstats
path: root/src/boost/libs/smart_ptr/extras
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 18:45:59 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 18:45:59 +0000
commit19fcec84d8d7d21e796c7624e521b60d28ee21ed (patch)
tree42d26aa27d1e3f7c0b8bd3fd14e7d7082f5008dc /src/boost/libs/smart_ptr/extras
parentInitial commit. (diff)
downloadceph-6d07fdb6bb33b1af39833b850bb6cf8af79fe293.tar.xz
ceph-6d07fdb6bb33b1af39833b850bb6cf8af79fe293.zip
Adding upstream version 16.2.11+ds.upstream/16.2.11+dsupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/boost/libs/smart_ptr/extras')
-rw-r--r--src/boost/libs/smart_ptr/extras/src/sp_collector.cpp270
-rw-r--r--src/boost/libs/smart_ptr/extras/src/sp_debug_hooks.cpp243
-rw-r--r--src/boost/libs/smart_ptr/extras/test/shared_ptr_mt_test.cpp82
-rw-r--r--src/boost/libs/smart_ptr/extras/test/shared_ptr_timing_test.cpp46
-rw-r--r--src/boost/libs/smart_ptr/extras/test/sp_atomic_mt2_test.cpp247
-rw-r--r--src/boost/libs/smart_ptr/extras/test/sp_atomic_mt_test.cpp191
-rw-r--r--src/boost/libs/smart_ptr/extras/test/weak_ptr_mt_test.cpp122
-rw-r--r--src/boost/libs/smart_ptr/extras/test/weak_ptr_timing_test.cpp85
8 files changed, 1286 insertions, 0 deletions
diff --git a/src/boost/libs/smart_ptr/extras/src/sp_collector.cpp b/src/boost/libs/smart_ptr/extras/src/sp_collector.cpp
new file mode 100644
index 000000000..bb69ae88b
--- /dev/null
+++ b/src/boost/libs/smart_ptr/extras/src/sp_collector.cpp
@@ -0,0 +1,270 @@
+//
+// sp_collector.cpp
+//
+// Copyright (c) 2002, 2003 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)
+//
+
+#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
+
+#include <boost/assert.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/detail/lightweight_mutex.hpp>
+#include <cstdlib>
+#include <map>
+#include <deque>
+#include <iostream>
+
+typedef std::map< void const *, std::pair<void *, size_t> > map_type;
+
+static map_type & get_map()
+{
+ static map_type m;
+ return m;
+}
+
+typedef boost::detail::lightweight_mutex mutex_type;
+
+static mutex_type & get_mutex()
+{
+ static mutex_type m;
+ return m;
+}
+
+static void * init_mutex_before_main = &get_mutex();
+
+namespace
+{
+ class X;
+
+ struct count_layout
+ {
+ boost::detail::sp_counted_base * pi;
+ int id;
+ };
+
+ struct shared_ptr_layout
+ {
+ X * px;
+ count_layout pn;
+ };
+}
+
+// assume 4 byte alignment for pointers when scanning
+size_t const pointer_align = 4;
+
+typedef std::map<void const *, long> map2_type;
+
+static void scan_and_count(void const * area, size_t size, map_type const & m, map2_type & m2)
+{
+ unsigned char const * p = static_cast<unsigned char const *>(area);
+
+ for(size_t n = 0; n + sizeof(shared_ptr_layout) <= size; p += pointer_align, n += pointer_align)
+ {
+ shared_ptr_layout const * q = reinterpret_cast<shared_ptr_layout const *>(p);
+
+ if(q->pn.id == boost::detail::shared_count_id && q->pn.pi != 0 && m.count(q->pn.pi) != 0)
+ {
+ ++m2[q->pn.pi];
+ }
+ }
+}
+
+typedef std::deque<void const *> open_type;
+
+static void scan_and_mark(void const * area, size_t size, map2_type & m2, open_type & open)
+{
+ unsigned char const * p = static_cast<unsigned char const *>(area);
+
+ for(size_t n = 0; n + sizeof(shared_ptr_layout) <= size; p += pointer_align, n += pointer_align)
+ {
+ shared_ptr_layout const * q = reinterpret_cast<shared_ptr_layout const *>(p);
+
+ if(q->pn.id == boost::detail::shared_count_id && q->pn.pi != 0 && m2.count(q->pn.pi) != 0)
+ {
+ open.push_back(q->pn.pi);
+ m2.erase(q->pn.pi);
+ }
+ }
+}
+
+static void find_unreachable_objects_impl(map_type const & m, map2_type & m2)
+{
+ // scan objects for shared_ptr members, compute internal counts
+
+ {
+ std::cout << "... " << m.size() << " objects in m.\n";
+
+ for(map_type::const_iterator i = m.begin(); i != m.end(); ++i)
+ {
+ boost::detail::sp_counted_base const * p = static_cast<boost::detail::sp_counted_base const *>(i->first);
+
+ BOOST_ASSERT(p->use_count() != 0); // there should be no inactive counts in the map
+
+ m2[ i->first ];
+
+ scan_and_count(i->second.first, i->second.second, m, m2);
+ }
+
+ std::cout << "... " << m2.size() << " objects in m2.\n";
+ }
+
+ // mark reachable objects
+
+ {
+ open_type open;
+
+ for(map2_type::iterator i = m2.begin(); i != m2.end(); ++i)
+ {
+ boost::detail::sp_counted_base const * p = static_cast<boost::detail::sp_counted_base const *>(i->first);
+ if(p->use_count() != i->second) open.push_back(p);
+ }
+
+ std::cout << "... " << open.size() << " objects in open.\n";
+
+ for(open_type::iterator j = open.begin(); j != open.end(); ++j)
+ {
+ m2.erase(*j);
+ }
+
+ while(!open.empty())
+ {
+ void const * p = open.front();
+ open.pop_front();
+
+ map_type::const_iterator i = m.find(p);
+ BOOST_ASSERT(i != m.end());
+
+ scan_and_mark(i->second.first, i->second.second, m2, open);
+ }
+ }
+
+ // m2 now contains the unreachable objects
+}
+
+std::size_t find_unreachable_objects(bool report)
+{
+ map2_type m2;
+
+#ifdef BOOST_HAS_THREADS
+
+ // This will work without the #ifdef, but some compilers warn
+ // that lock is not referenced
+
+ mutex_type::scoped_lock lock(get_mutex());
+
+#endif
+
+ map_type const & m = get_map();
+
+ find_unreachable_objects_impl(m, m2);
+
+ if(report)
+ {
+ for(map2_type::iterator j = m2.begin(); j != m2.end(); ++j)
+ {
+ map_type::const_iterator i = m.find(j->first);
+ BOOST_ASSERT(i != m.end());
+ std::cout << "Unreachable object at " << i->second.first << ", " << i->second.second << " bytes long.\n";
+ }
+ }
+
+ return m2.size();
+}
+
+typedef std::deque< boost::shared_ptr<X> > free_list_type;
+
+static void scan_and_free(void * area, size_t size, map2_type const & m2, free_list_type & free)
+{
+ unsigned char * p = static_cast<unsigned char *>(area);
+
+ for(size_t n = 0; n + sizeof(shared_ptr_layout) <= size; p += pointer_align, n += pointer_align)
+ {
+ shared_ptr_layout * q = reinterpret_cast<shared_ptr_layout *>(p);
+
+ if(q->pn.id == boost::detail::shared_count_id && q->pn.pi != 0 && m2.count(q->pn.pi) != 0 && q->px != 0)
+ {
+ boost::shared_ptr<X> * ppx = reinterpret_cast< boost::shared_ptr<X> * >(p);
+ free.push_back(*ppx);
+ ppx->reset();
+ }
+ }
+}
+
+void free_unreachable_objects()
+{
+ free_list_type free;
+
+ {
+ map2_type m2;
+
+#ifdef BOOST_HAS_THREADS
+
+ mutex_type::scoped_lock lock(get_mutex());
+
+#endif
+
+ map_type const & m = get_map();
+
+ find_unreachable_objects_impl(m, m2);
+
+ for(map2_type::iterator j = m2.begin(); j != m2.end(); ++j)
+ {
+ map_type::const_iterator i = m.find(j->first);
+ BOOST_ASSERT(i != m.end());
+ scan_and_free(i->second.first, i->second.second, m2, free);
+ }
+ }
+
+ std::cout << "... about to free " << free.size() << " objects.\n";
+}
+
+// debug hooks
+
+namespace boost
+{
+
+void sp_scalar_constructor_hook(void *)
+{
+}
+
+void sp_scalar_constructor_hook(void * px, std::size_t size, void * pn)
+{
+#ifdef BOOST_HAS_THREADS
+
+ mutex_type::scoped_lock lock(get_mutex());
+
+#endif
+
+ get_map()[pn] = std::make_pair(px, size);
+}
+
+void sp_scalar_destructor_hook(void *)
+{
+}
+
+void sp_scalar_destructor_hook(void *, std::size_t, void * pn)
+{
+#ifdef BOOST_HAS_THREADS
+
+ mutex_type::scoped_lock lock(get_mutex());
+
+#endif
+
+ get_map().erase(pn);
+}
+
+void sp_array_constructor_hook(void *)
+{
+}
+
+void sp_array_destructor_hook(void *)
+{
+}
+
+} // namespace boost
+
+#endif // defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
diff --git a/src/boost/libs/smart_ptr/extras/src/sp_debug_hooks.cpp b/src/boost/libs/smart_ptr/extras/src/sp_debug_hooks.cpp
new file mode 100644
index 000000000..31939363b
--- /dev/null
+++ b/src/boost/libs/smart_ptr/extras/src/sp_debug_hooks.cpp
@@ -0,0 +1,243 @@
+//
+// sp_debug_hooks.cpp
+//
+// Copyright (c) 2002, 2003 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)
+//
+
+#if defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
+
+#include <boost/assert.hpp>
+#include <new>
+#include <cstdlib>
+
+int const m = 2; // m * sizeof(int) must be aligned appropriately
+
+// magic values to mark heap blocks with
+
+int const allocated_scalar = 0x1234560C;
+int const allocated_array = 0x1234560A;
+int const adopted_scalar = 0x0567890C;
+int const adopted_array = 0x0567890A;
+int const deleted = 0x498769DE;
+
+using namespace std; // for compilers where things aren't in std
+
+// operator new
+
+static new_handler get_new_handler()
+{
+ new_handler p = set_new_handler(0);
+ set_new_handler(p);
+ return p;
+}
+
+static void * allocate(size_t n, int mark)
+{
+ int * pm;
+
+ for(;;)
+ {
+ pm = static_cast<int*>(malloc(n + m * sizeof(int)));
+
+ if(pm != 0) break;
+
+ if(new_handler pnh = get_new_handler())
+ {
+ pnh();
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ *pm = mark;
+
+ return pm + m;
+}
+
+void * operator new(size_t n) throw(bad_alloc)
+{
+ void * p = allocate(n, allocated_scalar);
+
+#if !defined(BOOST_NO_EXCEPTIONS)
+
+ if(p == 0) throw bad_alloc();
+
+#endif
+
+ return p;
+}
+
+#if !defined(__BORLANDC__) || (__BORLANDC__ > 0x551)
+
+void * operator new(size_t n, nothrow_t const &) throw()
+{
+ return allocate(n, allocated_scalar);
+}
+
+#endif
+
+void * operator new[](size_t n) throw(bad_alloc)
+{
+ void * p = allocate(n, allocated_array);
+
+#if !defined(BOOST_NO_EXCEPTIONS)
+
+ if(p == 0) throw bad_alloc();
+
+#endif
+
+ return p;
+}
+
+#if !defined(__BORLANDC__) || (__BORLANDC__ > 0x551)
+
+void * operator new[](size_t n, nothrow_t const &) throw()
+{
+ return allocate(n, allocated_array);
+}
+
+#endif
+
+// debug hooks
+
+namespace boost
+{
+
+void sp_scalar_constructor_hook(void * p)
+{
+ if(p == 0) return;
+
+ int * pm = static_cast<int*>(p);
+ pm -= m;
+
+ BOOST_ASSERT(*pm != adopted_scalar); // second smart pointer to the same address
+ BOOST_ASSERT(*pm != allocated_array); // allocated with new[]
+ BOOST_ASSERT(*pm == allocated_scalar); // not allocated with new
+
+ *pm = adopted_scalar;
+}
+
+void sp_scalar_constructor_hook(void * px, std::size_t, void *)
+{
+ sp_scalar_constructor_hook(px);
+}
+
+void sp_scalar_destructor_hook(void * p)
+{
+ if(p == 0) return;
+
+ int * pm = static_cast<int*>(p);
+ pm -= m;
+
+ BOOST_ASSERT(*pm == adopted_scalar); // attempt to destroy nonmanaged block
+
+ *pm = allocated_scalar;
+}
+
+void sp_scalar_destructor_hook(void * px, std::size_t, void *)
+{
+ sp_scalar_destructor_hook(px);
+}
+
+// It is not possible to handle the array hooks in a portable manner.
+// The implementation typically reserves a bit of storage for the number
+// of objects in the array, and the argument of the array hook isn't
+// equal to the return value of operator new[].
+
+void sp_array_constructor_hook(void * /* p */)
+{
+/*
+ if(p == 0) return;
+
+ // adjust p depending on the implementation
+
+ int * pm = static_cast<int*>(p);
+ pm -= m;
+
+ BOOST_ASSERT(*pm != adopted_array); // second smart array pointer to the same address
+ BOOST_ASSERT(*pm != allocated_scalar); // allocated with new
+ BOOST_ASSERT(*pm == allocated_array); // not allocated with new[]
+
+ *pm = adopted_array;
+*/
+}
+
+void sp_array_destructor_hook(void * /* p */)
+{
+/*
+ if(p == 0) return;
+
+ // adjust p depending on the implementation
+
+ int * pm = static_cast<int*>(p);
+ pm -= m;
+
+ BOOST_ASSERT(*pm == adopted_array); // attempt to destroy nonmanaged block
+
+ *pm = allocated_array;
+*/
+}
+
+} // namespace boost
+
+// operator delete
+
+void operator delete(void * p) throw()
+{
+ if(p == 0) return;
+
+ int * pm = static_cast<int*>(p);
+ pm -= m;
+
+ BOOST_ASSERT(*pm != deleted); // double delete
+ BOOST_ASSERT(*pm != adopted_scalar); // delete p.get();
+ BOOST_ASSERT(*pm != allocated_array); // allocated with new[]
+ BOOST_ASSERT(*pm == allocated_scalar); // not allocated with new
+
+ *pm = deleted;
+
+ free(pm);
+}
+
+#if !defined(__BORLANDC__) || (__BORLANDC__ > 0x551)
+
+void operator delete(void * p, nothrow_t const &) throw()
+{
+ ::operator delete(p);
+}
+
+#endif
+
+void operator delete[](void * p) throw()
+{
+ if(p == 0) return;
+
+ int * pm = static_cast<int*>(p);
+ pm -= m;
+
+ BOOST_ASSERT(*pm != deleted); // double delete
+ BOOST_ASSERT(*pm != adopted_scalar); // delete p.get();
+ BOOST_ASSERT(*pm != allocated_scalar); // allocated with new
+ BOOST_ASSERT(*pm == allocated_array); // not allocated with new[]
+
+ *pm = deleted;
+
+ free(pm);
+}
+
+#if !defined(__BORLANDC__) || (__BORLANDC__ > 0x551)
+
+void operator delete[](void * p, nothrow_t const &) throw()
+{
+ ::operator delete[](p);
+}
+
+#endif
+
+#endif // defined(BOOST_SP_ENABLE_DEBUG_HOOKS)
diff --git a/src/boost/libs/smart_ptr/extras/test/shared_ptr_mt_test.cpp b/src/boost/libs/smart_ptr/extras/test/shared_ptr_mt_test.cpp
new file mode 100644
index 000000000..8a504256e
--- /dev/null
+++ b/src/boost/libs/smart_ptr/extras/test/shared_ptr_mt_test.cpp
@@ -0,0 +1,82 @@
+#include <boost/config.hpp>
+
+#if defined(BOOST_MSVC)
+#pragma warning(disable: 4786) // identifier truncated in debug info
+#pragma warning(disable: 4710) // function not inlined
+#pragma warning(disable: 4711) // function selected for automatic inline expansion
+#pragma warning(disable: 4514) // unreferenced inline removed
+#endif
+
+// shared_ptr_mt_test.cpp - tests shared_ptr with multiple threads
+//
+// Copyright (c) 2002 Peter Dimov and Multi Media Ltd.
+// 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/shared_ptr.hpp>
+#include <boost/bind.hpp>
+
+#include <vector>
+
+#include <cstdio>
+#include <ctime>
+
+#include <boost/detail/lightweight_thread.hpp>
+
+//
+
+int const n = 1024 * 1024;
+
+void test( boost::shared_ptr<int> const & pi )
+{
+ std::vector< boost::shared_ptr<int> > v;
+
+ for( int i = 0; i < n; ++i )
+ {
+ v.push_back( pi );
+ }
+}
+
+int const m = 16; // threads
+
+#if defined( BOOST_HAS_PTHREADS )
+
+char const * thmodel = "POSIX";
+
+#else
+
+char const * thmodel = "Windows";
+
+#endif
+
+int main()
+{
+ using namespace std; // printf, clock_t, clock
+
+ printf( "Using %s threads: %d threads, %d iterations: ", thmodel, m, n );
+
+ boost::shared_ptr<int> pi( new int(42) );
+
+ clock_t t = clock();
+
+ boost::detail::lw_thread_t a[ m ];
+
+ for( int i = 0; i < m; ++i )
+ {
+ boost::detail::lw_thread_create( a[ i ], boost::bind( test, pi ) );
+ }
+
+ for( int j = 0; j < m; ++j )
+ {
+ boost::detail::lw_thread_join( a[j] );
+ }
+
+ t = clock() - t;
+
+ printf( "\n\n%.3f seconds.\n", static_cast<double>(t) / CLOCKS_PER_SEC );
+
+ return 0;
+}
diff --git a/src/boost/libs/smart_ptr/extras/test/shared_ptr_timing_test.cpp b/src/boost/libs/smart_ptr/extras/test/shared_ptr_timing_test.cpp
new file mode 100644
index 000000000..79e62ff43
--- /dev/null
+++ b/src/boost/libs/smart_ptr/extras/test/shared_ptr_timing_test.cpp
@@ -0,0 +1,46 @@
+#include <boost/config.hpp>
+
+#if defined(BOOST_MSVC)
+#pragma warning(disable: 4786) // identifier truncated in debug info
+#pragma warning(disable: 4710) // function not inlined
+#pragma warning(disable: 4711) // function selected for automatic inline expansion
+#pragma warning(disable: 4514) // unreferenced inline removed
+#endif
+
+//
+// shared_ptr_timing_test.cpp - use to evaluate the impact of thread safety
+//
+// Copyright (c) 2002 Peter Dimov and Multi Media Ltd.
+//
+// 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/shared_ptr.hpp>
+#include <iostream>
+#include <vector>
+#include <ctime>
+
+int const n = 8 * 1024 * 1024;
+
+int main()
+{
+ using namespace std;
+
+ std::vector< boost::shared_ptr<int> > v;
+ boost::shared_ptr<int> pi(new int);
+
+ clock_t t = clock();
+
+ for(int i = 0; i < n; ++i)
+ {
+ v.push_back(pi);
+ }
+
+ t = clock() - t;
+
+ std::cout << static_cast<double>(t) / CLOCKS_PER_SEC << '\n';
+
+ return 0;
+}
diff --git a/src/boost/libs/smart_ptr/extras/test/sp_atomic_mt2_test.cpp b/src/boost/libs/smart_ptr/extras/test/sp_atomic_mt2_test.cpp
new file mode 100644
index 000000000..750b0b26a
--- /dev/null
+++ b/src/boost/libs/smart_ptr/extras/test/sp_atomic_mt2_test.cpp
@@ -0,0 +1,247 @@
+
+// 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/config.hpp>
+
+#include <boost/shared_ptr.hpp>
+#include <boost/bind.hpp>
+
+#include <boost/thread/shared_mutex.hpp>
+#include <boost/thread/locks.hpp>
+
+#include <boost/detail/lightweight_mutex.hpp>
+#include <boost/detail/lightweight_thread.hpp>
+
+#include <vector>
+#include <numeric>
+#include <cstdio>
+#include <cstdlib>
+#include <cstddef>
+#include <ctime>
+
+//
+
+static void next_value( unsigned & v )
+{
+ v = v % 2? 3 * v + 1: v / 2;
+}
+
+struct X
+{
+ std::vector<unsigned> v_;
+
+ explicit X( std::size_t n ): v_( n )
+ {
+ for( std::size_t i = 0; i < n; ++i )
+ {
+ v_[ i ] = i;
+ }
+ }
+
+ unsigned get() const
+ {
+ return std::accumulate( v_.begin(), v_.end(), 0 );
+ }
+
+ void set()
+ {
+ std::for_each( v_.begin(), v_.end(), next_value );
+ }
+};
+
+static boost::shared_ptr<X> ps;
+
+static boost::detail::lightweight_mutex lm;
+static boost::shared_mutex rw;
+
+enum prim_type
+{
+ pt_mutex,
+ pt_rwlock,
+ pt_atomics
+};
+
+int read_access( prim_type pt )
+{
+ switch( pt )
+ {
+ case pt_mutex:
+ {
+ boost::detail::lightweight_mutex::scoped_lock lock( lm );
+ return ps->get();
+ }
+
+ case pt_rwlock:
+ {
+ boost::shared_lock<boost::shared_mutex> lock( rw );
+ return ps->get();
+ }
+
+ case pt_atomics:
+ {
+ boost::shared_ptr<X> p2 = boost::atomic_load( &ps );
+ return p2->get();
+ }
+ }
+}
+
+void write_access( prim_type pt )
+{
+ switch( pt )
+ {
+ case pt_mutex:
+ {
+ boost::detail::lightweight_mutex::scoped_lock lock( lm );
+ ps->set();
+ }
+ break;
+
+ case pt_rwlock:
+ {
+ boost::unique_lock<boost::shared_mutex> lock( rw );
+ ps->set();
+ }
+ break;
+
+ case pt_atomics:
+ {
+ boost::shared_ptr<X> p1 = boost::atomic_load( &ps );
+
+ for( ;; )
+ {
+ boost::shared_ptr<X> p2( new X( *p1 ) );
+ p2->set();
+
+ if( boost::atomic_compare_exchange( &ps, &p1, p2 ) ) break;
+ }
+ }
+ break;
+ }
+}
+
+void worker( int k, prim_type pt, int n, int r )
+{
+ ++r;
+
+ unsigned s = 0, nr = 0, nw = 0;
+
+ for( int i = 0; i < n; ++i )
+ {
+ if( i % r )
+ {
+ s += read_access( pt );
+ ++nr;
+ }
+ else
+ {
+ write_access( pt );
+ ++s;
+ ++nw;
+ }
+ }
+
+ printf( "Worker %2d: %u:%u, %10u\n", k, nr, nw, s );
+}
+
+#if defined( BOOST_HAS_PTHREADS )
+ char const * thmodel = "POSIX";
+#else
+ char const * thmodel = "Windows";
+#endif
+
+char const * pt_to_string( prim_type pt )
+{
+ switch( pt )
+ {
+ case pt_mutex:
+
+ return "mutex";
+
+ case pt_rwlock:
+
+ return "rwlock";
+
+ case pt_atomics:
+
+ return "atomics";
+ }
+}
+
+static void handle_pt_option( std::string const & opt, prim_type & pt, prim_type pt2 )
+{
+ if( opt == pt_to_string( pt2 ) )
+ {
+ pt = pt2;
+ }
+}
+
+static void handle_int_option( std::string const & opt, std::string const & prefix, int & k, int kmin, int kmax )
+{
+ if( opt.substr( 0, prefix.size() ) == prefix )
+ {
+ int v = atoi( opt.substr( prefix.size() ).c_str() );
+
+ if( v >= kmin && v <= kmax )
+ {
+ k = v;
+ }
+ }
+}
+
+int main( int ac, char const * av[] )
+{
+ using namespace std; // printf, clock_t, clock
+
+ int m = 4; // threads
+ int n = 10000; // vector size
+ int k = 1000000; // iterations
+ int r = 100; // read/write ratio, r:1
+
+ prim_type pt = pt_atomics;
+
+ for( int i = 1; i < ac; ++i )
+ {
+ handle_pt_option( av[i], pt, pt_mutex );
+ handle_pt_option( av[i], pt, pt_rwlock );
+ handle_pt_option( av[i], pt, pt_atomics );
+
+ handle_int_option( av[i], "n=", n, 1, INT_MAX );
+ handle_int_option( av[i], "size=", n, 1, INT_MAX );
+
+ handle_int_option( av[i], "k=", k, 1, INT_MAX );
+ handle_int_option( av[i], "iterations=", k, 1, INT_MAX );
+
+ handle_int_option( av[i], "m=", m, 1, INT_MAX );
+ handle_int_option( av[i], "threads=", m, 1, INT_MAX );
+
+ handle_int_option( av[i], "r=", r, 1, INT_MAX );
+ handle_int_option( av[i], "ratio=", r, 1, INT_MAX );
+ }
+
+ printf( "%s: threads=%d size=%d iterations=%d ratio=%d %s\n\n", thmodel, m, n, k, r, pt_to_string( pt ) );
+
+ ps.reset( new X( n ) );
+
+ clock_t t = clock();
+
+ std::vector<boost::detail::lw_thread_t> a( m );
+
+ for( int i = 0; i < m; ++i )
+ {
+ boost::detail::lw_thread_create( a[ i ], boost::bind( worker, i, pt, k, r ) );
+ }
+
+ for( int j = 0; j < m; ++j )
+ {
+ boost::detail::lw_thread_join( a[ j ] );
+ }
+
+ t = clock() - t;
+
+ double ts = static_cast<double>( t ) / CLOCKS_PER_SEC;
+ printf( "%.3f seconds, %.3f accesses per microsecond.\n", ts, m * k / ts / 1e+6 );
+}
diff --git a/src/boost/libs/smart_ptr/extras/test/sp_atomic_mt_test.cpp b/src/boost/libs/smart_ptr/extras/test/sp_atomic_mt_test.cpp
new file mode 100644
index 000000000..32c76c514
--- /dev/null
+++ b/src/boost/libs/smart_ptr/extras/test/sp_atomic_mt_test.cpp
@@ -0,0 +1,191 @@
+
+// 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
+
+//#define USE_MUTEX
+//#define USE_RWLOCK
+
+#include <boost/config.hpp>
+
+#include <boost/shared_ptr.hpp>
+#include <boost/bind.hpp>
+
+#if defined( USE_RWLOCK )
+#include <boost/thread/shared_mutex.hpp>
+#include <boost/thread/locks.hpp>
+#endif
+
+#include <boost/detail/lightweight_mutex.hpp>
+#include <boost/detail/lightweight_test.hpp>
+#include <boost/detail/lightweight_thread.hpp>
+
+#include <cstdio>
+#include <ctime>
+
+//
+
+int const n = 1024 * 1024;
+
+struct X
+{
+ int v_; // version
+
+ unsigned a_;
+ unsigned b_;
+
+ X(): v_( 0 ), a_( 1 ), b_( 1 )
+ {
+ }
+
+ int get() const
+ {
+ return a_ * 7 + b_ * 11;
+ }
+
+ void set()
+ {
+ int tmp = get();
+
+ b_ = a_;
+ a_ = tmp;
+
+ ++v_;
+ }
+};
+
+static boost::shared_ptr<X> ps( new X );
+
+static boost::detail::lightweight_mutex lm;
+
+#if defined( USE_RWLOCK )
+static boost::shared_mutex rw;
+#endif
+
+static int tr = 0;
+
+void reader( int r )
+{
+ int k = 0;
+ unsigned s = 0;
+
+ for( int i = 0; i < n; ++k )
+ {
+#if defined( USE_MUTEX )
+
+ boost::detail::lightweight_mutex::scoped_lock lock( lm );
+
+ s += ps->get();
+
+ BOOST_TEST( ps->v_ >= i );
+ i = ps->v_;
+
+#elif defined( USE_RWLOCK )
+
+ boost::shared_lock<boost::shared_mutex> lock( rw );
+
+ s += ps->get();
+
+ BOOST_TEST( ps->v_ >= i );
+ i = ps->v_;
+
+#else
+
+ boost::shared_ptr<X> p2 = boost::atomic_load( &ps );
+
+ s += p2->get();
+
+ BOOST_TEST( p2->v_ >= i );
+ i = p2->v_;
+
+#endif
+ }
+
+ printf( "Reader %d: %9d iterations (%6.3fx), %u\n", r, k, (double)k / n, s );
+
+ boost::detail::lightweight_mutex::scoped_lock lock( lm );
+ tr += k;
+}
+
+void writer()
+{
+ for( int i = 0; i < n; ++i )
+ {
+#if defined( USE_MUTEX )
+
+ boost::detail::lightweight_mutex::scoped_lock lock( lm );
+
+ BOOST_TEST( ps->v_ == i );
+ ps->set();
+
+#elif defined( USE_RWLOCK )
+
+ boost::unique_lock<boost::shared_mutex> lock( rw );
+
+ BOOST_TEST( ps->v_ == i );
+ ps->set();
+
+#else
+
+ boost::shared_ptr<X> p2( new X( *ps ) );
+
+ BOOST_TEST( p2->v_ == i );
+ p2->set();
+
+ boost::atomic_store( &ps, p2 );
+
+#endif
+ }
+}
+
+#if defined( BOOST_HAS_PTHREADS )
+ char const * thmodel = "POSIX";
+#else
+ char const * thmodel = "Windows";
+#endif
+
+int const mr = 8; // reader threads
+int const mw = 1; // writer thread
+
+#if defined( USE_MUTEX )
+ char const * prim = "mutex";
+#elif defined( USE_RWLOCK )
+ char const * prim = "rwlock";
+#else
+ char const * prim = "atomics";
+#endif
+
+int main()
+{
+ using namespace std; // printf, clock_t, clock
+
+ printf( "Using %s threads: %dR + %dW threads, %d iterations, %s\n\n", thmodel, mr, mw, n, prim );
+
+ clock_t t = clock();
+
+ boost::detail::lw_thread_t a[ mr+mw ];
+
+ for( int i = 0; i < mr; ++i )
+ {
+ boost::detail::lw_thread_create( a[ i ], boost::bind( reader, i ) );
+ }
+
+ for( int i = mr; i < mr+mw; ++i )
+ {
+ boost::detail::lw_thread_create( a[ i ], writer );
+ }
+
+ for( int j = 0; j < mr+mw; ++j )
+ {
+ boost::detail::lw_thread_join( a[ j ] );
+ }
+
+ t = clock() - t;
+
+ double ts = static_cast<double>( t ) / CLOCKS_PER_SEC;
+ printf( "%.3f seconds, %.3f reads per microsecond.\n", ts, tr / ts / 1e+6 );
+
+ return boost::report_errors();
+}
diff --git a/src/boost/libs/smart_ptr/extras/test/weak_ptr_mt_test.cpp b/src/boost/libs/smart_ptr/extras/test/weak_ptr_mt_test.cpp
new file mode 100644
index 000000000..5b11ff9c6
--- /dev/null
+++ b/src/boost/libs/smart_ptr/extras/test/weak_ptr_mt_test.cpp
@@ -0,0 +1,122 @@
+#include <boost/config.hpp>
+
+#if defined(BOOST_MSVC)
+#pragma warning(disable: 4786) // identifier truncated in debug info
+#pragma warning(disable: 4710) // function not inlined
+#pragma warning(disable: 4711) // function selected for automatic inline expansion
+#pragma warning(disable: 4514) // unreferenced inline removed
+#endif
+
+// weak_ptr_mt_test.cpp
+//
+// Copyright (c) 2002 Peter Dimov and Multi Media Ltd.
+// Copyright 2005, 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/shared_ptr.hpp>
+#include <boost/weak_ptr.hpp>
+#include <boost/bind.hpp>
+
+#include <vector>
+
+#include <cstdio>
+#include <ctime>
+#include <cstdlib>
+
+#include <boost/detail/lightweight_thread.hpp>
+
+//
+
+int const n = 16384;
+int const k = 512; // vector size
+int const m = 16; // threads
+
+void test( std::vector< boost::shared_ptr<int> > & v )
+{
+ using namespace std; // printf, rand
+
+ std::vector< boost::weak_ptr<int> > w( v.begin(), v.end() );
+
+ int s = 0, f = 0, r = 0;
+
+ for( int i = 0; i < n; ++i )
+ {
+ // randomly kill a pointer
+
+ v[ rand() % k ].reset();
+ ++s;
+
+ for( int j = 0; j < k; ++j )
+ {
+ if( boost::shared_ptr<int> px = w[ j ].lock() )
+ {
+ ++s;
+
+ if( rand() & 4 )
+ {
+ continue;
+ }
+
+ // rebind anyway with prob. 50% for add_ref_lock() against weak_release() contention
+ ++f;
+ }
+ else
+ {
+ ++r;
+ }
+
+ w[ j ] = v[ rand() % k ];
+ }
+ }
+
+ printf( "\n%d locks, %d forced rebinds, %d normal rebinds.", s, f, r );
+}
+
+#if defined( BOOST_HAS_PTHREADS )
+
+char const * thmodel = "POSIX";
+
+#else
+
+char const * thmodel = "Windows";
+
+#endif
+
+int main()
+{
+ using namespace std; // printf, clock_t, clock
+
+ printf("Using %s threads: %d threads, %d * %d iterations: ", thmodel, m, n, k );
+
+ std::vector< boost::shared_ptr<int> > v( k );
+
+ for( int i = 0; i < k; ++i )
+ {
+ v[ i ].reset( new int( 0 ) );
+ }
+
+ clock_t t = clock();
+
+ boost::detail::lw_thread_t a[ m ];
+
+ for( int i = 0; i < m; ++i )
+ {
+ boost::detail::lw_thread_create( a[ i ], boost::bind( test, v ) );
+ }
+
+ v.resize( 0 ); // kill original copies
+
+ for( int j = 0; j < m; ++j )
+ {
+ boost::detail::lw_thread_join( a[j] );
+ }
+
+ t = clock() - t;
+
+ printf("\n\n%.3f seconds.\n", static_cast<double>(t) / CLOCKS_PER_SEC);
+
+ return 0;
+}
diff --git a/src/boost/libs/smart_ptr/extras/test/weak_ptr_timing_test.cpp b/src/boost/libs/smart_ptr/extras/test/weak_ptr_timing_test.cpp
new file mode 100644
index 000000000..1c24b0a3b
--- /dev/null
+++ b/src/boost/libs/smart_ptr/extras/test/weak_ptr_timing_test.cpp
@@ -0,0 +1,85 @@
+#include <boost/config.hpp>
+
+#if defined(BOOST_MSVC)
+#pragma warning(disable: 4786) // identifier truncated in debug info
+#pragma warning(disable: 4710) // function not inlined
+#pragma warning(disable: 4711) // function selected for automatic inline expansion
+#pragma warning(disable: 4514) // unreferenced inline removed
+#endif
+
+//
+// weak_ptr_timing_test.cpp
+//
+// Copyright (c) 2002 Peter Dimov and Multi Media Ltd.
+// Copyright 2005 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/shared_ptr.hpp>
+#include <boost/weak_ptr.hpp>
+
+#include <vector>
+#include <cstdio>
+#include <ctime>
+#include <cstdlib>
+
+//
+
+int const n = 29000;
+int const k = 2048;
+
+void test( std::vector< boost::shared_ptr<int> > & v )
+{
+ using namespace std; // printf, rand
+
+ std::vector< boost::weak_ptr<int> > w( v.begin(), v.end() );
+
+ int s = 0, r = 0;
+
+ for( int i = 0; i < n; ++i )
+ {
+ // randomly kill a pointer
+
+ v[ rand() % k ].reset();
+
+ for( int j = 0; j < k; ++j )
+ {
+ if( boost::shared_ptr<int> px = w[ j ].lock() )
+ {
+ ++s;
+ }
+ else
+ {
+ ++r;
+ w[ j ] = v[ rand() % k ];
+ }
+ }
+ }
+
+ printf( "\n%d locks, %d rebinds.", s, r );
+}
+
+int main()
+{
+ using namespace std; // printf, clock_t, clock
+
+ std::vector< boost::shared_ptr<int> > v( k );
+
+ for( int i = 0; i < k; ++i )
+ {
+ v[ i ].reset( new int( 0 ) );
+ }
+
+ clock_t t = clock();
+
+ test( v );
+
+ t = clock() - t;
+
+ printf( "\n\n%.3f seconds.\n", static_cast<double>( t ) / CLOCKS_PER_SEC );
+
+ return 0;
+}