From 7faec4265bff23acae3f2599fa29b4608916d8aa Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Wed, 21 Jan 2015 19:55:42 +0200 Subject: [PATCH 1/3] Fix conflicts with the I macro in . --- include/boost/smart_ptr/detail/spinlock_pool.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/smart_ptr/detail/spinlock_pool.hpp b/include/boost/smart_ptr/detail/spinlock_pool.hpp index f09d5c6..39cf180 100644 --- a/include/boost/smart_ptr/detail/spinlock_pool.hpp +++ b/include/boost/smart_ptr/detail/spinlock_pool.hpp @@ -31,7 +31,7 @@ namespace boost namespace detail { -template< int I > class spinlock_pool +template< int M > class spinlock_pool { private: @@ -72,7 +72,7 @@ public: }; }; -template< int I > spinlock spinlock_pool< I >::pool_[ 41 ] = +template< int M > spinlock spinlock_pool< M >::pool_[ 41 ] = { BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, BOOST_DETAIL_SPINLOCK_INIT, From 75de3dbcf1379119ee21a8029845c65fb8ce38a6 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Thu, 22 Jan 2015 05:13:27 +0200 Subject: [PATCH 2/3] Add clang-specific sp_counted_base. --- .../smart_ptr/detail/sp_counted_base.hpp | 11 ++ .../detail/sp_counted_base_clang.hpp | 140 ++++++++++++++++++ 2 files changed, 151 insertions(+) create mode 100644 include/boost/smart_ptr/detail/sp_counted_base_clang.hpp diff --git a/include/boost/smart_ptr/detail/sp_counted_base.hpp b/include/boost/smart_ptr/detail/sp_counted_base.hpp index c415892..0addf07 100644 --- a/include/boost/smart_ptr/detail/sp_counted_base.hpp +++ b/include/boost/smart_ptr/detail/sp_counted_base.hpp @@ -20,6 +20,12 @@ #include #include +#if defined( __clang__ ) && defined( __has_extension ) +# if __has_extension( __c_atomic__ ) +# define BOOST_SP_HAS_CLANG_C11_ATOMICS +# endif +#endif + #if defined( BOOST_SP_DISABLE_THREADS ) # include @@ -35,6 +41,9 @@ #elif defined( BOOST_DISABLE_THREADS ) && !defined( BOOST_SP_ENABLE_THREADS ) && !defined( BOOST_DISABLE_WIN32 ) # include +#elif defined( BOOST_SP_HAS_CLANG_C11_ATOMICS ) +# include + #elif defined( __SNC__ ) # include @@ -79,4 +88,6 @@ #endif +#undef BOOST_SP_HAS_CLANG_C11_ATOMICS + #endif // #ifndef BOOST_SMART_PTR_DETAIL_SP_COUNTED_BASE_HPP_INCLUDED diff --git a/include/boost/smart_ptr/detail/sp_counted_base_clang.hpp b/include/boost/smart_ptr/detail/sp_counted_base_clang.hpp new file mode 100644 index 0000000..c66b985 --- /dev/null +++ b/include/boost/smart_ptr/detail/sp_counted_base_clang.hpp @@ -0,0 +1,140 @@ +#ifndef BOOST_SMART_PTR_DETAIL_SP_COUNTED_BASE_CLANG_HPP_INCLUDED +#define BOOST_SMART_PTR_DETAIL_SP_COUNTED_BASE_CLANG_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// detail/sp_counted_base_clang.hpp - __c11 clang intrinsics +// +// Copyright (c) 2007, 2013, 2015 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 + +namespace boost +{ + +namespace detail +{ + +typedef _Atomic( boost::int_least32_t ) atomic_int_least32_t; + +inline void atomic_increment( atomic_int_least32_t * pw ) +{ + __c11_atomic_fetch_add( pw, 1, __ATOMIC_RELAXED ); +} + +inline boost::int_least32_t atomic_decrement( atomic_int_least32_t * pw ) +{ + return __c11_atomic_fetch_sub( pw, 1, __ATOMIC_ACQ_REL ); +} + +inline boost::int_least32_t atomic_conditional_increment( atomic_int_least32_t * pw ) +{ + // long r = *pw; + // if( r != 0 ) ++*pw; + // return r; + + boost::int_least32_t r = __c11_atomic_load( pw, __ATOMIC_RELAXED ); + + for( ;; ) + { + if( r == 0 ) + { + return r; + } + + if( __c11_atomic_compare_exchange_weak( pw, &r, r + 1, __ATOMIC_RELAXED, __ATOMIC_RELAXED ) ) + { + return r; + } + } +} + +class sp_counted_base +{ +private: + + sp_counted_base( sp_counted_base const & ); + sp_counted_base & operator= ( sp_counted_base const & ); + + atomic_int_least32_t use_count_; // #shared + atomic_int_least32_t weak_count_; // #weak + (#shared != 0) + +public: + + sp_counted_base() + { + __c11_atomic_init( &use_count_, 1 ); + __c11_atomic_init( &weak_count_, 1 ); + } + + virtual ~sp_counted_base() // nothrow + { + } + + // dispose() is called when use_count_ drops to zero, to release + // the resources managed by *this. + + virtual void dispose() = 0; // nothrow + + // destroy() is called when weak_count_ drops to zero. + + virtual void destroy() // nothrow + { + delete this; + } + + virtual void * get_deleter( sp_typeinfo const & ti ) = 0; + virtual void * get_untyped_deleter() = 0; + + void add_ref_copy() + { + atomic_increment( &use_count_ ); + } + + bool add_ref_lock() // true on success + { + return atomic_conditional_increment( &use_count_ ) != 0; + } + + void release() // nothrow + { + if( atomic_decrement( &use_count_ ) == 1 ) + { + dispose(); + weak_release(); + } + } + + void weak_add_ref() // nothrow + { + atomic_increment( &weak_count_ ); + } + + void weak_release() // nothrow + { + if( atomic_decrement( &weak_count_ ) == 1 ) + { + destroy(); + } + } + + long use_count() const // nothrow + { + return __c11_atomic_load( const_cast< atomic_int_least32_t* >( &use_count_ ), __ATOMIC_ACQUIRE ); + } +}; + +} // namespace detail + +} // namespace boost + +#endif // #ifndef BOOST_SMART_PTR_DETAIL_SP_COUNTED_BASE_CLANG_HPP_INCLUDED From 3fd53ced83d1ac67a27f9f9a47431c025d414b02 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Thu, 22 Jan 2015 20:47:01 +0200 Subject: [PATCH 3/3] Make shared_from_raw and weak_from_raw return consistent values in a constructor, regardless of order, as suggested by Gavin Lambert in #8. --- .../smart_ptr/enable_shared_from_raw.hpp | 26 ++++++- test/Jamfile.v2 | 2 + test/weak_from_raw_test.cpp | 3 +- test/weak_from_raw_test3.cpp | 46 +++++++++++++ test/weak_from_raw_test4.cpp | 67 +++++++++++++++++++ 5 files changed, 139 insertions(+), 5 deletions(-) create mode 100644 test/weak_from_raw_test3.cpp create mode 100644 test/weak_from_raw_test4.cpp diff --git a/include/boost/smart_ptr/enable_shared_from_raw.hpp b/include/boost/smart_ptr/enable_shared_from_raw.hpp index 1911c07..669a649 100644 --- a/include/boost/smart_ptr/enable_shared_from_raw.hpp +++ b/include/boost/smart_ptr/enable_shared_from_raw.hpp @@ -53,7 +53,7 @@ protected: private: - void init_weak_once() const + void init_if_expired() const { if( weak_this_.expired() ) { @@ -62,6 +62,15 @@ private: } } + void init_if_empty() const + { + if( weak_this_._empty() ) + { + shared_this_.reset( static_cast(0), detail::esft2_deleter_wrapper() ); + weak_this_ = shared_this_; + } + } + #ifdef BOOST_NO_MEMBER_TEMPLATE_FRIENDS public: #else @@ -74,7 +83,7 @@ private: shared_ptr shared_from_this() const { - init_weak_once(); + init_if_expired(); return shared_ptr( weak_this_ ); } @@ -83,6 +92,17 @@ private: return const_cast< enable_shared_from_raw const * >( this )->shared_from_this(); } + weak_ptr weak_from_this() const + { + init_if_empty(); + return weak_this_; + } + + weak_ptr weak_from_this() const volatile + { + return const_cast< enable_shared_from_raw const * >( this )->weak_from_this(); + } + // Note: invoked automatically by shared_ptr; do not call template void _internal_accept_owner( shared_ptr * ppx, Y * py ) const { @@ -125,7 +145,7 @@ boost::weak_ptr weak_from_raw(T *p) { BOOST_ASSERT(p != 0); boost::weak_ptr result; - result._internal_aliasing_assign(p->enable_shared_from_raw::weak_this_, p); + result._internal_aliasing_assign(p->enable_shared_from_raw::weak_from_this(), p); return result; } diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 0b51eee..a848d4f 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -171,6 +171,8 @@ import testing ; [ run weak_from_raw_test.cpp ] [ run weak_from_raw_test2.cpp ] + [ run weak_from_raw_test3.cpp ] + [ run weak_from_raw_test4.cpp ] [ compile sp_explicit_inst_test.cpp ] ; diff --git a/test/weak_from_raw_test.cpp b/test/weak_from_raw_test.cpp index ba95ecc..34d21eb 100644 --- a/test/weak_from_raw_test.cpp +++ b/test/weak_from_raw_test.cpp @@ -12,7 +12,6 @@ #include - #include @@ -23,7 +22,7 @@ void basic_weak_from_raw_test() { X *p(new X); boost::weak_ptr weak = boost::weak_from_raw(p); - BOOST_TEST(weak.expired()); + BOOST_TEST(!weak.expired()); boost::shared_ptr shared(p); weak = boost::weak_from_raw(p); BOOST_TEST(weak.expired() == false); diff --git a/test/weak_from_raw_test3.cpp b/test/weak_from_raw_test3.cpp new file mode 100644 index 0000000..ee73b4c --- /dev/null +++ b/test/weak_from_raw_test3.cpp @@ -0,0 +1,46 @@ +// +// weak_from_raw_test3.cpp +// +// Test that weak_from_raw and shared_from_raw +// return consistent values from a constructor +// +// Copyright (c) 2015 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 +#include + +class X: public boost::enable_shared_from_raw +{ +public: + + X() + { + boost::weak_ptr p1 = boost::weak_from_raw( this ); + BOOST_TEST( !p1.expired() ); + + boost::weak_ptr p2 = boost::weak_from_raw( this ); + BOOST_TEST( !p2.expired() ); + BOOST_TEST( !( p1 < p2 ) && !( p2 < p1 ) ); + + boost::weak_ptr p3 = boost::shared_from_raw( this ); + BOOST_TEST( !( p1 < p3 ) && !( p3 < p1 ) ); + + boost::weak_ptr p4 = boost::weak_from_raw( this ); + BOOST_TEST( !p4.expired() ); + BOOST_TEST( !( p3 < p4 ) && !( p4 < p3 ) ); + BOOST_TEST( !( p1 < p4 ) && !( p4 < p1 ) ); + } +}; + +int main() +{ + boost::shared_ptr< X > px( new X ); + return boost::report_errors(); +} diff --git a/test/weak_from_raw_test4.cpp b/test/weak_from_raw_test4.cpp new file mode 100644 index 0000000..646b84e --- /dev/null +++ b/test/weak_from_raw_test4.cpp @@ -0,0 +1,67 @@ +// +// weak_from_raw_test4.cpp +// +// As weak_from_raw_test2.cpp, but uses weak_from_this +// in the constructor +// +// Copyright (c) 2014, 2015 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 +#include + +class X; + +static boost::weak_ptr< X > r_; + +void register_( boost::weak_ptr< X > const & r ) +{ + r_ = r; +} + +void check_( boost::weak_ptr< X > const & r ) +{ + BOOST_TEST( !( r < r_ ) && !( r_ < r ) ); +} + +void unregister_( boost::weak_ptr< X > const & r ) +{ + BOOST_TEST( !( r < r_ ) && !( r_ < r ) ); + r_.reset(); +} + +class X: public boost::enable_shared_from_raw +{ +public: + + X() + { + register_( boost::weak_from_raw( this ) ); + } + + ~X() + { + unregister_( boost::weak_from_raw( this ) ); + } + + void check() + { + check_( boost::weak_from_raw( this ) ); + } +}; + +int main() +{ + { + boost::shared_ptr< X > px( new X ); + px->check(); + } + + return boost::report_errors(); +}