Home | History | Annotate | Download | only in tr1_impl
      1 // <tr1_impl/boost_sp_counted_base.h> -*- C++ -*-
      2 
      3 // Copyright (C) 2007, 2009 Free Software Foundation, Inc.
      4 //
      5 // This file is part of the GNU ISO C++ Library.  This library is free
      6 // software; you can redistribute it and/or modify it under the
      7 // terms of the GNU General Public License as published by the
      8 // Free Software Foundation; either version 3, or (at your option)
      9 // any later version.
     10 
     11 // This library is distributed in the hope that it will be useful,
     12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14 // GNU General Public License for more details.
     15 
     16 // Under Section 7 of GPL version 3, you are granted additional
     17 // permissions described in the GCC Runtime Library Exception, version
     18 // 3.1, as published by the Free Software Foundation.
     19 
     20 // You should have received a copy of the GNU General Public License and
     21 // a copy of the GCC Runtime Library Exception along with this program;
     22 // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
     23 // <http://www.gnu.org/licenses/>.
     24 
     25 //  shared_count.hpp
     26 //  Copyright (c) 2001, 2002, 2003 Peter Dimov and Multi Media Ltd.
     27 
     28 //  shared_ptr.hpp
     29 //  Copyright (C) 1998, 1999 Greg Colvin and Beman Dawes.
     30 //  Copyright (C) 2001, 2002, 2003 Peter Dimov
     31 
     32 //  weak_ptr.hpp
     33 //  Copyright (C) 2001, 2002, 2003 Peter Dimov
     34 
     35 //  enable_shared_from_this.hpp
     36 //  Copyright (C) 2002 Peter Dimov
     37 
     38 // Distributed under the Boost Software License, Version 1.0. (See
     39 // accompanying file LICENSE_1_0.txt or copy at
     40 // http://www.boost.org/LICENSE_1_0.txt)
     41 
     42 // GCC Note:  based on version 1.32.0 of the Boost library.
     43 
     44 /** @file tr1_impl/boost_sp_counted_base.h
     45  *  This is an internal header file, included by other library headers.
     46  *  You should not attempt to use it directly.
     47  */
     48 
     49 
     50 namespace std
     51 {
     52 _GLIBCXX_BEGIN_NAMESPACE_TR1
     53 
     54   class bad_weak_ptr : public std::exception
     55   {
     56   public:
     57     virtual char const*
     58     what() const throw()
     59 #ifdef _GLIBCXX_INCLUDE_AS_CXX0X
     60     { return "std::bad_weak_ptr"; }
     61 #else
     62     { return "tr1::bad_weak_ptr"; }
     63 #endif
     64   };
     65 
     66   // Substitute for bad_weak_ptr object in the case of -fno-exceptions.
     67   inline void
     68   __throw_bad_weak_ptr()
     69   {
     70 #if __EXCEPTIONS
     71     throw bad_weak_ptr();
     72 #else
     73     __builtin_abort();
     74 #endif
     75   }
     76 
     77   using __gnu_cxx::_Lock_policy;
     78   using __gnu_cxx::__default_lock_policy;
     79   using __gnu_cxx::_S_single;
     80   using __gnu_cxx::_S_mutex;
     81   using __gnu_cxx::_S_atomic;
     82 
     83   // Empty helper class except when the template argument is _S_mutex.
     84   template<_Lock_policy _Lp>
     85     class _Mutex_base
     86     {
     87     protected:
     88       // The atomic policy uses fully-fenced builtins, single doesn't care.
     89       enum { _S_need_barriers = 0 };
     90     };
     91 
     92   template<>
     93     class _Mutex_base<_S_mutex>
     94     : public __gnu_cxx::__mutex
     95     {
     96     protected:
     97       // This policy is used when atomic builtins are not available.
     98       // The replacement atomic operations might not have the necessary
     99       // memory barriers.
    100       enum { _S_need_barriers = 1 };
    101     };
    102 
    103   template<_Lock_policy _Lp = __default_lock_policy>
    104     class _Sp_counted_base
    105     : public _Mutex_base<_Lp>
    106     {
    107     public:
    108       _Sp_counted_base()
    109       : _M_use_count(1), _M_weak_count(1) { }
    110 
    111       virtual
    112       ~_Sp_counted_base() // nothrow
    113       { }
    114 
    115       // Called when _M_use_count drops to zero, to release the resources
    116       // managed by *this.
    117       virtual void
    118       _M_dispose() = 0; // nothrow
    119 
    120       // Called when _M_weak_count drops to zero.
    121       virtual void
    122       _M_destroy() // nothrow
    123       { delete this; }
    124 
    125       virtual void*
    126       _M_get_deleter(const std::type_info&) = 0;
    127 
    128       void
    129       _M_add_ref_copy()
    130       { __gnu_cxx::__atomic_add_dispatch(&_M_use_count, 1); }
    131 
    132       void
    133       _M_add_ref_lock();
    134 
    135       void
    136       _M_release() // nothrow
    137       {
    138 	if (__gnu_cxx::__exchange_and_add_dispatch(&_M_use_count, -1) == 1)
    139 	  {
    140 	    _M_dispose();
    141 	    // There must be a memory barrier between dispose() and destroy()
    142 	    // to ensure that the effects of dispose() are observed in the
    143 	    // thread that runs destroy().
    144 	    // See http://gcc.gnu.org/ml/libstdc++/2005-11/msg00136.html
    145 	    if (_Mutex_base<_Lp>::_S_need_barriers)
    146 	      {
    147 	        _GLIBCXX_READ_MEM_BARRIER;
    148 	        _GLIBCXX_WRITE_MEM_BARRIER;
    149 	      }
    150 
    151 	    if (__gnu_cxx::__exchange_and_add_dispatch(&_M_weak_count,
    152 						       -1) == 1)
    153 	      _M_destroy();
    154 	  }
    155       }
    156 
    157       void
    158       _M_weak_add_ref() // nothrow
    159       { __gnu_cxx::__atomic_add_dispatch(&_M_weak_count, 1); }
    160 
    161       void
    162       _M_weak_release() // nothrow
    163       {
    164 	if (__gnu_cxx::__exchange_and_add_dispatch(&_M_weak_count, -1) == 1)
    165 	  {
    166 	    if (_Mutex_base<_Lp>::_S_need_barriers)
    167 	      {
    168 	        // See _M_release(),
    169 	        // destroy() must observe results of dispose()
    170 	        _GLIBCXX_READ_MEM_BARRIER;
    171 	        _GLIBCXX_WRITE_MEM_BARRIER;
    172 	      }
    173 	    _M_destroy();
    174 	  }
    175       }
    176 
    177       long
    178       _M_get_use_count() const // nothrow
    179       {
    180         // No memory barrier is used here so there is no synchronization
    181         // with other threads.
    182         return const_cast<const volatile _Atomic_word&>(_M_use_count);
    183       }
    184 
    185     private:
    186       _Sp_counted_base(_Sp_counted_base const&);
    187       _Sp_counted_base& operator=(_Sp_counted_base const&);
    188 
    189       _Atomic_word  _M_use_count;     // #shared
    190       _Atomic_word  _M_weak_count;    // #weak + (#shared != 0)
    191     };
    192 
    193   template<>
    194     inline void
    195     _Sp_counted_base<_S_single>::
    196     _M_add_ref_lock()
    197     {
    198       if (__gnu_cxx::__exchange_and_add_dispatch(&_M_use_count, 1) == 0)
    199 	{
    200 	  _M_use_count = 0;
    201 	  __throw_bad_weak_ptr();
    202 	}
    203     }
    204 
    205   template<>
    206     inline void
    207     _Sp_counted_base<_S_mutex>::
    208     _M_add_ref_lock()
    209     {
    210       __gnu_cxx::__scoped_lock sentry(*this);
    211       if (__gnu_cxx::__exchange_and_add_dispatch(&_M_use_count, 1) == 0)
    212 	{
    213 	  _M_use_count = 0;
    214 	  __throw_bad_weak_ptr();
    215 	}
    216     }
    217 
    218   template<>
    219     inline void
    220     _Sp_counted_base<_S_atomic>::
    221     _M_add_ref_lock()
    222     {
    223       // Perform lock-free add-if-not-zero operation.
    224       _Atomic_word __count;
    225       do
    226 	{
    227 	  __count = _M_use_count;
    228 	  if (__count == 0)
    229 	    __throw_bad_weak_ptr();
    230 
    231 	  // Replace the current counter value with the old value + 1, as
    232 	  // long as it's not changed meanwhile.
    233 	}
    234       while (!__sync_bool_compare_and_swap(&_M_use_count, __count,
    235 					   __count + 1));
    236     }
    237 
    238 _GLIBCXX_END_NAMESPACE_TR1
    239 }
    240