Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r52486 - in branches/release: boost/flyweight boost/smart_ptr/detail libs/flyweight/doc libs/smart_ptr/test
From: joaquin_at_[hidden]
Date: 2009-04-19 06:17:52


Author: joaquin
Date: 2009-04-19 06:17:50 EDT (Sun, 19 Apr 2009)
New Revision: 52486
URL: http://svn.boost.org/trac/boost/changeset/52486

Log:
merged [52456], [52457] and [52464] from trunk
Added:
   branches/release/libs/smart_ptr/test/atomic_count_test2.cpp
      - copied unchanged from r52456, /trunk/libs/smart_ptr/test/atomic_count_test2.cpp
Text files modified:
   branches/release/boost/flyweight/refcounted.hpp | 55 +++++++++++++++++++++++++++++++--------
   branches/release/boost/smart_ptr/detail/atomic_count.hpp | 5 +--
   branches/release/boost/smart_ptr/detail/atomic_count_gcc.hpp | 10 +++---
   branches/release/boost/smart_ptr/detail/atomic_count_gcc_x86.hpp | 11 +------
   branches/release/boost/smart_ptr/detail/atomic_count_pthreads.hpp | 4 +-
   branches/release/boost/smart_ptr/detail/atomic_count_sync.hpp | 4 +-
   branches/release/libs/flyweight/doc/acknowledgements.html | 14 ++++++++-
   branches/release/libs/flyweight/doc/release_notes.html | 16 ++++++++++-
   branches/release/libs/smart_ptr/test/Jamfile.v2 | 1
   9 files changed, 83 insertions(+), 37 deletions(-)

