From 3de36a09ac124ff2b1bf50c822259ca206f88f23 Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Tue, 6 Nov 2007 14:28:28 +0000 Subject: [PATCH] boost_shared_ptr.h: Avoid unnecessary memory barriers in _S_atomic case. 2007-11-06 Jonathan Wakely * include/tr1_impl/boost_shared_ptr.h: Avoid unnecessary memory barriers in _S_atomic case. From-SVN: r129927 --- libstdc++-v3/ChangeLog | 5 ++ .../include/tr1_impl/boost_shared_ptr.h | 53 +++++++++++++------ 2 files changed, 42 insertions(+), 16 deletions(-) diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 36c9f4bfb4f..6dcaed004d3 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,8 @@ +2007-11-06 Jonathan Wakely + + * include/tr1_impl/boost_shared_ptr.h: Avoid unnecessary memory + barriers in _S_atomic case. + 2007-11-05 Chris Jefferson Paolo Carlini diff --git a/libstdc++-v3/include/tr1_impl/boost_shared_ptr.h b/libstdc++-v3/include/tr1_impl/boost_shared_ptr.h index 55c60bc0e17..5d244aae3e7 100644 --- a/libstdc++-v3/include/tr1_impl/boost_shared_ptr.h +++ b/libstdc++-v3/include/tr1_impl/boost_shared_ptr.h @@ -94,12 +94,22 @@ _GLIBCXX_BEGIN_NAMESPACE_TR1 // Empty helper class except when the template argument is _S_mutex. template<_Lock_policy _Lp> class _Mutex_base - { }; + { + protected: + // The atomic policy uses fully-fenced builtins, single doesn't care. + enum { _S_need_barriers = 0 }; + }; template<> class _Mutex_base<_S_mutex> : public __gnu_cxx::__mutex - { }; + { + protected: + // This policy is used when atomic builtins are not available. + // The replacement atomic operations might not have the necessary + // memory barriers. + enum { _S_need_barriers = 1 }; + }; template<_Lock_policy _Lp = __default_lock_policy> class _Sp_counted_base @@ -136,14 +146,19 @@ _GLIBCXX_BEGIN_NAMESPACE_TR1 void _M_release() // nothrow { - if (__gnu_cxx::__exchange_and_add_dispatch(&_M_use_count, - -1) == 1) + if (__gnu_cxx::__exchange_and_add_dispatch(&_M_use_count, -1) == 1) { _M_dispose(); -#ifdef __GTHREADS - _GLIBCXX_READ_MEM_BARRIER; - _GLIBCXX_WRITE_MEM_BARRIER; -#endif + // There must be a memory barrier between dispose() and destroy() + // to ensure that the effects of dispose() are observed in the + // thread that runs destroy(). + // See http://gcc.gnu.org/ml/libstdc++/2005-11/msg00136.html + if (_Mutex_base<_Lp>::_S_need_barriers) + { + _GLIBCXX_READ_MEM_BARRIER; + _GLIBCXX_WRITE_MEM_BARRIER; + } + if (__gnu_cxx::__exchange_and_add_dispatch(&_M_weak_count, -1) == 1) _M_destroy(); @@ -159,18 +174,25 @@ _GLIBCXX_BEGIN_NAMESPACE_TR1 { if (__gnu_cxx::__exchange_and_add_dispatch(&_M_weak_count, -1) == 1) { -#ifdef __GTHREADS - _GLIBCXX_READ_MEM_BARRIER; - _GLIBCXX_WRITE_MEM_BARRIER; -#endif + if (_Mutex_base<_Lp>::_S_need_barriers) + { + // See _M_release(), + // destroy() must observe results of dispose() + _GLIBCXX_READ_MEM_BARRIER; + _GLIBCXX_WRITE_MEM_BARRIER; + } _M_destroy(); } } long _M_get_use_count() const // nothrow - { return _M_use_count; } // XXX is this MT safe? - + { + // No memory barrier is used here so there is no synchronization + // with other threads. + return const_cast(_M_use_count); + } + private: _Sp_counted_base(_Sp_counted_base const&); _Sp_counted_base& operator=(_Sp_counted_base const&); @@ -525,7 +547,7 @@ _GLIBCXX_BEGIN_NAMESPACE_TR1 } // - // Requirements: _Deleter' copy constructor and destructor must not throw + // Requirements: _Deleter's copy constructor and destructor must not throw // // __shared_ptr will release __p by calling __d(__p) // @@ -552,7 +574,6 @@ _GLIBCXX_BEGIN_NAMESPACE_TR1 * with @a __r. * @param __r A %__shared_ptr. * @post get() == __r.get() && use_count() == __r.use_count() - * @throw std::bad_alloc, in which case */ template __shared_ptr(const __shared_ptr<_Tp1, _Lp>& __r)