# 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 }