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