|
ref.h00001 // 00002 // ref.h --- definitions of the reference counting classes 00003 // 00004 // Copyright (C) 1996 Limit Point Systems, Inc. 00005 // 00006 // Author: Curtis Janssen <cljanss@limitpt.com> 00007 // Maintainer: LPS 00008 // 00009 // This file is part of the SC Toolkit. 00010 // 00011 // The SC Toolkit is free software; you can redistribute it and/or modify 00012 // it under the terms of the GNU Library General Public License as published by 00013 // the Free Software Foundation; either version 2, or (at your option) 00014 // any later version. 00015 // 00016 // The SC Toolkit is distributed in the hope that it will be useful, 00017 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00019 // GNU Library General Public License for more details. 00020 // 00021 // You should have received a copy of the GNU Library General Public License 00022 // along with the SC Toolkit; see the file COPYING.LIB. If not, write to 00023 // the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 00024 // 00025 // The U.S. Government is granted a limited license as per AL 91-7. 00026 // 00027 00028 // This is the main include file for the reference counting classes. 00029 // This includes two other files: reftmpl.h and refmacr.h. The 00030 // former is a template declaration for the reference counted classes 00031 // and the latter is generated from the former by a perl script and 00032 // provides CPP macros that declare reference counting classes. 00033 // 00034 // The behaviour of the package can be modified with the following five 00035 // macros, each of which should be undefined, 0, or 1: 00036 // 00037 // REF_CHECK_STACK: If this is 1 referenced objects are checked to see if they 00038 // reside on the stack, in which case storage for the object is not managed, 00039 // if management is enabled. This feature can be confused by multiple threads 00040 // and memory checking libraries. 00041 // 00042 // REF_MANAGE: If this is 1 the manage and unmanage members are enabled. 00043 // 00044 // REF_CHECK_MAX_NREF: If this is 1 the reference count is checked before 00045 // it is incremented to make sure it isn't too big. 00046 // 00047 // REF_CHECK_MIN_NREF: If this is 1 the reference count is checked before 00048 // it is decremented to make sure it isn't already zero. 00049 // 00050 // REF_USE_LOCKS: If this is 1 then critical regions are locked before they 00051 // are entered. This prevents erroneous behavior when multiple threads 00052 // share reference counted objects. This will slow down certain operations, 00053 // so it should be set to 0 if your application does not need to be thread 00054 // safe. 00055 // 00056 // If a macro is undefined, then the behaviour is architecture 00057 // dependent--usually, the macro will be set to 1 in this case. 00058 // For maximum efficiency and for normal operation after the program is 00059 // debugged, compile with all of the above macros defined to zero. 00060 // This can also be done with -DREF_OPTIMIZE. 00061 // 00062 // An include file can be used to set these options as well. This has 00063 // the advantage that dependency checking will force an automatic 00064 // recompile of all affected files if the options change. The file 00065 // <scconfig.h> will be include if -DHAVE_CONFIG_H is specified. 00066 // 00067 // Note that all source code that uses references must be compiled with 00068 // the same value REF_MANAGE. Changing this can change the storage layout 00069 // and the interpretation of the reference count data. 00070 00071 00072 #ifdef __GNUC__ 00073 #pragma interface 00074 #endif 00075 00076 #ifndef _util_ref_ref_h 00077 #define _util_ref_ref_h 00078 00079 #include <iostream> 00080 #include <stdlib.h> 00081 #include <limits.h> 00082 00083 #include <util/ref/identity.h> 00084 00085 #ifdef HAVE_CONFIG_H 00086 #include <scconfig.h> 00087 #endif 00088 00089 #ifdef REF_OPTIMIZE 00090 #ifndef REF_CHECK_STACK 00091 # define REF_CHECK_STACK 0 00092 #endif 00093 #ifndef REF_MANAGE 00094 # define REF_MANAGE 0 00095 #endif 00096 #ifndef REF_CHECK_MAX_NREF 00097 # define REF_CHECK_MAX_NREF 0 00098 #endif 00099 #ifndef REF_CHECK_MIN_NREF 00100 # define REF_CHECK_MIN_NREF 0 00101 #endif 00102 #endif 00103 00104 #ifdef SUNMOS 00105 #ifndef REF_CHECK_STACK 00106 #define REF_CHECK_STACK 0 00107 #endif 00108 #else 00109 #ifndef REF_CHECK_STACK 00110 #define REF_CHECK_STACK 0 00111 #endif 00112 #endif 00113 00114 #ifndef REF_MANAGE 00115 #define REF_MANAGE 1 00116 #endif 00117 00118 #ifndef REF_CHECK_MAX_NREF 00119 #define REF_CHECK_MAX_NREF 1 00120 #endif 00121 00122 #ifndef REF_CHECK_MIN_NREF 00123 #define REF_CHECK_MIN_NREF 1 00124 #endif 00125 00126 #ifndef REF_USE_LOCKS 00127 # if HAVE_STHREAD || HAVE_CREATETHREAD || HAVE_PTHREAD 00128 # define REF_USE_LOCKS 1 00129 # endif 00130 #endif 00131 00132 #if REF_CHECK_STACK 00133 #include <unistd.h> 00134 #ifndef HAVE_SBRK_DEC 00135 extern "C" void * sbrk(ssize_t); 00136 #endif 00137 #define DO_REF_CHECK_STACK(p) (((void*) (p) > sbrk(0)) && (p)->managed()) 00138 #else // REF_CHECK_STACK 00139 #define DO_REF_CHECK_STACK(p) (0) 00140 #endif // REF_CHECK_STACK 00141 00142 #if REF_MANAGE 00143 #define DO_REF_UNMANAGE(p) ((p)->unmanage()) 00144 #else // REF_MANAGE 00145 #define DO_REF_UNMANAGE(p) 00146 #endif // REF_MANAGE 00147 00148 #if REF_USE_LOCKS 00149 #define __REF_LOCK__(p) p->lock_ptr() 00150 #define __REF_UNLOCK__(p) p->unlock_ptr() 00151 #define __REF_INITLOCK__() ref_lock_ = 0xff 00152 #else 00153 #define __REF_LOCK__(p) 00154 #define __REF_UNLOCK__(p) 00155 #define __REF_INITLOCK__() 00156 #endif 00157 00158 namespace sc { 00159 00160 typedef unsigned long refcount_t; 00161 00186 class RefCount: public Identity { 00187 private: 00188 #if REF_MANAGE 00189 # define REF_MAX_NREF (UINT_MAX - 1) 00190 # define REF_MANAGED_CODE UINT_MAX 00191 #else 00192 # define REF_MAX_NREF UINT_MAX 00193 #endif 00194 unsigned int _reference_count_; 00195 #if REF_USE_LOCKS 00196 unsigned char ref_lock_; 00197 #endif 00198 00199 void error(const char*) const; 00200 void too_many_refs() const; 00201 void not_enough_refs() const; 00202 protected: 00203 RefCount(): _reference_count_(0) { 00204 __REF_INITLOCK__(); 00205 //std::cout << "ref_lock_ = " << (int) ref_lock_ << std::endl; 00206 } 00207 RefCount(const RefCount&): _reference_count_(0) { 00208 __REF_INITLOCK__(); 00209 //std::cout << "ref_lock_ = " << (int) ref_lock_ << std::endl; 00210 } 00211 00212 // Assigment should not overwrite the reference count. 00213 RefCount& operator=(const RefCount&) { return *this; } 00214 public: 00215 virtual ~RefCount(); 00216 00218 int lock_ptr() const; 00220 int unlock_ptr() const; 00221 00223 void use_locks(bool inVal); 00224 00226 refcount_t nreference() const { 00227 # if REF_MANAGE 00228 if (!managed()) return 1; 00229 # endif 00230 return _reference_count_; 00231 } 00232 00234 refcount_t reference() { 00235 # if REF_MANAGE 00236 if (!managed()) return 1; 00237 # endif 00238 __REF_LOCK__(this); 00239 # if REF_CHECK_MAX_NREF 00240 if (_reference_count_ >= REF_MAX_NREF) too_many_refs(); 00241 # endif 00242 _reference_count_++; 00243 refcount_t r = _reference_count_; 00244 __REF_UNLOCK__(this); 00245 return r; 00246 } 00247 00249 refcount_t dereference() { 00250 # if REF_MANAGE 00251 if (!managed()) return 1; 00252 # endif 00253 __REF_LOCK__(this); 00254 # if REF_CHECK_MIN_NREF 00255 if (_reference_count_ == 0) not_enough_refs(); 00256 # endif 00257 _reference_count_--; 00258 refcount_t r = _reference_count_; 00259 __REF_UNLOCK__(this); 00260 return r; 00261 } 00262 00263 #if REF_MANAGE 00264 int managed() const { 00265 return _reference_count_ != REF_MANAGED_CODE; 00266 } 00272 void unmanage() { 00273 _reference_count_ = REF_MANAGED_CODE; 00274 } 00275 #else // REF_MANAGE 00276 00277 int managed() const { return 1; } 00278 #endif // REF_MANAGE 00279 }; 00280 00284 class RefBase { 00285 protected: 00287 void warn ( const char * msg) const; 00289 void warn_ref_to_stack() const; 00291 void warn_skip_stack_delete() const; 00293 void warn_bad_ref_count() const; 00295 void ref_info(RefCount*p,std::ostream& os) const; 00296 void ref_info(std::ostream& os) const; 00297 void check_pointer() const; 00298 void reference(RefCount *); 00299 int dereference(RefCount *); 00300 public: 00301 virtual ~RefBase(); 00303 virtual RefCount* parentpointer() const = 0; 00306 void require_nonnull() const; 00307 }; 00308 00322 template <class T> 00323 class Ref : public RefBase { 00324 private: 00325 T* p; 00326 public: 00328 Ref(): p(0) {} 00330 Ref(T*a) : p(0) 00331 { 00332 if (a) { 00333 p = a; 00334 reference(p); 00335 } 00336 } 00338 Ref(const Ref<T> &a) : p(0) 00339 { 00340 if (a.pointer()) { 00341 p = a.pointer(); 00342 reference(p); 00343 } 00344 } 00346 template <class A> Ref(const Ref<A> &a): p(0) 00347 { 00348 if (a.pointer()) { 00349 p = a.pointer(); 00350 reference(p); 00351 } 00352 } 00353 // /** Create a reference to the object a. Do a 00354 // dynamic_cast to convert a to the appropiate type. */ 00355 // Ref(const RefBase&a) { 00356 // p = dynamic_cast<T*>(a.parentpointer()); 00357 // reference(p); 00358 // } 00359 // /** Create a reference to the object a. Do a 00360 // dynamic_cast to convert a to the appropiate type. */ 00361 // Ref(RefCount*a): p(0) { 00362 // operator<<(a); 00363 // } 00366 ~Ref() 00367 { 00368 clear(); 00369 } 00372 T* operator->() const { return p; } 00374 T* pointer() const { return p; } 00376 RefCount *parentpointer() const { return p; } 00377 00378 operator T*() const { return p; } 00381 T& operator *() const { return *p; }; 00384 int null() const { return p == 0; } 00386 int nonnull() const { return p != 0; } 00389 template <class A> int operator==(const Ref<A>&a) const 00390 { return eq(p,a.pointer()); } 00391 template <class A> int operator>=(const Ref<A>&a) const 00392 { return ge(p,a.pointer()); } 00393 template <class A> int operator<=(const Ref<A>&a) const 00394 { return le(p,a.pointer()); } 00395 template <class A> int operator>(const Ref<A>&a) const 00396 { return gt(p,a.pointer()); } 00397 template <class A> int operator<(const Ref<A>&a) const 00398 { return lt(p,a.pointer()); } 00399 template <class A> int operator!=(const Ref<A>&a) const 00400 { return ne(p,a.pointer()); } 00403 int compare(const Ref<T> &a) const { 00404 return eq(p,a.p)?0:((lt(p,a.p)?-1:1)); 00405 } 00407 void clear() 00408 { 00409 if (p) { 00410 int ref = dereference(p); 00411 if (ref == 0) 00412 delete p; 00413 p = 0; 00414 } 00415 } 00417 Ref<T>& operator=(const Ref<T> & c) 00418 { 00419 T *cp = c.pointer(); 00420 if (cp) { 00421 cp->reference(); 00422 clear(); 00423 p=cp; 00424 } 00425 else { 00426 clear(); 00427 } 00428 return *this; 00429 } 00431 template <class A> Ref<T>& operator=(const Ref<A> & c) 00432 { 00433 A *cp = c.pointer(); 00434 if (cp) { 00435 cp->reference(); 00436 clear(); 00437 p=cp; 00438 } 00439 else { 00440 clear(); 00441 } 00442 return *this; 00443 } 00445 Ref<T>& operator<<(const RefBase&a) { 00446 T* cr = dynamic_cast<T*>(a.parentpointer()); 00447 if (cr) { 00448 reference(cr); 00449 clear(); 00450 } 00451 p = cr; 00452 return *this; 00453 } 00457 Ref<T>& operator<<(RefCount *a) { 00458 T* cr = dynamic_cast<T*>(a); 00459 if (cr) assign_pointer(cr); 00460 else if (a && a->nreference() <= 0) delete a; 00461 return *this; 00462 } 00464 Ref<T>& operator=(T* cr) 00465 { 00466 assign_pointer(cr); 00467 return *this; 00468 } 00470 void assign_pointer(T* cr) 00471 { 00472 if (cr) { 00473 if (DO_REF_CHECK_STACK(cr)) { 00474 DO_REF_UNMANAGE(cr); 00475 warn_ref_to_stack(); 00476 } 00477 cr->reference(); 00478 } 00479 clear(); 00480 p = cr; 00481 } 00483 void check_pointer() const 00484 { 00485 if (p && p->nreference() <= 0) { 00486 warn_bad_ref_count(); 00487 } 00488 } 00490 void ref_info(std::ostream& os) const 00491 { 00492 RefBase::ref_info(p,os); 00493 } 00495 void warn(const char*s) const { RefBase::warn(s); } 00496 }; 00497 00498 } 00499 00500 #endif 00501 00502 // /////////////////////////////////////////////////////////////////////////// 00503 00504 // Local Variables: 00505 // mode: c++ 00506 // c-file-style: "CLJ" 00507 // End: Generated at Fri Jan 10 08:14:09 2003 for MPQC 2.1.3 using the documentation package Doxygen 1.2.14. |