diff --git a/include/boost/smart_ptr/detail/atomic_count.hpp b/include/boost/smart_ptr/detail/atomic_count.hpp index cc44ac2..8aefd44 100644 --- a/include/boost/smart_ptr/detail/atomic_count.hpp +++ b/include/boost/smart_ptr/detail/atomic_count.hpp @@ -11,10 +11,11 @@ // boost/detail/atomic_count.hpp - thread/SMP safe reference counter // // Copyright (c) 2001, 2002 Peter Dimov and Multi Media Ltd. +// Copyright (c) 2013 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) +// 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 // // typedef boost::detail::atomic_count; // @@ -27,92 +28,68 @@ // a; // // Returns: (long) the current value of a +// Memory Ordering: acquire // // ++a; // // Effects: Atomically increments the value of a // Returns: (long) the new value of a +// Memory Ordering: acquire/release // // --a; // // Effects: Atomically decrements the value of a // Returns: (long) the new value of a -// -// Important note: when --a returns zero, it must act as a -// read memory barrier (RMB); i.e. the calling thread must -// have a synchronized view of the memory -// -// On Intel IA-32 (x86) memory is always synchronized, so this -// is not a problem. -// -// On many architectures the atomic instructions already act as -// a memory barrier. -// -// This property is necessary for proper reference counting, since -// a thread can update the contents of a shared object, then -// release its reference, and another thread may immediately -// release the last reference causing object destruction. -// -// The destructor needs to have a synchronized view of the -// object to perform proper cleanup. -// -// Original example by Alexander Terekhov: -// -// Given: -// -// - a mutable shared object OBJ; -// - two threads THREAD1 and THREAD2 each holding -// a private smart_ptr object pointing to that OBJ. -// -// t1: THREAD1 updates OBJ (thread-safe via some synchronization) -// and a few cycles later (after "unlock") destroys smart_ptr; -// -// t2: THREAD2 destroys smart_ptr WITHOUT doing any synchronization -// with respect to shared mutable object OBJ; OBJ destructors -// are called driven by smart_ptr interface... +// Memory Ordering: acquire/release // #include #include -#ifndef BOOST_HAS_THREADS +#if defined( BOOST_AC_DISABLE_THREADS ) +# include -namespace boost -{ +#elif defined( BOOST_AC_USE_STD_ATOMIC ) +# include -namespace detail -{ +#elif defined( BOOST_AC_USE_SPINLOCK ) +# include -typedef long atomic_count; +#elif defined( BOOST_AC_USE_PTHREADS ) +# include -} +#elif defined( BOOST_SP_DISABLE_THREADS ) +# include -} +#elif defined( BOOST_SP_USE_STD_ATOMIC ) +# include -#elif defined(BOOST_AC_USE_PTHREADS) -# include +#elif defined( BOOST_SP_USE_SPINLOCK ) +# include -#elif defined( __GNUC__ ) && ( defined( __i386__ ) || defined( __x86_64__ ) ) -# include +#elif defined( BOOST_SP_USE_PTHREADS ) +# include -#elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) -# include +#elif defined( BOOST_DISABLE_THREADS ) && !defined( BOOST_SP_ENABLE_THREADS ) && !defined( BOOST_DISABLE_WIN32 ) +# include + +#elif defined( __GNUC__ ) && ( defined( __i386__ ) || defined( __x86_64__ ) ) && !defined( __PATHSCALE__ ) +# include #elif defined( BOOST_SP_HAS_SYNC ) -# include +# include + +#elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) +# include #elif defined(__GLIBCPP__) || defined(__GLIBCXX__) -# include +# include -#elif defined(BOOST_HAS_PTHREADS) - -# define BOOST_AC_USE_PTHREADS -# include +#elif !defined( BOOST_HAS_THREADS ) +# include #else - -// Use #define BOOST_DISABLE_THREADS to avoid the error -#error Unrecognized threading platform +# include #endif diff --git a/include/boost/smart_ptr/detail/atomic_count_nt.hpp b/include/boost/smart_ptr/detail/atomic_count_nt.hpp new file mode 100644 index 0000000..3bbf138 --- /dev/null +++ b/include/boost/smart_ptr/detail/atomic_count_nt.hpp @@ -0,0 +1,59 @@ +#ifndef BOOST_SMART_PTR_DETAIL_ATOMIC_COUNT_NT_HPP_INCLUDED +#define BOOST_SMART_PTR_DETAIL_ATOMIC_COUNT_NT_HPP_INCLUDED + +// +// boost/detail/atomic_count_nt.hpp +// +// Trivial atomic_count for the single-threaded case +// +// http://gcc.gnu.org/onlinedocs/porting/Thread-safety.html +// +// Copyright 2013 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 +{ + +namespace detail +{ + +class atomic_count +{ +public: + + explicit atomic_count( long v ): value_( v ) + { + } + + long operator++() + { + return ++value_; + } + + long operator--() + { + return --value_; + } + + operator long() const + { + return value_; + } + +private: + + atomic_count(atomic_count const &); + atomic_count & operator=(atomic_count const &); + + long value_; +}; + +} // namespace detail + +} // namespace boost + +#endif // #ifndef BOOST_SMART_PTR_DETAIL_ATOMIC_COUNT_NT_HPP_INCLUDED diff --git a/include/boost/smart_ptr/detail/atomic_count_pthreads.hpp b/include/boost/smart_ptr/detail/atomic_count_pt.hpp similarity index 100% rename from include/boost/smart_ptr/detail/atomic_count_pthreads.hpp rename to include/boost/smart_ptr/detail/atomic_count_pt.hpp diff --git a/include/boost/smart_ptr/detail/atomic_count_spin.hpp b/include/boost/smart_ptr/detail/atomic_count_spin.hpp new file mode 100644 index 0000000..8e62349 --- /dev/null +++ b/include/boost/smart_ptr/detail/atomic_count_spin.hpp @@ -0,0 +1,62 @@ +#ifndef BOOST_SMART_PTR_DETAIL_ATOMIC_COUNT_SPIN_HPP_INCLUDED +#define BOOST_SMART_PTR_DETAIL_ATOMIC_COUNT_SPIN_HPP_INCLUDED + +// +// boost/detail/atomic_count_spin.hpp +// +// Copyright (c) 2013 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 + +namespace boost +{ + +namespace detail +{ + +class atomic_count +{ +private: + +public: + + explicit atomic_count( long v ): value_( v ) + { + } + + long operator++() + { + spinlock_pool<0>::scoped_lock lock( &value_ ); + return ++value_; + } + + long operator--() + { + spinlock_pool<0>::scoped_lock lock( &value_ ); + return --value_; + } + + operator long() const + { + spinlock_pool<0>::scoped_lock lock( &value_ ); + return value_; + } + +private: + + atomic_count(atomic_count const &); + atomic_count & operator=(atomic_count const &); + + long value_; +}; + +} // namespace detail + +} // namespace boost + +#endif // #ifndef BOOST_SMART_PTR_DETAIL_ATOMIC_COUNT_SPIN_HPP_INCLUDED diff --git a/include/boost/smart_ptr/detail/atomic_count_std_atomic.hpp b/include/boost/smart_ptr/detail/atomic_count_std_atomic.hpp new file mode 100644 index 0000000..55b9998 --- /dev/null +++ b/include/boost/smart_ptr/detail/atomic_count_std_atomic.hpp @@ -0,0 +1,60 @@ +#ifndef BOOST_SMART_PTR_DETAIL_ATOMIC_COUNT_STD_ATOMIC_HPP_INCLUDED +#define BOOST_SMART_PTR_DETAIL_ATOMIC_COUNT_STD_ATOMIC_HPP_INCLUDED + +// +// boost/detail/atomic_count_std_atomic.hpp +// +// atomic_count for std::atomic +// +// Copyright 2013 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 +{ + +class atomic_count +{ +public: + + explicit atomic_count( long v ): value_( v ) + { + } + + long operator++() + { + return value_.fetch_add( 1, std::memory_order_acq_rel ) + 1; + } + + long operator--() + { + return value_.fetch_sub( 1, std::memory_order_acq_rel ) - 1; + } + + operator long() const + { + return value_.load( std::memory_order_acquire ); + } + +private: + + atomic_count(atomic_count const &); + atomic_count & operator=(atomic_count const &); + + std::atomic_int_least32_t value_; +}; + +} // namespace detail + +} // namespace boost + +#endif // #ifndef BOOST_SMART_PTR_DETAIL_ATOMIC_COUNT_STD_ATOMIC_HPP_INCLUDED