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

Generated on Sat Oct 25 05:09:00 2008 for libstdc++ by  doxygen 1.5.6