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   class bad_weak_ptr : public std::exception
00055   {
00056   public:
00057     virtual char const*
00058     what() const throw()
00059 #ifdef _GLIBCXX_INCLUDE_AS_CXX0X
00060     { return "std::bad_weak_ptr"; }
00061 #else
00062     { return "tr1::bad_weak_ptr"; }
00063 #endif
00064   };
00065 
00066   // Substitute for bad_weak_ptr object in the case of -fno-exceptions.
00067   inline void
00068   __throw_bad_weak_ptr()
00069   {
00070 #if __EXCEPTIONS
00071     throw bad_weak_ptr();
00072 #else
00073     __builtin_abort();
00074 #endif
00075   }
00076 
00077   using __gnu_cxx::_Lock_policy;
00078   using __gnu_cxx::__default_lock_policy;
00079   using __gnu_cxx::_S_single;
00080   using __gnu_cxx::_S_mutex;
00081   using __gnu_cxx::_S_atomic;
00082 
00083   // Empty helper class except when the template argument is _S_mutex.
00084   template<_Lock_policy _Lp>
00085     class _Mutex_base
00086     {
00087     protected:
00088       // The atomic policy uses fully-fenced builtins, single doesn't care.
00089       enum { _S_need_barriers = 0 };
00090     };
00091 
00092   template<>
00093     class _Mutex_base<_S_mutex>
00094     : public __gnu_cxx::__mutex
00095     {
00096     protected:
00097       // This policy is used when atomic builtins are not available.
00098       // The replacement atomic operations might not have the necessary
00099       // memory barriers.
00100       enum { _S_need_barriers = 1 };
00101     };
00102 
00103   template<_Lock_policy _Lp = __default_lock_policy>
00104     class _Sp_counted_base
00105     : public _Mutex_base<_Lp>
00106     {
00107     public:  
00108       _Sp_counted_base()
00109       : _M_use_count(1), _M_weak_count(1) { }
00110       
00111       virtual
00112       ~_Sp_counted_base() // nothrow 
00113       { }
00114   
00115       // Called when _M_use_count drops to zero, to release the resources
00116       // managed by *this.
00117       virtual void
00118       _M_dispose() = 0; // nothrow
00119       
00120       // Called when _M_weak_count drops to zero.
00121       virtual void
00122       _M_destroy() // nothrow
00123       { delete this; }
00124       
00125       virtual void*
00126       _M_get_deleter(const std::type_info&) = 0;
00127 
00128       void
00129       _M_add_ref_copy()
00130       { __gnu_cxx::__atomic_add_dispatch(&_M_use_count, 1); }
00131   
00132       void
00133       _M_add_ref_lock();
00134       
00135       void
00136       _M_release() // nothrow
00137       {
00138     if (__gnu_cxx::__exchange_and_add_dispatch(&_M_use_count, -1) == 1)
00139       {
00140         _M_dispose();
00141         // There must be a memory barrier between dispose() and destroy()
00142         // to ensure that the effects of dispose() are observed in the
00143         // thread that runs destroy().
00144         // See http://gcc.gnu.org/ml/libstdc++/2005-11/msg00136.html
00145         if (_Mutex_base<_Lp>::_S_need_barriers)
00146           {
00147             _GLIBCXX_READ_MEM_BARRIER;
00148             _GLIBCXX_WRITE_MEM_BARRIER;
00149           }
00150 
00151         if (__gnu_cxx::__exchange_and_add_dispatch(&_M_weak_count,
00152                                -1) == 1)
00153           _M_destroy();
00154       }
00155       }
00156   
00157       void
00158       _M_weak_add_ref() // nothrow
00159       { __gnu_cxx::__atomic_add_dispatch(&_M_weak_count, 1); }
00160 
00161       void
00162       _M_weak_release() // nothrow
00163       {
00164     if (__gnu_cxx::__exchange_and_add_dispatch(&_M_weak_count, -1) == 1)
00165       {
00166         if (_Mutex_base<_Lp>::_S_need_barriers)
00167           {
00168             // See _M_release(),
00169             // destroy() must observe results of dispose()
00170             _GLIBCXX_READ_MEM_BARRIER;
00171             _GLIBCXX_WRITE_MEM_BARRIER;
00172           }
00173         _M_destroy();
00174       }
00175       }
00176   
00177       long
00178       _M_get_use_count() const // nothrow
00179       {
00180         // No memory barrier is used here so there is no synchronization
00181         // with other threads.
00182         return const_cast<const volatile _Atomic_word&>(_M_use_count);
00183       }
00184 
00185     private:  
00186       _Sp_counted_base(_Sp_counted_base const&);
00187       _Sp_counted_base& operator=(_Sp_counted_base const&);
00188 
00189       _Atomic_word  _M_use_count;     // #shared
00190       _Atomic_word  _M_weak_count;    // #weak + (#shared != 0)
00191     };
00192 
00193   template<>
00194     inline void
00195     _Sp_counted_base<_S_single>::
00196     _M_add_ref_lock()
00197     {
00198       if (__gnu_cxx::__exchange_and_add_dispatch(&_M_use_count, 1) == 0)
00199     {
00200       _M_use_count = 0;
00201       __throw_bad_weak_ptr();
00202     }
00203     }
00204 
00205   template<>
00206     inline void
00207     _Sp_counted_base<_S_mutex>::
00208     _M_add_ref_lock()
00209     {
00210       __gnu_cxx::__scoped_lock sentry(*this);
00211       if (__gnu_cxx::__exchange_and_add_dispatch(&_M_use_count, 1) == 0)
00212     {
00213       _M_use_count = 0;
00214       __throw_bad_weak_ptr();
00215     }
00216     }
00217 
00218   template<> 
00219     inline void
00220     _Sp_counted_base<_S_atomic>::
00221     _M_add_ref_lock()
00222     {
00223       // Perform lock-free add-if-not-zero operation.
00224       _Atomic_word __count;
00225       do
00226     {
00227       __count = _M_use_count;
00228       if (__count == 0)
00229         __throw_bad_weak_ptr();
00230       
00231       // Replace the current counter value with the old value + 1, as
00232       // long as it's not changed meanwhile. 
00233     }
00234       while (!__sync_bool_compare_and_swap(&_M_use_count, __count,
00235                        __count + 1));
00236     }
00237 
00238 _GLIBCXX_END_NAMESPACE_TR1
00239 }

Generated on Thu Jul 23 21:16:01 2009 for libstdc++ by  doxygen 1.5.8