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