boost_sp_counted_base.h

Go to the documentation of this file.
00001 // <tr1_impl/boost_sp_counted_base.h> -*- C++ -*-
00002 
00003 // Copyright (C) 2007, 2009 Free Software Foundation, Inc.
00004 //
00005 // This file is part of the GNU ISO C++ Library.  This library is free
00006 // software; you can redistribute it and/or modify it under the
00007 // terms of the GNU General Public License as published by the
00008 // Free Software Foundation; either version 3, or (at your option)
00009 // any later version.
00010 
00011 // This library is distributed in the hope that it will be useful,
00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 // GNU General Public License for more details.
00015 
00016 // Under Section 7 of GPL version 3, you are granted additional
00017 // permissions described in the GCC Runtime Library Exception, version
00018 // 3.1, as published by the Free Software Foundation.
00019 
00020 // You should have received a copy of the GNU General Public License and
00021 // a copy of the GCC Runtime Library Exception along with this program;
00022 // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
00023 // <http://www.gnu.org/licenses/>.
00024 
00025 //  shared_count.hpp
00026 //  Copyright (c) 2001, 2002, 2003 Peter Dimov and Multi Media Ltd.
00027 
00028 //  shared_ptr.hpp
00029 //  Copyright (C) 1998, 1999 Greg Colvin and Beman Dawes.
00030 //  Copyright (C) 2001, 2002, 2003 Peter Dimov
00031 
00032 //  weak_ptr.hpp
00033 //  Copyright (C) 2001, 2002, 2003 Peter Dimov
00034 
00035 //  enable_shared_from_this.hpp
00036 //  Copyright (C) 2002 Peter Dimov
00037 
00038 // Distributed under the Boost Software License, Version 1.0. (See
00039 // accompanying file LICENSE_1_0.txt or copy at
00040 // http://www.boost.org/LICENSE_1_0.txt)
00041 
00042 // GCC Note:  based on version 1.32.0 of the Boost library.
00043 
00044 /** @file tr1_impl/boost_sp_counted_base.h
00045  *  This is an internal header file, included by other library headers.
00046  *  You should not attempt to use it directly.
00047  */
00048 
00049 
00050 namespace std
00051 {
00052 _GLIBCXX_BEGIN_NAMESPACE_TR1
00053 
00054  /**
00055    *  @brief  Exception possibly thrown by @c shared_ptr.
00056    *  @ingroup exceptions
00057    */
00058   class bad_weak_ptr : public std::exception
00059   {
00060   public:
00061     virtual char const*
00062     what() const throw()
00063 #ifdef _GLIBCXX_INCLUDE_AS_CXX0X
00064     { return "std::bad_weak_ptr"; }
00065 #else
00066     { return "tr1::bad_weak_ptr"; }
00067 #endif
00068   };
00069 
00070   // Substitute for bad_weak_ptr object in the case of -fno-exceptions.
00071   inline void
00072   __throw_bad_weak_ptr()
00073   {
00074 #if __EXCEPTIONS
00075     throw bad_weak_ptr();
00076 #else
00077     __builtin_abort();
00078 #endif
00079   }
00080 
00081   using __gnu_cxx::_Lock_policy;
00082   using __gnu_cxx::__default_lock_policy;
00083   using __gnu_cxx::_S_single;
00084   using __gnu_cxx::_S_mutex;
00085   using __gnu_cxx::_S_atomic;
00086 
00087   // Empty helper class except when the template argument is _S_mutex.
00088   template<_Lock_policy _Lp>
00089     class _Mutex_base
00090     {
00091     protected:
00092       // The atomic policy uses fully-fenced builtins, single doesn't care.
00093       enum { _S_need_barriers = 0 };
00094     };
00095 
00096   template<>
00097     class _Mutex_base<_S_mutex>
00098     : public __gnu_cxx::__mutex
00099     {
00100     protected:
00101       // This policy is used when atomic builtins are not available.
00102       // The replacement atomic operations might not have the necessary
00103       // memory barriers.
00104       enum { _S_need_barriers = 1 };
00105     };
00106 
00107   template<_Lock_policy _Lp = __default_lock_policy>
00108     class _Sp_counted_base
00109     : public _Mutex_base<_Lp>
00110     {
00111     public:  
00112       _Sp_counted_base()
00113       : _M_use_count(1), _M_weak_count(1) { }
00114       
00115       virtual
00116       ~_Sp_counted_base() // nothrow 
00117       { }
00118   
00119       // Called when _M_use_count drops to zero, to release the resources
00120       // managed by *this.
00121       virtual void
00122       _M_dispose() = 0; // nothrow
00123       
00124       // Called when _M_weak_count drops to zero.
00125       virtual void
00126       _M_destroy() // nothrow
00127       { delete this; }
00128       
00129       virtual void*
00130       _M_get_deleter(const std::type_info&) = 0;
00131 
00132       void
00133       _M_add_ref_copy()
00134       { __gnu_cxx::__atomic_add_dispatch(&_M_use_count, 1); }
00135   
00136       void
00137       _M_add_ref_lock();
00138       
00139       void
00140       _M_release() // nothrow
00141       {
00142     if (__gnu_cxx::__exchange_and_add_dispatch(&_M_use_count, -1) == 1)
00143       {
00144         _M_dispose();
00145         // There must be a memory barrier between dispose() and destroy()
00146         // to ensure that the effects of dispose() are observed in the
00147         // thread that runs destroy().
00148         // See http://gcc.gnu.org/ml/libstdc++/2005-11/msg00136.html
00149         if (_Mutex_base<_Lp>::_S_need_barriers)
00150           {
00151             _GLIBCXX_READ_MEM_BARRIER;
00152             _GLIBCXX_WRITE_MEM_BARRIER;
00153           }
00154 
00155         if (__gnu_cxx::__exchange_and_add_dispatch(&_M_weak_count,
00156                                -1) == 1)
00157           _M_destroy();
00158       }
00159       }
00160   
00161       void
00162       _M_weak_add_ref() // nothrow
00163       { __gnu_cxx::__atomic_add_dispatch(&_M_weak_count, 1); }
00164 
00165       void
00166       _M_weak_release() // nothrow
00167       {
00168     if (__gnu_cxx::__exchange_and_add_dispatch(&_M_weak_count, -1) == 1)
00169       {
00170         if (_Mutex_base<_Lp>::_S_need_barriers)
00171           {
00172             // See _M_release(),
00173             // destroy() must observe results of dispose()
00174             _GLIBCXX_READ_MEM_BARRIER;
00175             _GLIBCXX_WRITE_MEM_BARRIER;
00176           }
00177         _M_destroy();
00178       }
00179       }
00180   
00181       long
00182       _M_get_use_count() const // nothrow
00183       {
00184         // No memory barrier is used here so there is no synchronization
00185         // with other threads.
00186         return const_cast<const volatile _Atomic_word&>(_M_use_count);
00187       }
00188 
00189     private:  
00190       _Sp_counted_base(_Sp_counted_base const&);
00191       _Sp_counted_base& operator=(_Sp_counted_base const&);
00192 
00193       _Atomic_word  _M_use_count;     // #shared
00194       _Atomic_word  _M_weak_count;    // #weak + (#shared != 0)
00195     };
00196 
00197   template<>
00198     inline void
00199     _Sp_counted_base<_S_single>::
00200     _M_add_ref_lock()
00201     {
00202       if (__gnu_cxx::__exchange_and_add_dispatch(&_M_use_count, 1) == 0)
00203     {
00204       _M_use_count = 0;
00205       __throw_bad_weak_ptr();
00206     }
00207     }
00208 
00209   template<>
00210     inline void
00211     _Sp_counted_base<_S_mutex>::
00212     _M_add_ref_lock()
00213     {
00214       __gnu_cxx::__scoped_lock sentry(*this);
00215       if (__gnu_cxx::__exchange_and_add_dispatch(&_M_use_count, 1) == 0)
00216     {
00217       _M_use_count = 0;
00218       __throw_bad_weak_ptr();
00219     }
00220     }
00221 
00222   template<> 
00223     inline void
00224     _Sp_counted_base<_S_atomic>::
00225     _M_add_ref_lock()
00226     {
00227       // Perform lock-free add-if-not-zero operation.
00228       _Atomic_word __count;
00229       do
00230     {
00231       __count = _M_use_count;
00232       if (__count == 0)
00233         __throw_bad_weak_ptr();
00234       
00235       // Replace the current counter value with the old value + 1, as
00236       // long as it's not changed meanwhile. 
00237     }
00238       while (!__sync_bool_compare_and_swap(&_M_use_count, __count,
00239                        __count + 1));
00240     }
00241 
00242 _GLIBCXX_END_NAMESPACE_TR1
00243 }