Main Page Class Hierarchy Compound List File List Compound Members Related Pages

# ref.h

    00001 //
    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 #ifndef REF_ALWAYS_USE_LOCKS
    00133 #  define REF_ALWAYS_USE_LOCKS 1
    00134 #endif
    00135
    00136 #if REF_CHECK_STACK
    00137 #include <unistd.h>
    00138 #ifndef HAVE_SBRK_DEC
    00139 extern "C" void * sbrk(ssize_t);
    00140 #endif
    00141 #define DO_REF_CHECK_STACK(p) (((void*) (p) > sbrk(0)) && (p)->managed())
    00142 #else // REF_CHECK_STACK
    00143 #define DO_REF_CHECK_STACK(p) (0)
    00144 #endif // REF_CHECK_STACK
    00145
    00146 #if REF_MANAGE
    00147 #define DO_REF_UNMANAGE(p) ((p)->unmanage())
    00148 #else // REF_MANAGE
    00149 #define DO_REF_UNMANAGE(p)
    00150 #endif // REF_MANAGE
    00151
    00152 #if REF_USE_LOCKS
    00153 #define __REF_LOCK__(p) p->lock_ptr()
    00154 #define __REF_UNLOCK__(p) p->unlock_ptr()
    00155 #if REF_ALWAYS_USE_LOCKS
    00156 #define __REF_INITLOCK__() use_locks(true)
    00157 #else
    00158 #define __REF_INITLOCK__() ref_lock_ = 0xff
    00159 #endif
    00160 #else
    00161 #define __REF_LOCK__(p)
    00162 #define __REF_UNLOCK__(p)
    00163 #define __REF_INITLOCK__()
    00164 #endif
    00165
    00166 namespace sc {
    00167
    00168 typedef unsigned long refcount_t;
    00169
    00194 class RefCount: public Identity {
    00195   private:
    00196 #if REF_MANAGE
    00197 #  define REF_MAX_NREF (UINT_MAX - 1)
    00198 #  define REF_MANAGED_CODE UINT_MAX
    00199 #else
    00200 #  define REF_MAX_NREF UINT_MAX
    00201 #endif
    00202     unsigned int _reference_count_;
    00203 #if REF_USE_LOCKS
    00204     unsigned char ref_lock_;
    00205 #endif
    00206
    00207     void error(const char*) const;
    00208     void too_many_refs() const;
    00209     void not_enough_refs() const;
    00210   protected:
    00211     RefCount(): _reference_count_(0) {
    00212         __REF_INITLOCK__();
    00213         //std::cout << "ref_lock_ = " << (int) ref_lock_ << std::endl;
    00214       }
    00215     RefCount(const RefCount&): _reference_count_(0) {
    00216         __REF_INITLOCK__();
    00217         //std::cout << "ref_lock_ = " << (int) ref_lock_ << std::endl;
    00218       }
    00219
    00220     // Assigment should not overwrite the reference count.
    00221     RefCount& operator=(const RefCount&) { return *this; }
    00222   public:
    00223     virtual ~RefCount();
    00224
    00226     int lock_ptr() const;
    00228     int unlock_ptr() const;
    00229
    00231     void use_locks(bool inVal);
    00232
    00234     refcount_t nreference() const {
    00235 #       if REF_MANAGE
    00236         if (!managed()) return 1;
    00237 #       endif
    00238         return _reference_count_;
    00239       }
    00240
    00242     refcount_t reference() {
    00243 #       if REF_MANAGE
    00244         if (!managed()) return 1;
    00245 #       endif
    00246         __REF_LOCK__(this);
    00247 #       if REF_CHECK_MAX_NREF
    00248         if (_reference_count_ >= REF_MAX_NREF) too_many_refs();
    00249 #       endif
    00250         _reference_count_++;
    00251         refcount_t r = _reference_count_;
    00252         __REF_UNLOCK__(this);
    00253         return r;
    00254       }
    00255
    00257     refcount_t dereference() {
    00258 #       if REF_MANAGE
    00259         if (!managed()) return 1;
    00260 #       endif
    00261         __REF_LOCK__(this);
    00262 #       if REF_CHECK_MIN_NREF
    00263         if (_reference_count_ == 0) not_enough_refs();
    00264 #       endif
    00265         _reference_count_--;
    00266         refcount_t r = _reference_count_;
    00267         __REF_UNLOCK__(this);
    00268         return r;
    00269       }
    00270
    00271 #if REF_MANAGE
    00272     int managed() const {
    00273         return _reference_count_ != REF_MANAGED_CODE;
    00274       }
    00280     void unmanage() {
    00281         _reference_count_ = REF_MANAGED_CODE;
    00282       }
    00283 #else // REF_MANAGE
    00284
    00285     int managed() const { return 1; }
    00286 #endif // REF_MANAGE
    00287 };
    00288
    00292 class RefBase {
    00293   protected:
    00295     void warn ( const char * msg) const;
    00297     void warn_ref_to_stack() const;
    00299     void warn_skip_stack_delete() const;
    00301     void warn_bad_ref_count() const;
    00303     void ref_info(RefCount*p,std::ostream& os) const;
    00304     void ref_info(std::ostream& os) const;
    00305     void check_pointer() const;
    00306     void reference(RefCount *);
    00307     int dereference(RefCount *);
    00308   public:
    00309     virtual ~RefBase();
    00311     virtual RefCount* parentpointer() const = 0;
    00314     void require_nonnull() const;
    00315 };
    00316
    00330 template <class T>
    00331 class  Ref  : public RefBase {
    00332   private:
    00333     T* p;
    00334   public:
    00336     Ref(): p(0) {}
    00338     Ref(T*a) : p(0)
    00339     {
    00340       if (a) {
    00341           p = a;
    00342           reference(p);
    00343         }
    00344     }
    00346     Ref(const Ref<T> &a) : p(0)
    00347     {
    00348       if (a.pointer()) {
    00349           p = a.pointer();
    00350           reference(p);
    00351         }
    00352     }
    00354     template <class A> Ref(const Ref<A> &a): p(0)
    00355     {
    00356       if (a.pointer()) {
    00357           p = a.pointer();
    00358           reference(p);
    00359         }
    00360     }
    00361 //      /** Create a reference to the object a.  Do a
    00362 //          dynamic_cast to convert a to the appropiate type. */
    00363 //      Ref(const RefBase&a) {
    00364 //          p = dynamic_cast<T*>(a.parentpointer());
    00365 //          reference(p);
    00366 //        }
    00367 //      /** Create a reference to the object a.  Do a
    00368 //          dynamic_cast to convert a to the appropiate type. */
    00369 //      Ref(RefCount*a): p(0) {
    00370 //        operator<<(a);
    00371 //        }
    00374     ~Ref()
    00375     {
    00376       clear();
    00377     }
    00380     T* operator->() const { return p; }
    00382     T* pointer() const { return p; }
    00384     RefCount *parentpointer() const { return p; }
    00385
    00386     operator T*() const { return p; }
    00389     T& operator *() const { return *p; };
    00392     int null() const { return p == 0; }
    00394     int nonnull() const { return p != 0; }
    00397     template <class A> int operator==(const Ref<A>&a) const
    00398         { return eq(p,a.pointer()); }
    00399     template <class A> int operator>=(const Ref<A>&a) const
    00400         { return ge(p,a.pointer()); }
    00401     template <class A> int operator<=(const Ref<A>&a) const
    00402         { return le(p,a.pointer()); }
    00403     template <class A> int operator>(const Ref<A>&a) const
    00404         { return gt(p,a.pointer()); }
    00405     template <class A> int operator<(const Ref<A>&a) const
    00406         { return lt(p,a.pointer()); }
    00407     template <class A> int operator!=(const Ref<A>&a) const
    00408         { return ne(p,a.pointer()); }
    00411     int compare(const Ref<T> &a) const {
    00412       return eq(p,a.p)?0:((lt(p,a.p)?-1:1));
    00413     }
    00415     void clear()
    00416     {
    00417       if (p) {
    00418           int ref = dereference(p);
    00419           if (ref == 0)
    00420               delete p;
    00421           p = 0;
    00422         }
    00423     }
    00425     Ref<T>& operator=(const Ref<T> & c)
    00426     {
    00427       T *cp = c.pointer();
    00428       if (cp) {
    00429           cp->reference();
    00430           clear();
    00431           p=cp;
    00432         }
    00433       else {
    00434           clear();
    00435         }
    00436       return *this;
    00437     }
    00439     template <class A> Ref<T>& operator=(const Ref<A> & c)
    00440     {
    00441       A *cp = c.pointer();
    00442       if (cp) {
    00443           cp->reference();
    00444           clear();
    00445           p=cp;
    00446         }
    00447       else {
    00448           clear();
    00449         }
    00450       return *this;
    00451     }
    00453     Ref<T>& operator<<(const RefBase&a) {
    00454         T* cr = dynamic_cast<T*>(a.parentpointer());
    00455         if (cr) {
    00456             reference(cr);
    00457             clear();
    00458           }
    00459         p = cr;
    00460         return *this;
    00461       }
    00465     Ref<T>& operator<<(RefCount *a) {
    00466         T* cr = dynamic_cast<T*>(a);
    00467         if (cr) assign_pointer(cr);
    00468         else if (a && a->nreference() <= 0) delete a;
    00469         return *this;
    00470       }
    00472     Ref<T>& operator=(T* cr)
    00473     {
    00474       assign_pointer(cr);
    00475       return *this;
    00476     }
    00478     void assign_pointer(T* cr)
    00479     {
    00480       if (cr) {
    00481           if (DO_REF_CHECK_STACK(cr)) {
    00482               DO_REF_UNMANAGE(cr);
    00483               warn_ref_to_stack();
    00484             }
    00485           cr->reference();
    00486         }
    00487       clear();
    00488       p = cr;
    00489     }
    00491     void check_pointer() const
    00492     {
    00493       if (p && p->nreference() <= 0) {
    00494           warn_bad_ref_count();
    00495         }
    00496     }
    00498     void ref_info(std::ostream& os) const
    00499     {
    00500       RefBase::ref_info(p,os);
    00501     }
    00503     void warn(const char*s) const { RefBase::warn(s); }
    00504 };
    00505
    00506 }
    00507
    00508 #endif
    00509
    00510 // ///////////////////////////////////////////////////////////////////////////
    00511
    00512 // Local Variables:
    00513 // mode: c++
    00514 // c-file-style: "CLJ"
    00515 // End: