![]()
|
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. |