00001
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
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
00054
00055
00056
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 )
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
00152
00153
00154
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 )
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
00185
00186
00187
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
00232
00233
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 10065 2007-04-12 05:54:56Z rjpeters $ $HeadURL: file:
00265 #endif // !GROOVX_NUB_REFCOUNTED_CC_UTC20050626084018_DEFINED