Modified: branches/release/boost/flyweight/refcounted.hpp
==============================================================================
--- branches/release/boost/flyweight/refcounted.hpp (original)
+++ branches/release/boost/flyweight/refcounted.hpp 2009-04-19 06:17:50 EDT (Sun, 19 Apr 2009)
@@ -1,4 +1,4 @@
-/* Copyright 2006-2008 Joaquin M Lopez Munoz.
+/* Copyright 2006-2009 Joaquin M Lopez Munoz.
  * 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)
@@ -22,9 +22,23 @@
 #include <boost/flyweight/tracking_tag.hpp>
 #include <boost/utility/swap.hpp>
 
-/* Refcounting tracking policy: values have an embedded ref count,
- * when this goes down to zero the element is erased from the
- * factory.
+/* Refcounting tracking policy.
+ * The implementation deserves some explanation; values are equipped with a
+ * reference count with the following semantics:
+ * - 0: newly created value.
+ * - n: (n-1) active references to the value.
+ * When the number of references reaches zero, the value can be erased. The
+ * exact protocol, however, is a little more complicated to avoid data races
+ * like the following:
+ * - Thread A detaches the last reference to x and is preempted.
+ * - Thread B looks for x, finds it and attaches a reference to it.
+ * - Thread A resumes and proceeds with erasing x, leaving a dangling
+ * reference in thread B.
+ * To cope with this, values are equipped with an additional count of threads
+ * preempted during erasure. Such a preemption are detected by the preempting
+ * thread by checking whether the reference count of the object is 1 (hence
+ * the uncommon refcounting semantics distinguishing between a newly created
+ * value and a value with no active references.
  */
 
 namespace boost{
@@ -38,22 +52,22 @@
 {
 public:
   explicit refcounted_value(const Value& x_):
- x(x_),ref(0)
+ x(x_),ref(0),del_ref(0)
   {}
   
   refcounted_value(const refcounted_value& r):
- x(r.x),ref(0)
+ x(r.x),ref(0),del_ref(0)
   {}
 
   ~refcounted_value()
   {
- /* count()!=0 most likely indicates that the flyweight factory
+ /* count()>1 most likely indicates that the flyweight factory
      * has been destructed before some of the flyweight objects using
      * it. Check for static initialization order problems with this
      * flyweight type.
      */
 
- BOOST_ASSERT(count()==0);
+ BOOST_ASSERT(count()<=1);
   }
 
   refcounted_value& operator=(const refcounted_value& r)
@@ -71,12 +85,17 @@
 #endif
 
   long count()const{return ref;}
- void add_ref()const{++ref;}
- bool release()const{return (--ref==0);}
+ long add_ref()const{return ++ref;}
+ bool release()const{return (--ref==1);}
+
+ long count_deleters()const{return del_ref;}
+ void add_deleter()const{++del_ref;}
+ void release_deleter()const{--del_ref;}
 
 private:
   Value x;
   mutable boost::detail::atomic_count ref;
+ mutable long del_ref;
 };
 
 template<typename Handle,typename TrackingHelper>
@@ -85,7 +104,15 @@
 public:
   explicit refcounted_handle(const Handle& h_):h(h_)
   {
- TrackingHelper::entry(*this).add_ref();
+ switch(TrackingHelper::entry(*this).add_ref()){
+ case 1: /* newly created object, make count()==2 (1 active reference) */
+ TrackingHelper::entry(*this).add_ref();
+ break;
+ case 2: /* object was about to be erased, increment the deleter count */
+ TrackingHelper::entry(*this).add_deleter();
+ break;
+ default:break;
+ }
   }
   
   refcounted_handle(const refcounted_handle& x):h(x.h)
@@ -116,7 +143,11 @@
 private:
   static bool check_erase(const refcounted_handle& x)
   {
- return TrackingHelper::entry(x).count()==0;
+ if(TrackingHelper::entry(x).count_deleters()){
+ TrackingHelper::entry(x).release_deleter();
+ return false;
+ }
+ return true;
   }
 
   Handle h;

Modified: branches/release/boost/smart_ptr/detail/atomic_count.hpp
==============================================================================
--- branches/release/boost/smart_ptr/detail/atomic_count.hpp (original)
+++ branches/release/boost/smart_ptr/detail/atomic_count.hpp 2009-04-19 06:17:50 EDT (Sun, 19 Apr 2009)
@@ -31,13 +31,12 @@
 // ++a;
 //
 // Effects: Atomically increments the value of a
-// Returns: nothing
+// Returns: (long) the new value of a
 //
 // --a;
 //
 // Effects: Atomically decrements the value of a
-// Returns: (long) zero if the new value of a is zero,
-// unspecified non-zero value otherwise (usually the new value)
+// 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

Modified: branches/release/boost/smart_ptr/detail/atomic_count_gcc.hpp
==============================================================================
--- branches/release/boost/smart_ptr/detail/atomic_count_gcc.hpp (original)
+++ branches/release/boost/smart_ptr/detail/atomic_count_gcc.hpp 2009-04-19 06:17:50 EDT (Sun, 19 Apr 2009)
@@ -40,21 +40,21 @@
 {
 public:
 
- explicit atomic_count(long v) : value_(v) {}
+ explicit atomic_count( long v ) : value_( v ) {}
 
- void operator++()
+ long operator++()
     {
- __atomic_add(&value_, 1);
+ return __exchange_and_add( &value_, +1 ) + 1;
     }
 
     long operator--()
     {
- return __exchange_and_add(&value_, -1) - 1;
+ return __exchange_and_add( &value_, -1 ) - 1;
     }
 
     operator long() const
     {
- return __exchange_and_add(&value_, 0);
+ return __exchange_and_add( &value_, 0 );
     }
 
 private:

Modified: branches/release/boost/smart_ptr/detail/atomic_count_gcc_x86.hpp
==============================================================================
--- branches/release/boost/smart_ptr/detail/atomic_count_gcc_x86.hpp (original)
+++ branches/release/boost/smart_ptr/detail/atomic_count_gcc_x86.hpp 2009-04-19 06:17:50 EDT (Sun, 19 Apr 2009)
@@ -25,16 +25,9 @@
 
     explicit atomic_count( long v ) : value_( static_cast< int >( v ) ) {}
 
- void operator++()
+ long operator++()
     {
- __asm__
- (
- "lock\n\t"
- "incl %0":
- "+m"( value_ ): // output (%0)
- : // inputs
- "cc" // clobbers
- );
+ return atomic_exchange_and_add( &value_, +1 ) + 1;
     }
 
     long operator--()

Modified: branches/release/boost/smart_ptr/detail/atomic_count_pthreads.hpp
==============================================================================
--- branches/release/boost/smart_ptr/detail/atomic_count_pthreads.hpp (original)
+++ branches/release/boost/smart_ptr/detail/atomic_count_pthreads.hpp 2009-04-19 06:17:50 EDT (Sun, 19 Apr 2009)
@@ -62,10 +62,10 @@
         pthread_mutex_destroy(&mutex_);
     }
 
- void operator++()
+ long operator++()
     {
         scoped_lock lock(mutex_);
- ++value_;
+ return ++value_;
     }
 
     long operator--()

Modified: branches/release/boost/smart_ptr/detail/atomic_count_sync.hpp
==============================================================================
--- branches/release/boost/smart_ptr/detail/atomic_count_sync.hpp (original)
+++ branches/release/boost/smart_ptr/detail/atomic_count_sync.hpp 2009-04-19 06:17:50 EDT (Sun, 19 Apr 2009)
@@ -31,9 +31,9 @@
 
     explicit atomic_count( long v ) : value_( v ) {}
 
- void operator++()
+ long operator++()
     {
- __sync_add_and_fetch( &value_, 1 );
+ return __sync_add_and_fetch( &value_, 1 );
     }
 
     long operator--()

Modified: branches/release/libs/flyweight/doc/acknowledgements.html
==============================================================================
--- branches/release/libs/flyweight/doc/acknowledgements.html (original)
+++ branches/release/libs/flyweight/doc/acknowledgements.html 2009-04-19 06:17:50 EDT (Sun, 19 Apr 2009)
@@ -62,6 +62,16 @@
 dire straits gentler oceans will lie.
 </p>
 
+<h2><a name="boost_1_39">Boost 1.39 release</a></h2>
+
+<p>
+Many thanks to Tim Blechmann for helping identify and solve a serious
+tread safety problem
+and to Peter Dimov for kindly extending the interface of his
+<code>boost::detail::atomic_count</code> utility to allow for the
+implementation of the fix.
+</p>
+
 <hr>
 
 <div class="prev_link"><a href="release_notes.html"><img src="prev.gif" alt="release notes" border="0"><br>
@@ -75,9 +85,9 @@
 
 <br>
 
-<p>Revised December 10th 2008</p>
+<p>Revised April 18th 2009</p>
 
-<p>&copy; Copyright 2006-2008 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz.
+<p>&copy; Copyright 2006-2009 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz.
 Distributed under the Boost Software
 License, Version 1.0. (See accompanying file <a href="../../../LICENSE_1_0.txt">
 LICENSE_1_0.txt</a> or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">

Modified: branches/release/libs/flyweight/doc/release_notes.html
==============================================================================
--- branches/release/libs/flyweight/doc/release_notes.html (original)
+++ branches/release/libs/flyweight/doc/release_notes.html 2009-04-19 06:17:50 EDT (Sun, 19 Apr 2009)
@@ -31,9 +31,21 @@
 <h2>Contents</h2>
 
 <ul>
+ <li>Boost 1.39 release</li>
   <li>Boost 1.38 release</li>
 </ul>
 
+<h2><a name="boost_1_39">Boost 1.39 release</a></h2>
+
+<p>
+<ul>
+ <li><a name="refcounted_bug">The refcounted
+ component was not thread-safe due to an incorrect implementation and could deadlock
+ under heavy usage conditions. This problem has been corrected.</a>
+ </li>
+</ul>
+</p>
+
 <h2><a name="boost_1_38">Boost 1.38 release</a></h2>
 
 <p>
@@ -57,9 +69,9 @@
 
 <br>
 
-<p>Revised August 27th 2008</p>
+<p>Revised April 7th 2009</p>
 
-<p>&copy; Copyright 2006-2008 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz.
+<p>&copy; Copyright 2006-2009 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz.
 Distributed under the Boost Software
 License, Version 1.0. (See accompanying file <a href="../../../LICENSE_1_0.txt">
 LICENSE_1_0.txt</a> or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">

Modified: branches/release/libs/smart_ptr/test/Jamfile.v2
==============================================================================
--- branches/release/libs/smart_ptr/test/Jamfile.v2 (original)
+++ branches/release/libs/smart_ptr/test/Jamfile.v2 2009-04-19 06:17:50 EDT (Sun, 19 Apr 2009)
@@ -57,5 +57,6 @@
           [ run sp_recursive_assign_rv_test.cpp ]
           [ run sp_recursive_assign2_rv_test.cpp ]
           [ compile-fail auto_ptr_lv_fail.cpp ]
+ [ run atomic_count_test2.cpp ]
         ;
 }


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk