gbx.cc

00001 /* 
00002    EyeDB Object Database Management System
00003    Copyright (C) 1994-2008 SYSRA
00004    
00005    EyeDB is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009    
00010    EyeDB is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014    
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with this library; if not, write to the Free Software
00017    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA 
00018 */
00019 
00020 /*
00021    Author: Eric Viara <viara@sysra.com>
00022 */
00023 
00024 
00025 #include <stdio.h>
00026 #include <string.h>
00027 #include <time.h>
00028 #include "eyedb/gbx.h"
00029 #include "eyedb/gbxcyctx.h"
00030 #define _eyedb_se_P_
00031 #include <eyedblib/log.h>
00032 #include <assert.h>
00033 #include <eyedb/linklist.h>
00034 #include <iostream>
00035 
00036 #include <typeinfo>
00037 
00038 //#include <execinfo.h>
00039 
00040 //#define GBX_TRACE
00041 //#define GBX_TRACE2
00042 
00043 namespace eyedb {
00044 
00045     /*
00046       in gbx.h:
00047     struct lessObject {
00048       bool operator() (const gbxObject *x, const gbxObject *y) const;
00049     };
00050 
00051     typedef std::map<gbxObject *, bool, lessObject> Map;
00052     typedef std::map<gbxObject *, bool, lessObject>::iterator MapIterator;
00053     */
00054 
00055 
00056   /*
00057   bool gbxObject::lessObject::operator()(const gbxObject *x,
00058                                          const gbxObject *y) const
00059   {
00060     return x < y;
00061   }
00062   */
00063 
00064   enum gbxObjState {
00065     ToDelete = 1,
00066     Deleted,
00067     Keep
00068   };
00069 
00070   struct gbxRegObj {
00071     gbxObjState state;
00072     gbxObject *o;
00073   };
00074 
00075   static gbxBool object_isonstack = gbxTrue;
00076   static int object_size;
00077 
00078   int gbxObject::obj_cnt;
00079   int gbxObject::heap_size;
00080   gbxObject::Map *gbxObject::obj_map;
00081 
00082 #define ValidObject   (unsigned int)0x76fe12f1
00083 #define DeletedObject (unsigned int)0x1547eef3
00084 
00085   gbxObject::gbxObject()
00086   {
00087     init("");
00088   }
00089 
00090   gbxObject::gbxObject(const gbxTag &_tag)
00091   {
00092     init("");
00093     gbx_tag = new gbxTag(_tag);
00094   }
00095 
00096   gbxObject::gbxObject(const std::string &ptag)
00097   {
00098     init(ptag);
00099   }
00100 
00101   void gbxObject::init(const std::string &ptag)
00102   {
00103     gbx_ptag = ptag;
00104     gbx_magic     = ValidObject;
00105     gbx_refcnt    = 1;
00106     gbx_must_release = true;
00107     gbx_locked    = gbxFalse;
00108     gbx_isonstack = object_isonstack;
00109     gbx_on_release = 0;
00110 
00111     gbx_size      = object_size;
00112     gbx_tag       = 0;
00113     gbx_activeDestruction = gbxFalse;
00114     gbx_chgRefCnt = gbxFalse;
00115 
00116     object_isonstack = gbxTrue;
00117     object_size = 0;
00118 
00119     if (!gbx_isonstack)
00120       gbxAutoGarb::addObject(this);
00121 
00122     obj_cnt++;
00123     gbxObserver::addObject(this);
00124 
00125 #if 0
00126     void * array[100];
00127     int nSize = backtrace(array, 100);
00128     char ** symbols = backtrace_symbols(array, nSize);
00129  
00130     std::cout << "gbxObject called from:\n";
00131     for (int n = 0; n < nSize; n++) {
00132       std::cout << symbols[n] << '\n';
00133     }
00134     free(symbols);
00135 #endif
00136 
00137 
00138     if (obj_map) {
00139       if (obj_map->find(this) != obj_map->end())
00140         std::cerr << "gbxObject::init: " << this << " already in map" << std::endl;
00141 
00142       (*obj_map)[this] = true;
00143     }
00144 
00145     heap_size += gbx_size;
00146     IDB_LOG(IDB_LOG_OBJ_GBX,
00147             ("gbxObject::gbxObject(o=%p, isonstack=%s, refcnt=1)\n",
00148              this, gbx_isonstack ? "true" : "false"));
00149 #ifdef GBX_TRACE
00150     printf("gbxObject::gbxObject(%p, refcnt=1, stack=%d)\n",
00151            this, gbx_isonstack);
00152 #endif
00153   }
00154 
00155   gbxBool gbxObject::isValidObject() const
00156   {
00157     return (gbx_magic == ValidObject ? gbxTrue : gbxFalse);
00158   }
00159 
00160   gbxObject::gbxObject(const gbxObject &o)
00161   {
00162     init(o.gbx_ptag);
00163 
00164     gbx_locked = o.gbx_locked;
00165     gbx_tag = o.gbx_tag ? new gbxTag(*o.gbx_tag) : 0;
00166     gbx_must_release = o.gbx_must_release; // ??
00167   }
00168 
00169   gbxObject::gbxObject(const gbxObject *o)
00170   {
00171     init(o ? o->gbx_ptag : std::string(""));
00172 
00173     if (o) {
00174       gbx_locked  = o->gbx_locked;
00175       gbx_tag = o->gbx_tag ? new gbxTag(*o->gbx_tag) : 0;
00176       gbx_must_release = o->gbx_must_release; // ??
00177     }
00178   }
00179 
00180   gbxObject &gbxObject::operator=(const gbxObject &o)
00181   {
00182     if (&o == this)
00183       return *this;
00184 
00185     garbageRealize(gbxFalse, gbxFalse);
00186 
00187     gbx_magic = ValidObject;
00188     gbx_refcnt = 1;
00189     gbx_locked = o.gbx_locked;
00190     gbx_tag = o.gbx_tag ? new gbxTag(*o.gbx_tag) : 0;
00191     gbx_must_release = o.gbx_must_release; // ??
00192     gbx_on_release = 0;
00193 
00194     gbx_activeDestruction = gbxFalse;
00195 
00196     return *this;
00197   }
00198 
00199   void *gbxObject::operator new(size_t size)
00200   {
00201     object_isonstack = gbxFalse;
00202     object_size = size;
00203     return ::operator new(size);
00204   }
00205 
00206   static bool nodelete = getenv("EYEDB_NODELETE") ? true : false;
00207   static bool noabort_on_delete = getenv("EYEDB_NOABORT_ON_DELETE") ? true : false;
00208 
00209   void gbxObject::operator delete(void *o)
00210   {
00211     if (!o)
00212       return;
00213 
00214     fprintf(stderr, "gbxObject::delete: tries to use operator delete on an gbxObject * [%p]\n", o);
00215     fprintf(stderr, "use gbxObject::release method instead\n");
00216     if (!noabort_on_delete)
00217       abort();
00218   }
00219 
00220   void gbxObject::keep()
00221   {
00222     gbxAutoGarb::keepObject(this, gbxTrue);
00223   }
00224 
00225   void gbxObject::unkeep()
00226   {
00227     gbxAutoGarb::keepObject(this, gbxFalse);
00228   }
00229 
00230   void gbxObject::release_realize(gbxBool reentrant)
00231   {
00232     if (gbx_activeDestruction)
00233       return;
00234     garbageRealize(reentrant, gbxTrue);
00235     gbx_activeDestruction = gbxFalse;
00236 
00237     /*
00238     if (!gbx_refcnt && !gbx_locked) {
00239       obj_cnt--;
00240       assert(gbx_magic == DeletedObject);
00241       gbxObserver::rmvObject(this);
00242     }
00243     */
00244 
00245     if (!nodelete)
00246       if (!gbx_isonstack && !gbx_refcnt && !gbx_locked)
00247         delete ((void *)this);
00248   }
00249 
00250   void gbxObject::release()
00251   {
00252     if (!grant_release()) {
00253       fprintf(stderr, "gbxObject::release error, object %p is not granted to be released refcnt = %d\n", this, gbx_refcnt);
00254       abort();
00255     }
00256     release_realize(gbxFalse);
00257   }
00258 
00259   void gbxObject::release_r()
00260   {
00261     release_realize(gbxTrue);
00262   }
00263 
00264   void
00265   gbxObject::garbageRealize(gbxBool reentrant, gbxBool remove)
00266   {
00267 #if 0
00268     if (gbx_isonstack) {
00269       std::cerr << "---> onstack " << (void *)this << ": " <<
00270         gbx_refcnt << " " << gbx_locked << " " << reentrant << " " << remove
00271                << std::endl;
00272     }
00273 #endif
00274 
00275     if (gbx_activeDestruction)
00276       return;
00277 
00278     /*
00279       if (gbxAutoGarb::isObjectDeleted(this))
00280       return;
00281     */
00282 
00283     gbx_activeDestruction = gbxTrue;
00284 
00285 #ifdef GBX_TRACE
00286     printf("gbxObject::garbageRealize(%p, refcnt=%d, locked=%d, stack=%d, "
00287            "reentrant=%d)\n",
00288            this, gbx_refcnt, gbx_locked, gbx_isonstack, reentrant);
00289 #endif
00290 
00291     if ((reentrant && gbx_refcnt < 0) || (!reentrant && gbx_refcnt < 1)) {
00292 #if 1
00293         fprintf(stderr, "gbxObject::delete warning, tries to delete a null ref count object `%p', refcnt = %d\n", this, gbx_refcnt);
00294       gbx_refcnt = 1;
00295 #else
00296       fprintf(stderr, "gbxObject::delete error, tries to delete a null ref count object `%p', refcnt = %d\n", this, gbx_refcnt);
00297       abort();
00298 #endif
00299     }
00300 
00301     if (gbx_magic == DeletedObject) {
00302       fprintf(stderr, "gbxObject::delete: error, tries to delete an object already deleted `%p'\n", this);
00303       abort();
00304       return;
00305     }
00306 
00307     if (gbx_magic != ValidObject) {
00308       fprintf(stderr, "gbxObject::delete: try to delete an invalid object `%p'\n", this);
00309       abort();
00310       return;
00311     }
00312 
00313     // added 30/09/05
00314     if (gbx_locked)
00315       return;
00316 
00317     gbxObject::decrRefCount();
00318 
00319     IDB_LOG(IDB_LOG_OBJ_GBX,
00320             ("gbxObject::garbageRealize(o=%p, refcnt=%d, locked=%d)\n",
00321              this, gbx_refcnt, gbx_locked));
00322 
00323     //if (!reentrant && gbx_refcnt == 1) {// added the 18/10/99: '&& gbx_refcnt==1'
00324     if (!reentrant) {// EV_CYCLE: suppress the 23/11/06: '&& gbx_refcnt==1' for testing
00325 #ifdef MANAGE_CYCLE_TRACE
00326       struct timeval tp0, tp1;
00327       gettimeofday(&tp0, NULL);
00328       printf("gbxObject begin detect cycle for %p\n", this);
00329 #endif
00330 
00331       gbxCycleContext r(this);
00332       manageCycle(r);
00333 
00334 #ifdef MANAGE_CYCLE_TRACE
00335       gettimeofday(&tp1, NULL);
00336 
00337       int ms = ((tp1.tv_sec - tp0.tv_sec) * 1000) + ((tp1.tv_usec - tp0.tv_usec)/1000);
00338       printf("gbxObject end detect cycle for %p [cycle=%d] [%d ms]\n", this,
00339              r.isCycle(), ms);
00340 #endif
00341 
00342       if (r.isCycle()) {
00343         gbxObject::decrRefCount();
00344       }
00345     }
00346 
00347 #if 0
00348     if (gbx_isonstack) {
00349       std::cerr << "onstack " << (void *)this << ": " <<
00350         gbx_refcnt << " " << gbx_locked << std::endl;
00351     }
00352 #endif
00353 
00354     if (!gbx_refcnt && !gbx_locked) {
00355       if (!gbx_isonstack)
00356         gbxAutoGarb::markObjectDeleted(this);
00357 #ifdef GBX_TRACE
00358       printf("gbxObject garbaging 0x%p\n", this);
00359 #endif
00360       IDB_LOG(IDB_LOG_OBJ_GBX,
00361               ("gbxObject::garbageRealize(o=%p) calling virtual garbage\n",
00362                this));
00363 
00364       if (obj_map) {
00365         MapIterator iter = obj_map->find(this);
00366 
00367         if (iter != obj_map->end())
00368           obj_map->erase(iter);
00369         else {
00370           /*
00371             std::cerr << "gbxObject::garbage: " << this << " not found";
00372             if (gbx_tag) {
00373             if (gbx_tag->getSTag())
00374             std::cerr << " [" << gbx_tag->getSTag() << "]";
00375             else if (gbx_tag->getITag())
00376             std::cerr << " [" << gbx_tag->getITag() << "]";
00377             std::cerr << std::endl;
00378             }
00379           */
00380         }
00381       }
00382 
00383       if (remove) {
00384         obj_cnt--;
00385         gbxObserver::rmvObject(this);
00386       }
00387 
00388       if (gbx_on_release) {
00389         //printf("GBX_ON_RELEASE %p\n", gbx_on_release);
00390         gbx_on_release->perform(this);
00391       }
00392 
00393       userGarbage();
00394       garbage();
00395       delete gbx_tag;
00396       gbx_tag = 0;
00397       gbx_magic = DeletedObject;
00398 
00399       heap_size -= gbx_size; 
00400    }
00401   }
00402 
00403   void gbxObject::setObjMapped(bool obj_mapped, bool reinit_if_exists)
00404   {
00405     if (obj_mapped) {
00406       if (obj_map) {
00407         if (!reinit_if_exists)
00408           return;
00409       }
00410 
00411       delete obj_map;
00412       obj_map = new Map();
00413       return;
00414     }
00415 
00416     delete obj_map;
00417     obj_map = 0;
00418   }
00419 
00420   void gbxObject::setTag(const gbxTag &_tag)
00421   {
00422     delete gbx_tag;
00423     gbx_tag = new gbxTag(_tag);
00424   }
00425 
00426   void
00427   gbxObject::incrRefCount()
00428   {
00429     IDB_LOG(IDB_LOG_OBJ_GBX, ("gbxObject::incrRefCount(o=%p, refcnt=%d -> %d)\n", this, gbx_refcnt, gbx_refcnt+1));
00430 
00431     if (!isValidObject()) {
00432       fprintf(stderr, "gbxObject::incrRefCount: try to increment reference count on an invalid object `%p'\n", this);
00433       abort();
00434     }
00435 
00436     if (!gbx_chgRefCnt)
00437       gbx_refcnt++;
00438     /*
00439     else
00440       printf("should increment refcnt %p\n", this);
00441     */
00442   }
00443 
00444   void
00445   gbxObject::reserve()
00446   {
00447     incrRefCount();
00448   }
00449 
00450   void
00451   gbxObject::decrRefCount()
00452   {
00453     IDB_LOG(IDB_LOG_OBJ_GBX, ("gbxObject::decrRefCount(o=%p, refcnt=%d -> %d)\n", this, gbx_refcnt, gbx_refcnt-1));
00454 
00455     if (!isValidObject()) {
00456       fprintf(stderr, "gbxObject::incrRefCount: try to increment reference count on an invalid object `%p'\n", this);
00457       abort();
00458     }
00459 
00460     if (!gbx_chgRefCnt)
00461       gbx_refcnt--;
00462     /*
00463     else
00464       printf("should decrement refcnt %p\n", this);
00465     */
00466     assert(gbx_refcnt >= 0);
00467   }
00468 
00469   void
00470   gbxObject::manageCycle(gbxCycleContext &)
00471   {
00472   }
00473 
00474   gbxObject::~gbxObject()
00475   {
00476     garbageRealize(gbxFalse, gbxTrue);
00477     gbx_activeDestruction = gbxFalse;
00478   }
00479 
00480   //
00481   // gbxCycleContext
00482   //
00483 
00484   gbxBool gbxCycleContext::mustClean(gbxObject *_ref)
00485   {
00486     //if (this->ref == _ref)
00487       //printf("mustClean: ref %p refcnt=%d\n", ref, ref->getRefCount());
00488 
00489     //    if (this->ref == _ref && this->ref->getRefCount() == 1)
00490     // EV_CYCLE
00491     if (this->ref == _ref)
00492       return gbxTrue;
00493     return gbxFalse;
00494   }
00495 
00496   void gbxCycleContext::manageCycle(gbxObject *_ref)
00497   {
00498     if (this->ref == _ref) {
00499       //printf("manage cycle %p\n", ref);
00500       cycle = gbxTrue;
00501     }
00502   }
00503 
00504   //
00505   // gbxTag
00506   //
00507 
00508   void gbxTag::init()
00509   {
00510     stag = 0;
00511     vtag = 0;
00512     itag = 0;
00513   }
00514 
00515   gbxTag::gbxTag()
00516   {
00517     init();
00518   }
00519 
00520   gbxTag::gbxTag(const gbxTag &tag)
00521   {
00522     init();
00523     *this = tag;
00524   }
00525 
00526   gbxTag::gbxTag(const char *_stag)
00527   {
00528     init();
00529     stag = _stag ? strdup(_stag) : 0;
00530   }
00531 
00532   gbxTag::gbxTag(int _itag)
00533   {
00534     init();
00535     itag = _itag;
00536   }
00537 
00538   gbxTag::gbxTag(void *_vtag)
00539   {
00540     init();
00541     vtag = _vtag;
00542   }
00543 
00544   gbxTag &gbxTag::operator=(const gbxTag &tag)
00545   {
00546     free(stag);
00547 
00548     stag = tag.stag ? strdup(tag.stag) : 0;
00549     itag = tag.itag;
00550     vtag = tag.vtag;
00551 
00552     return *this;
00553   }
00554 
00555   int gbxTag::operator==(const gbxTag &tag) const
00556   {
00557     return (itag == tag.itag && vtag == tag.vtag && !strcmp(stag, tag.stag));
00558   }
00559 
00560   int gbxTag::operator!=(const gbxTag &tag) const
00561   {
00562     return !this->operator==(tag);
00563   }
00564 
00565   gbxTag::~gbxTag()
00566   {
00567     free(stag);
00568   }
00569 
00570   //
00571   // gbxDeleter
00572   //
00573 
00574   //
00575   // added the 18/02/99: WARNING this does not work with the gbxAutoGarb!
00576   //
00577 
00578   gbxDeleter::gbxDeleter(gbxObject *_o) : o(_o), _keep(gbxFalse)
00579   {
00580   }
00581 
00582   gbxObject *
00583   gbxDeleter::keep()
00584   {
00585     _keep = gbxTrue;
00586     return o;
00587   }
00588 
00589   gbxDeleter::~gbxDeleter()
00590   {
00591     if (!_keep && o)
00592       {
00593         o->release();
00594         return;
00595       }
00596   }
00597 
00598   //
00599   // gbxAutoGarb
00600   //
00601 
00602   static gbxBool
00603   isPower2(unsigned int x)
00604   {
00605     int n = 0;
00606     while(x) {
00607       if ((x & 1) && ++n > 1)
00608         return gbxFalse;
00609 
00610       x >>= 1;
00611     }
00612 
00613     return gbxTrue;
00614   }
00615 
00616   gbxAutoGarb *gbxAutoGarb::current_auto_garb = 0;
00617 
00618   void gbxAutoGarb::init(int _list_cnt)
00619   {
00620 #ifdef GBX_TRACE
00621     //printf("gbxAutoGarb::init();\n");
00622 #endif
00623     excepted = gbxFalse;
00624     keepobjs = gbxFalse;
00625     regobjs_cnt = 0;
00626     if (!isPower2(_list_cnt))
00627       throw "gbxAutoGarb::init() power of 2 expected";
00628     list_cnt = _list_cnt;
00629     mask = list_cnt - 1;
00630     todelete_lists = new LinkedList*[list_cnt];
00631     memset(todelete_lists, 0, sizeof(LinkedList*)*list_cnt);
00632     deleted_lists = new LinkedList*[list_cnt];
00633     memset(deleted_lists, 0, sizeof(LinkedList*)*list_cnt);
00634     deleted_cnt = todelete_cnt = 0;
00635 
00636     prev = current_auto_garb;
00637     current_auto_garb = this;
00638     tag  = 0;
00639     type = (gbxAutoGarb::Type)0;
00640     deleg_auto_garb = 0;
00641   }
00642 
00643   gbxAutoGarb::gbxAutoGarb(int _list_cnt)
00644   {
00645     init(_list_cnt);
00646   }
00647 
00648   gbxAutoGarb::gbxAutoGarb(gbxAutoGarb *auto_garb)
00649   {
00650     deleg_auto_garb = auto_garb;
00651     prev = current_auto_garb;
00652     current_auto_garb = deleg_auto_garb;
00653   }
00654 
00655   gbxAutoGarb::gbxAutoGarb(gbxAutoGarb::Type _type, int _list_cnt)
00656   {
00657     init(_list_cnt);
00658     type = _type;
00659   }
00660 
00661   gbxAutoGarb::gbxAutoGarb(const gbxTag &_tag, gbxBool _excepted, int _list_cnt)
00662   {
00663     init(_list_cnt);
00664     tag = new gbxTag(_tag);
00665     excepted = _excepted;
00666   }
00667 
00668   gbxAutoGarb *gbxAutoGarb::getAutoGarb()
00669   {
00670     return (deleg_auto_garb ? deleg_auto_garb : this);
00671   }
00672 
00673   void gbxAutoGarb::keepObjs()
00674   {
00675     getAutoGarb()->keepobjs = gbxTrue;
00676   }
00677 
00678   static int true_obj;
00679 
00680   inline unsigned int
00681   gbxAutoGarb::get_key(gbxObject *o)
00682   {
00683     return ((((long)o)>>4) & mask);
00684   }
00685 
00686   gbxRegObj *
00687   gbxAutoGarb::find(gbxObject *o, LinkedList **lists)
00688   {
00689     unsigned int key = get_key(o);
00690     if (!lists[key])
00691       return 0;
00692 
00693     LinkedListCursor c(lists[key]);
00694     gbxRegObj *reg;
00695     while(c.getNext((void *&)reg)) 
00696       if (reg->o == o)
00697         return reg;
00698 
00699     return 0;
00700   }
00701 
00702   void gbxAutoGarb::addObj(gbxObject *o)
00703   {
00704     if (type == SUSPEND) {
00705 #ifdef GBX_TRACE
00706       printf("gbxAutoGarb::addObject(%p) AUTO_GARB IS SUSPENDED\n", o);
00707 #endif
00708       return;
00709     }
00710 
00711 #ifdef GBX_TRACE
00712     printf("gbxAutoGarb::addObject(%p)\n", o);
00713 #endif
00714 
00715     unsigned int key = get_key(o);
00716     if (!todelete_lists[key])
00717       todelete_lists[key] = new LinkedList();
00718     gbxRegObj *reg = new gbxRegObj();
00719     reg->state = ToDelete;
00720     reg->o = o;
00721     todelete_lists[key]->insertObject(reg);
00722     regobjs_cnt++;
00723     todelete_cnt++;
00724     true_obj = regobjs_cnt;
00725   }
00726 
00727   gbxBool gbxAutoGarb::keepObj(gbxObject *o, gbxBool keep)
00728   {
00729 #ifdef GBX_TRACE
00730     printf("keepObj(%p, o = %p, regobjs_cnt = %d, true_obj = %d)\n",
00731            this, o, regobjs_cnt, true_obj);
00732 #endif
00733 
00734     gbxRegObj *reg = find(o, todelete_lists);
00735     if (reg) {
00736       if (keep) {
00737         if (reg->state == ToDelete) {
00738           reg->state = Keep;
00739           true_obj--;
00740           todelete_cnt--;
00741         }
00742       }
00743       else if (reg->state == Keep) {
00744         reg->state = ToDelete;
00745         true_obj++;
00746         todelete_cnt++;
00747       }
00748 #ifdef GBX_TRACE
00749       printf("%p -> found\n", o);
00750 #endif
00751       return gbxTrue;
00752     }
00753 
00754     return gbxFalse;
00755   }
00756 
00757   gbxBool gbxAutoGarb::markObjDeleted(gbxObject *o)
00758   {
00759 #ifdef GBX_TRACE
00760     printf("gbxAutoGarb::markObjDeleted(%p)\n", o);
00761 #endif
00762     gbxRegObj *reg = find(o, todelete_lists);
00763     if (!reg) {
00764 #ifdef GBX_TRACE
00765       printf(" -> *not* found\n");
00766 #endif
00767       return gbxFalse;
00768     }
00769 
00770     unsigned int key = get_key(o);
00771     todelete_lists[key]->deleteObject(reg);
00772     if (reg->state == ToDelete)
00773       todelete_cnt--;
00774 
00775     if (!find(o, deleted_lists)) {
00776       reg->state = Deleted;
00777       if (!deleted_lists[key])
00778         deleted_lists[key] = new LinkedList();
00779       deleted_lists[key]->insertObject(reg);
00780       deleted_cnt++;
00781     }
00782     else
00783       delete reg;
00784 #ifdef GBX_TRACE
00785     printf(" -> found\n");
00786 #endif
00787     return gbxTrue;
00788   }
00789 
00790   gbxBool gbxAutoGarb::isObjRegistered(gbxObject *o)
00791   {
00792     return find(o, todelete_lists) || find(o, deleted_lists) ? gbxTrue : gbxFalse;
00793   }
00794 
00795   gbxBool gbxAutoGarb::isObjDeleted(gbxObject *o)
00796   {
00797     return find(o, deleted_lists) ? gbxTrue : gbxFalse;
00798   }
00799 
00800   gbxBool gbxAutoGarb::isObjectRegistered(gbxObject *o)
00801   {
00802     return current_auto_garb ? current_auto_garb->isObjRegistered(o) : gbxFalse;
00803   }
00804 
00805   // 7/05/01: added this flag because this method is called from several
00806   // points in eyedb and this considerally slow down the system !
00807   // is this disconnection a good idea !?
00808   //#define GBX_IS_OBJ_DELETED_DISCONNECTED
00809   gbxBool gbxAutoGarb::isObjectDeleted(gbxObject *o)
00810   {
00811 #ifdef GBX_IS_OBJ_DELETED_DISCONNECTED
00812     return gbxFalse;
00813 #else
00814     gbxBool r =  current_auto_garb ? current_auto_garb->isObjDeleted(o) : gbxFalse;
00815 #ifdef GBX_TRACE
00816     if (r)
00817       printf("gbxAutoGarb::isObjectDeleted: object %p was deleted\n", o);
00818 #endif
00819     return r;
00820 #endif
00821   }
00822 
00823   void gbxAutoGarb::addObject(gbxObject *o)
00824   {
00825     if (current_auto_garb)
00826       current_auto_garb->getAutoGarb()->addObj(o);
00827   }
00828 
00829   void gbxAutoGarb::keepObject(gbxObject *o, gbxBool keep)
00830   {
00831     for (gbxAutoGarb *auto_garb = current_auto_garb; auto_garb; auto_garb = auto_garb->prev)
00832       if (auto_garb->getAutoGarb()->keepObj(o, keep))
00833         break;
00834   }
00835 
00836   void gbxAutoGarb::markObjectDeleted(gbxObject *o)
00837   {
00838     for (gbxAutoGarb *auto_garb = current_auto_garb; auto_garb; auto_garb = auto_garb->prev)
00839       if (auto_garb->getAutoGarb()->markObjDeleted(o))
00840         break;
00841   }
00842 
00843   gbxAutoGarb::Type
00844   gbxAutoGarb::suspend()
00845   {
00846     return setType(SUSPEND);
00847   }
00848 
00849   void
00850   gbxAutoGarb::restore(gbxAutoGarb::Type t)
00851   {
00852     (void)setType(t);
00853   }
00854 
00855   gbxAutoGarb::Type
00856   gbxAutoGarb::setType(gbxAutoGarb::Type t)
00857   {
00858     Type ot = type;
00859     type = t;
00860     return ot;
00861   }
00862 
00863   gbxAutoGarb::Type
00864   gbxAutoGarb::getType()
00865   {
00866     return type;
00867   }
00868 
00869   void gbxAutoGarb::wipeLists(LinkedList **lists)
00870   {
00871     for (int i = 0; i < list_cnt; i++) {
00872       LinkedList *list = lists[i];
00873       if (!list) continue;
00874       LinkedListCursor c(list);
00875       gbxRegObj *reg;
00876       while(c.getNext((void *&)reg))
00877         delete reg;
00878       delete list;
00879     }
00880 
00881     delete [] lists;
00882   }
00883 
00884   unsigned int gbxAutoGarb::countLists(LinkedList **lists, int state)
00885   {
00886     unsigned int cnt = 0;
00887     for (int i = 0; i < list_cnt; i++) {
00888       LinkedList *list = lists[i];
00889       if (!list) continue;
00890       LinkedListCursor c(list);
00891       gbxRegObj *reg;
00892       while(c.getNext((void *&)reg)) {
00893         if (!state || reg->state == state)
00894           cnt++;
00895       }
00896     }
00897     return cnt;
00898   }
00899 
00900   void displayLists(LinkedList **lists, int list_cnt, const char *msg)
00901   {
00902     printf(msg);
00903     for (int i = 0; i < list_cnt; i++) {
00904       LinkedList *list = lists[i];
00905       if (!list) continue;
00906       printf("#%d : %d\n", i, list->getCount());
00907     }
00908   }
00909 
00910   void gbxAutoGarb::garbage()
00911   {
00912 #ifdef GBX_TRACE2
00913     printf("BEGIN ~gbxAutoGarb(%p, %d, %d, todelete_cnt=%d, deleted_cnt=%d)\n", this, regobjs_cnt, true_obj,
00914            todelete_cnt, deleted_cnt);
00915     struct timeval tp0, tp1;
00916     gettimeofday(&tp0, NULL);
00917 #endif
00918 
00919     if (!keepobjs) {
00920       //displayLists(todelete_lists, list_cnt, "ToDeleteList:\n");
00921       //displayLists(deleted_lists, list_cnt, "DeletedList:\n");
00922       gbxRegObj **regs = (gbxRegObj **)malloc(todelete_cnt * sizeof(gbxRegObj*));
00923 
00924       int n = 0;
00925       for (int i = 0; i < list_cnt; i++) {
00926         LinkedList *list = todelete_lists[i];
00927         if (!list) continue;
00928         LinkedListCursor c(list);
00929         gbxRegObj *reg;
00930         while(c.getNext((void *&)reg)) {
00931           if (reg->state == ToDelete)
00932             regs[n++] = reg;
00933         }
00934       }
00935 
00936 #ifdef GBX_TRACE2
00937       if (n != todelete_cnt)
00938         printf("ToDelete %d vs. %d\n", todelete_cnt, n);
00939 #endif
00940 
00941       assert(n == todelete_cnt);
00942       { // A.W. adding block because of IRIX cc complain on i scope
00943         for (int i = 0; i < n; i++) {
00944           gbxRegObj *reg = regs[i];
00945           gbxObject *o = reg->o;
00946 #ifdef GBX_TRACE
00947           printf("o=%p, state=%d\n", o, reg->state);
00948 #endif
00949           if (!o || reg->state != ToDelete) {
00950 #ifdef GBX_TRACE
00951             printf("not to delete reg->o %p %d\n", o, reg->state);
00952 #endif
00953             continue;
00954           }
00955         
00956           IDB_LOG(IDB_LOG_OBJ_GARBAGE, 
00957                   ("~gbxAutoGarb(o=%p, refcnt=%d) => ",
00958                    o, reg->o->getRefCount()));
00959       
00960           if (o->getRefCount()) {
00961 #ifdef GBX_TRACE
00962             printf("gbxAutoGarb--garbage(%p)\n", o);
00963 #endif
00964             o->release();
00965           }
00966           else
00967             IDB_LOG_X(IDB_LOG_OBJ_GARBAGE, ("not "));
00968       
00969           IDB_LOG_X(IDB_LOG_OBJ_GARBAGE, ("releasing\n"));
00970         }
00971       }
00972 
00973       free(regs);
00974     }
00975 
00976 #ifdef GBX_TRACE2
00977     printf("Object Count : %d\n", regobjs_cnt);
00978     printf("  ToDelete : %d vs. %d [%d]\n", countLists(todelete_lists, ToDelete),
00979            todelete_cnt, countLists(todelete_lists, 0));
00980     printf("  Keep : %d+%d\n", countLists(todelete_lists, Keep),
00981            countLists(deleted_lists, Keep));
00982     printf("  Deleted : %d vs. %d [%d]\n", countLists(deleted_lists, Deleted),
00983            deleted_cnt, countLists(deleted_lists, 0));
00984 #endif
00985 
00986 #ifdef GBX_TRACE2
00987     fflush(stdout);
00988 #endif
00989 
00990     wipeLists(todelete_lists);
00991     wipeLists(deleted_lists);
00992 
00993     current_auto_garb = prev;
00994     delete tag;
00995 
00996     regobjs_cnt = 0;
00997   }
00998 
00999   gbxAutoGarb::~gbxAutoGarb()
01000   {
01001     getAutoGarb()->garbage();
01002   }
01003 
01004   gbxAutoGarbSuspender::gbxAutoGarbSuspender()
01005   {
01006     current = gbxAutoGarb::getCurrentAutoGarb();
01007     if (current)
01008       type = current->suspend();
01009   }
01010 
01011   gbxAutoGarbSuspender::~gbxAutoGarbSuspender()
01012   {
01013     if (current)
01014       current->restore(type);
01015   }
01016 
01017   gbxObserver *gbxObserver::current_observer = 0;
01018 
01019   gbxObserver::gbxObserver(const std::string &tag) : tag(tag)
01020   {
01021     prev = current_observer;
01022     current_observer = this;
01023     addobj_trigger = 0;
01024     rmvobj_trigger = 0;
01025     obj_map = new std::map<gbxObject *, bool>();
01026   }
01027 
01028   gbxObserver::~gbxObserver()
01029   {
01030     delete obj_map;
01031     current_observer = prev;
01032   }
01033 
01034   void gbxObserver::addObject(gbxObject *o)
01035   {
01036     if (getCurrentObserver())
01037       getCurrentObserver()->addObj(o);
01038   }
01039 
01040   void gbxObserver::rmvObject(gbxObject *o)
01041   {
01042     if (getCurrentObserver())
01043       getCurrentObserver()->rmvObj(o);
01044   }
01045 
01046   void gbxObserver::addObj(gbxObject *o)
01047   {
01048     assert(!isObjectRegistered(o));
01049     (*obj_map)[o] = true;
01050     if (addobj_trigger)
01051       (*addobj_trigger)(o);
01052   }
01053 
01054   void gbxObserver::rmvObj(gbxObject *o)
01055   {
01056     assert(isObjectRegistered(o));
01057     if (isObjectRegistered(o))
01058       obj_map->erase(obj_map->find(o));
01059     if (rmvobj_trigger)
01060       (*rmvobj_trigger)(o);
01061   }
01062 
01063   bool gbxObserver::isObjectRegistered(gbxObject *o) const
01064   {
01065     return obj_map->find(o) != obj_map->end();
01066   }
01067 
01068   void gbxObserver::getObjects(std::vector<gbxObject *> &v) const
01069   {
01070     v.erase(v.begin(), v.end());
01071     std::map<gbxObject *, bool>::const_iterator begin = obj_map->begin();
01072     std::map<gbxObject *, bool>::const_iterator end = obj_map->end();
01073 
01074     while (begin != end) {
01075       v.push_back((*begin).first);
01076       ++begin;
01077     }
01078   }
01079 
01080   size_t gbxObserver::getObjectCount() const
01081   {
01082     return obj_map->size();
01083   }
01084 
01085   void gbxObserver::setAddObjectTrigger(gbxObserver::AddObjectTrigger *_addobj_trigger)
01086   {
01087     addobj_trigger = _addobj_trigger;
01088   }
01089 
01090   void gbxObserver::setRemoveObjectTrigger(gbxObserver::RemoveObjectTrigger *_rmvobj_trigger)
01091   {
01092     rmvobj_trigger = _rmvobj_trigger;
01093   }
01094 
01095   gbxObserver::ObjectTrigger::~ObjectTrigger()
01096   {
01097   }
01098 
01099   gbxObserver::AddObjectTrigger::~AddObjectTrigger()
01100   {
01101   }
01102 
01103   gbxObserver::RemoveObjectTrigger::~RemoveObjectTrigger()
01104   {
01105   }
01106 }

Generated on Mon Dec 22 18:15:55 2008 for eyedb by  doxygen 1.5.3