From 04be979670d977b2deda77ca5ee9900d2196b3a8 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Sun, 20 Apr 2008 14:59:12 +0000 Subject: [PATCH] Atomic access added. [SVN r44636] --- include/boost/memory_order.hpp | 35 ++++++++++++++ include/boost/shared_ptr.hpp | 64 +++++++++++++++++++++++++ test/Jamfile.v2 | 1 + test/sp_atomic_test.cpp | 87 ++++++++++++++++++++++++++++++++++ 4 files changed, 187 insertions(+) create mode 100644 include/boost/memory_order.hpp create mode 100644 test/sp_atomic_test.cpp diff --git a/include/boost/memory_order.hpp b/include/boost/memory_order.hpp new file mode 100644 index 0000000..be5a9ce --- /dev/null +++ b/include/boost/memory_order.hpp @@ -0,0 +1,35 @@ +#ifndef BOOST_MEMORY_ORDER_HPP_INCLUDED +#define BOOST_MEMORY_ORDER_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// boost/memory_order.hpp +// +// Defines enum boost::memory_order per the C++0x working draft +// +// 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) + + +namespace boost +{ + +enum memory_order +{ + memory_order_relaxed = 0, + memory_order_acquire = 1, + memory_order_release = 2, + memory_order_acq_rel = 3, // acquire | release + memory_order_seq_cst = 7, // acq_rel | 4 +}; + +} // namespace boost + +#endif // #ifndef BOOST_MEMORY_ORDER_HPP_INCLUDED diff --git a/include/boost/shared_ptr.hpp b/include/boost/shared_ptr.hpp index dc39c7a..9d92fd7 100644 --- a/include/boost/shared_ptr.hpp +++ b/include/boost/shared_ptr.hpp @@ -32,6 +32,11 @@ #include #include +#if !defined(BOOST_SP_NO_ATOMIC_ACCESS) +#include +#include +#endif + #include // for std::swap #include // for std::less #include // for std::bad_cast @@ -472,6 +477,65 @@ public: return pn.get_deleter( ti ); } + // atomic access + +#if !defined(BOOST_SP_NO_ATOMIC_ACCESS) + + shared_ptr atomic_load( memory_order /*mo*/ = memory_order_seq_cst ) const + { + boost::detail::spinlock_pool<2>::scoped_lock lock( this ); + return *this; + } + + void atomic_store( shared_ptr r, memory_order /*mo*/ = memory_order_seq_cst ) + { + boost::detail::spinlock_pool<2>::scoped_lock lock( this ); + swap( r ); + } + + shared_ptr atomic_swap( shared_ptr r, memory_order /*mo*/ = memory_order_seq_cst ) + { + boost::detail::spinlock & sp = boost::detail::spinlock_pool<2>::spinlock_for( this ); + + sp.lock(); + swap( r ); + sp.unlock(); + + return r; // return std::move(r) + } + + bool atomic_compare_swap( shared_ptr & v, shared_ptr w ) + { + boost::detail::spinlock & sp = boost::detail::spinlock_pool<2>::spinlock_for( this ); + + sp.lock(); + + if( px == v.px && pn == v.pn ) + { + swap( w ); + + sp.unlock(); + + return true; + } + else + { + shared_ptr tmp( *this ); + + sp.unlock(); + + tmp.swap( v ); + return false; + } + } + + inline bool atomic_compare_swap( shared_ptr & v, shared_ptr w, memory_order /*success*/, memory_order /*failure*/ ) + { + return atomic_compare_swap( v, w ); // std::move( w ) + } + +#endif + // Tasteless as this may seem, making all members public allows member templates // to work in the absence of member template friends. (Matthew Langston) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 499f9b9..ca14dd1 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -44,5 +44,6 @@ import testing ; [ run spinlock_try_test.cpp : : : multi : spinlock_try_test.mt ] [ run spinlock_pool_test.cpp ] [ run sp_accept_owner_test.cpp ] + [ run sp_atomic_test.cpp ] ; } diff --git a/test/sp_atomic_test.cpp b/test/sp_atomic_test.cpp new file mode 100644 index 0000000..c1113da --- /dev/null +++ b/test/sp_atomic_test.cpp @@ -0,0 +1,87 @@ +#include + +// sp_atomic_test.cpp +// +// 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 +#include + +// + +struct X +{ +}; + +#define BOOST_TEST_SP_EQ( p, q ) BOOST_TEST( p == q && !( p < q ) && !( q < p ) ) + +int main() +{ + boost::shared_ptr px( new X ); + + { + boost::shared_ptr p2 = px.atomic_load(); + BOOST_TEST_SP_EQ( p2, px ); + + boost::shared_ptr px2( new X ); + px.atomic_store( px2 ); + BOOST_TEST_SP_EQ( px, px2 ); + + p2 = px.atomic_load(); + BOOST_TEST_SP_EQ( p2, px ); + BOOST_TEST_SP_EQ( p2, px2 ); + + boost::shared_ptr px3( new X ); + boost::shared_ptr p3 = px.atomic_swap( px3 ); + BOOST_TEST_SP_EQ( p3, px2 ); + BOOST_TEST_SP_EQ( px, px3 ); + + boost::shared_ptr px4( new X ); + boost::shared_ptr cmp; + + bool r = px.atomic_compare_swap( cmp, px4 ); + BOOST_TEST( !r ); + BOOST_TEST_SP_EQ( px, px3 ); + BOOST_TEST_SP_EQ( cmp, px3 ); + + r = px.atomic_compare_swap( cmp, px4 ); + BOOST_TEST( r ); + BOOST_TEST_SP_EQ( px, px4 ); + } + + // + + px.reset(); + + { + boost::shared_ptr p2 = px.atomic_load( boost::memory_order_acquire ); + BOOST_TEST_SP_EQ( p2, px ); + + boost::shared_ptr px2( new X ); + px.atomic_store( px2, boost::memory_order_release ); + BOOST_TEST_SP_EQ( px, px2 ); + + boost::shared_ptr p3 = px.atomic_swap( boost::shared_ptr(), boost::memory_order_acq_rel ); + BOOST_TEST_SP_EQ( p3, px2 ); + BOOST_TEST_SP_EQ( px, p2 ); + + boost::shared_ptr px4( new X ); + boost::shared_ptr cmp( px2 ); + + bool r = px.atomic_compare_swap( cmp, px4, boost::memory_order_acquire, boost::memory_order_relaxed ); + BOOST_TEST( !r ); + BOOST_TEST_SP_EQ( px, p2 ); + BOOST_TEST_SP_EQ( cmp, p2 ); + + r = px.atomic_compare_swap( cmp, px4, boost::memory_order_release, boost::memory_order_acquire ); + BOOST_TEST( r ); + BOOST_TEST_SP_EQ( px, px4 ); + } + + return boost::report_errors(); +}