00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
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
00039
00040
00041
00042
00043 namespace eyedb {
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
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
00239
00240
00241
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
00280
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
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
00324 if (!reentrant) {
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
00372
00373
00374
00375
00376
00377
00378
00379
00380 }
00381 }
00382
00383 if (remove) {
00384 obj_cnt--;
00385 gbxObserver::rmvObject(this);
00386 }
00387
00388 if (gbx_on_release) {
00389
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
00440
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
00464
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
00482
00483
00484 gbxBool gbxCycleContext::mustClean(gbxObject *_ref)
00485 {
00486
00487
00488
00489
00490
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
00500 cycle = gbxTrue;
00501 }
00502 }
00503
00504
00505
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
00572
00573
00574
00575
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
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
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
00806
00807
00808
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
00921
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 {
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 }