libstdc++
|
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 }