| //===----------- gccollector.cc - Mvm Garbage Collector -------------------===// |
| // |
| // Mvm |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "gccollector.h" |
| |
| using namespace mvm; |
| |
| #if !defined(MULTIPLE_GC) || defined(SERVICE_GC) |
| GCAllocator *GCCollector::allocator = 0; |
| #ifdef HAVE_PTHREAD |
| GCThread *GCCollector::threads; |
| #endif |
| |
| GCCollector::markerFn GCCollector::_marker; |
| |
| |
| int GCCollector::status; |
| |
| GCChunkNode *GCCollector::used_nodes; |
| GCChunkNode *GCCollector::unused_nodes; |
| |
| unsigned int GCCollector::current_mark; |
| #endif |
| |
| #ifdef MULTIPLE_GC |
| GCCollector* GCCollector::bootstrapGC; |
| #endif |
| |
| #ifdef SERVICE_GC |
| GCCollector* GCCollector::collectingGC; |
| #endif |
| |
| #if !defined(SERVICE_GC) && !defined(MULTIPLE_GC) |
| int GCCollector::_collect_freq_auto; |
| int GCCollector::_collect_freq_maybe; |
| int GCCollector::_since_last_collection; |
| |
| bool GCCollector::_enable_auto; |
| bool GCCollector::_enable_maybe; |
| bool GCCollector::_enable_collection; |
| #endif |
| |
| typedef void (*destructor_t)(void*); |
| |
| void GCCollector::do_collect() { |
| //printf("----- do collect -----\n"); |
| GCChunkNode *cur; |
| _since_last_collection = _collect_freq_auto; |
| |
| current_mark++; |
| |
| unused_nodes->attrape(used_nodes); |
| |
| #ifdef SERVICE_GC |
| collectingGC = this; |
| #endif |
| |
| #ifdef HAVE_PTHREAD |
| threads->synchronize(); |
| #endif |
| |
| for(cur=used_nodes->next(); cur!=used_nodes; cur=cur->next()) |
| trace(cur); |
| |
| if(_marker) |
| #ifdef MULTIPLE_GC |
| _marker(this); |
| #else |
| _marker(0); |
| #endif |
| status = stat_finalize; |
| |
| /* finalize */ |
| GCChunkNode finalizable; |
| finalizable.attrape(unused_nodes); |
| |
| status = stat_alloc; |
| |
| unlock(); |
| |
| /* kill everyone */ |
| GCChunkNode *next = 0; |
| |
| for(cur=finalizable.next(); cur!=&finalizable; cur=next) { |
| #ifdef SERVICE_GC |
| ((Collector*)cur->meta)->memoryUsed -= real_nbb(cur); |
| #endif |
| register gc_header *c = cur->chunk(); |
| next = cur->next(); |
| |
| destructor_t dest = c->getDestructor(); |
| if (dest) |
| dest(c); |
| } |
| |
| next = 0; |
| for(cur=finalizable.next(); cur!=&finalizable; cur=next) { |
| //printf(" !!!! reject %p [%p]\n", cur->chunk()->_2gc(), cur); |
| next = cur->next(); |
| allocator->reject_chunk(cur); |
| } |
| |
| lock(); |
| |
| #ifdef HAVE_PTHREAD |
| threads->collectionFinished(); |
| #endif |
| } |
| |
| void GCCollector::collect_unprotect() { |
| if(_enable_collection && (status == stat_alloc)) { |
| status = stat_collect; |
| do_collect(); |
| } |
| } |
| |
| #ifdef HAVE_PTHREAD |
| void GCCollector::die_if_sigsegv_occured_during_collection(void *addr) { |
| if(!isStable(0, 0, 0, 0, 0, 0, 0, 0, 0)) { |
| printf("; ****************************************************** ;\n"); |
| printf("; SIGSEGV occured during a collection ;\n"); |
| printf("; I'm trying to let the allocator in a coherent stat ;\n"); |
| printf("; but the collector is DEAD and will never collect again ;\n"); |
| printf("; ****************************************************** ;\n"); |
| |
| status = stat_broken; /* Collection is finished and no other collection will happend */ |
| threads->cancel(); /* Emulates a full collection to unlock mutators */ |
| used_nodes->eat(unused_nodes); /* All nodes are uses. Finalized are lost */ |
| unlock_dont_recovery(); /* Unlocks the GC lock */ |
| //gcfatal("SIGSEGV occured during collection at %p", addr); |
| } |
| } |
| #endif /* HAVE_PTHREAD */ |
| |
| void GCCollector::gcStats(size_t *_no, size_t *_nbb) { |
| register unsigned int n, tot; |
| register GCChunkNode *cur; |
| lock(); |
| for(n=0, tot=0, cur=used_nodes->next(); cur!=used_nodes; cur=cur->next(), n++) |
| tot += cur->nbb(); |
| unlock(); |
| *_no = n; |
| *_nbb = tot; |
| } |
| |