00001 /** @file nub/refcounted.cc reference-counted base class, allowing 00002 intrusive smart pointers to be used */ 00003 /////////////////////////////////////////////////////////////////////// 00004 // 00005 // Copyright (c) 2000-2004 California Institute of Technology 00006 // Copyright (c) 2004-2007 University of Southern California 00007 // Rob Peters <rjpeters at usc dot edu> 00008 // 00009 // created: Sun Oct 22 14:40:28 2000 00010 // commit: $Id: refcounted.cc 8249 2007-04-12 06:03:40Z rjpeters $ 00011 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/nub/refcounted.cc $ 00012 // 00013 // -------------------------------------------------------------------- 00014 // 00015 // This file is part of GroovX. 00016 // [http://ilab.usc.edu/rjpeters/groovx/] 00017 // 00018 // GroovX is free software; you can redistribute it and/or modify it 00019 // under the terms of the GNU General Public License as published by 00020 // the Free Software Foundation; either version 2 of the License, or 00021 // (at your option) any later version. 00022 // 00023 // GroovX is distributed in the hope that it will be useful, but 00024 // WITHOUT ANY WARRANTY; without even the implied warranty of 00025 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00026 // General Public License for more details. 00027 // 00028 // You should have received a copy of the GNU General Public License 00029 // along with GroovX; if not, write to the Free Software Foundation, 00030 // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. 00031 // 00032 /////////////////////////////////////////////////////////////////////// 00033 00034 #ifndef GROOVX_NUB_REFCOUNTED_CC_UTC20050626084018_DEFINED 00035 #define GROOVX_NUB_REFCOUNTED_CC_UTC20050626084018_DEFINED 00036 00037 #include "refcounted.h" 00038 00039 #include "rutz/error.h" 00040 00041 #include <limits> 00042 00043 #include <typeinfo> 00044 00045 #ifndef GVX_NO_PROF 00046 #define GVX_NO_PROF 00047 #endif 00048 00049 #include "rutz/trace.h" 00050 #include "rutz/debug.h" 00051 GVX_DBG_REGISTER 00052 00053 /////////////////////////////////////////////////////////////////////// 00054 // 00055 // ref_counts member definitions 00056 // 00057 /////////////////////////////////////////////////////////////////////// 00058 00059 void* nub::ref_counts::operator new(size_t bytes) 00060 { 00061 return ::operator new(bytes); 00062 } 00063 00064 void nub::ref_counts::operator delete(void* space, size_t /*bytes*/) 00065 { 00066 ::operator delete(space); 00067 } 00068 00069 nub::ref_counts::ref_counts() throw() : 00070 m_strong(), 00071 m_weak(), 00072 m_owner_alive(true), 00073 m_volatile(false) 00074 { 00075 GVX_TRACE("nub::ref_counts::ref_counts"); 00076 } 00077 00078 nub::ref_counts::~ref_counts() throw() 00079 { 00080 GVX_TRACE("nub::ref_counts::~ref_counts"); 00081 00082 if (m_strong.atomic_get() > 0) GVX_PANIC("ref_counts object destroyed before strong refcount fell to 0"); 00083 if (m_weak.atomic_get() > 0) GVX_PANIC("ref_counts object destroyed before weak refcount fell to 0"); 00084 } 00085 00086 void nub::ref_counts::acquire_weak() throw() 00087 { 00088 GVX_TRACE("nub::ref_counts::acquire_weak"); 00089 00090 if (m_weak.atomic_incr_return() == rutz::atomic_int_t::max_value()) 00091 GVX_PANIC("weak refcount overflow"); 00092 } 00093 00094 int nub::ref_counts::release_weak() throw() 00095 { 00096 GVX_TRACE("nub::ref_counts::release_weak"); 00097 00098 const int result = m_weak.atomic_decr_return(); 00099 00100 if (result < 0) GVX_PANIC("weak refcount already 0 in release_weak()"); 00101 00102 if (result == 0) 00103 { 00104 if (m_strong.atomic_get() > 0) GVX_PANIC("weak refcount fell to 0 before strong refcount"); 00105 delete this; 00106 } 00107 00108 return result; 00109 } 00110 00111 void nub::ref_counts::acquire_strong() throw() 00112 { 00113 GVX_TRACE("nub::ref_counts::acquire_strong"); 00114 00115 if (m_volatile) GVX_PANIC("attempt to use strong refcount with volatile object"); 00116 if (m_strong.atomic_incr_return() == rutz::atomic_int_t::max_value()) 00117 GVX_PANIC("strong refcount overflow"); 00118 } 00119 00120 int nub::ref_counts::release_strong() throw() 00121 { 00122 GVX_TRACE("nub::ref_counts::release_strong"); 00123 00124 if (m_volatile) GVX_PANIC("attempt to use strong refcount with volatile object"); 00125 if (m_weak.atomic_get() == 0) GVX_PANIC("weak refcount prematurely fell to 0"); 00126 00127 const int result = m_strong.atomic_decr_return(); 00128 00129 if (result < 0) GVX_PANIC("strong refcount already 0 in release_strong()"); 00130 00131 return result; 00132 } 00133 00134 void nub::ref_counts::release_strong_no_delete() throw() 00135 { 00136 GVX_TRACE("nub::ref_counts::release_strong_no_delete"); 00137 00138 const int result = m_strong.atomic_decr_return(); 00139 00140 if (result < 0) GVX_PANIC("strong refcount already 0 in release_strong_no_delete()"); 00141 } 00142 00143 void nub::ref_counts::debug_dump() const throw() 00144 { 00145 dbg_eval_nl(0, this); 00146 dbg_eval_nl(0, m_strong.atomic_get()); 00147 dbg_eval_nl(0, m_weak.atomic_get()); 00148 dbg_eval_nl(0, m_owner_alive); 00149 } 00150 00151 /////////////////////////////////////////////////////////////////////// 00152 // 00153 // ref_counted member definitions 00154 // 00155 /////////////////////////////////////////////////////////////////////// 00156 00157 void* nub::ref_counted::operator new(size_t bytes) 00158 { 00159 GVX_TRACE("nub::ref_counted::operator new"); 00160 return ::operator new(bytes); 00161 } 00162 00163 void nub::ref_counted::operator delete(void* space, size_t /*bytes*/) 00164 { 00165 GVX_TRACE("nub::ref_counted::operator delete"); 00166 ::operator delete(space); 00167 } 00168 00169 nub::ref_counted::ref_counted() : 00170 m_ref_counts(new nub::ref_counts) 00171 { 00172 GVX_TRACE("nub::ref_counted::ref_counted"); 00173 dbg_print(7, "ref_counted ctor"); dbg_eval_nl(7, this); 00174 00175 m_ref_counts->acquire_weak(); 00176 } 00177 00178 nub::ref_counted::~ref_counted() GVX_DTOR_NOTHROW 00179 { 00180 GVX_TRACE("nub::ref_counted::~ref_counted"); 00181 dbg_print(7, "ref_counted dtor"); dbg_eval_nl(7, this); 00182 dbg_dump(7, *m_ref_counts); 00183 00184 // Must guarantee that (strong-count == 0) when the refcounted object is 00185 // destroyed. Without that guarantee, weak references will be messed up, 00186 // since they'll think that the object is still alive (i.e. strong 00187 // refcount > 0) when it actually is already destroyed. 00188 if (m_ref_counts->m_strong.atomic_get() > 0) 00189 GVX_PANIC("ref_counted object destroyed before strong refcount dropped to 0"); 00190 00191 m_ref_counts->m_owner_alive = false; 00192 m_ref_counts->release_weak(); 00193 } 00194 00195 void nub::ref_counted::mark_as_volatile() throw() 00196 { 00197 GVX_TRACE("nub::ref_counted::mark_as_volatile"); 00198 if (m_ref_counts->m_strong.atomic_get() > 0) 00199 GVX_PANIC("can't make volatile object that already has strong refs"); 00200 00201 if (m_ref_counts->m_volatile) 00202 GVX_PANIC("object already marked as volatile"); 00203 00204 m_ref_counts->m_volatile = true; 00205 } 00206 00207 void nub::ref_counted::incr_ref_count() const throw() 00208 { 00209 m_ref_counts->acquire_strong(); 00210 } 00211 00212 void nub::ref_counted::decr_ref_count() const throw() 00213 { 00214 if (m_ref_counts->release_strong() == 0) 00215 { 00216 dbg_eval_nl(3, typeid(*this).name()); 00217 delete this; 00218 } 00219 } 00220 00221 void nub::ref_counted::decr_ref_count_no_delete() const throw() 00222 { 00223 m_ref_counts->release_strong_no_delete(); 00224 } 00225 00226 bool nub::ref_counted::is_shared() const throw() 00227 { 00228 GVX_TRACE("nub::ref_counted::is_shared"); 00229 00230 return (m_ref_counts->m_strong.atomic_get() > 1) || is_not_shareable(); 00231 // We check is_not_shareable() so that volatile objects always appear 00232 // shared, so that they cannot be removed from the nub::objectdb until 00233 // they become invalid. 00234 } 00235 00236 bool nub::ref_counted::is_unshared() const throw() 00237 { 00238 GVX_TRACE("nub::ref_counted::is_unshared"); 00239 return !is_shared(); 00240 } 00241 00242 bool nub::ref_counted::is_not_shareable() const throw() 00243 { 00244 GVX_TRACE("nub::ref_counted::is_not_shareable"); 00245 return m_ref_counts->m_volatile; 00246 } 00247 00248 nub::ref_counts* nub::ref_counted::get_counts() const throw() 00249 { 00250 GVX_TRACE("nub::ref_counted::get_counts"); 00251 return m_ref_counts; 00252 } 00253 00254 int nub::ref_counted::dbg_ref_count() const throw() 00255 { 00256 return m_ref_counts->m_strong.atomic_get(); 00257 } 00258 00259 int nub::ref_counted::dbg_weak_ref_count() const throw() 00260 { 00261 return m_ref_counts->m_weak.atomic_get(); 00262 } 00263 00264 static const char __attribute__((used)) vcid_groovx_nub_refcounted_cc_utc20050626084018[] = "$Id: refcounted.cc 8249 2007-04-12 06:03:40Z rjpeters $ $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/nub/refcounted.cc $"; 00265 #endif // !GROOVX_NUB_REFCOUNTED_CC_UTC20050626084018_DEFINED