/* ....[@@@..[@@@..............[@.................. MUD++ is a written from ....[@..[@..[@..[@..[@..[@@@@@....[@......[@.... scratch multi-user swords and ....[@..[@..[@..[@..[@..[@..[@..[@@@@@..[@@@@@.. sorcery game written in C++. ....[@......[@..[@..[@..[@..[@....[@......[@.... This server is an ongoing ....[@......[@..[@@@@@..[@@@@@.................. development project. All ................................................ contributions are welcome. ....Copyright(C).1995.Melvin.Smith.............. Enjoy. ------------------------------------------------------------------------------ Melvin Smith (aka Fusion) msmith@hom.net MUD++ development mailing list mudpp@van.ml.org ------------------------------------------------------------------------------ garbcoll.cc */ // Automatic Garbage collector for mud++ // It C, not C++ based, because there could be only one gc - even if // we will go multithreaded (of course it is now NOT prepared for multithreading) // Or maybe we will need more GCs ? Check it later // For now GC is run by hand (gc run), but will be put into some pulse // routine when it starts to be more reliable #include <sys/time.h> #include "config.h" #include "garbcoll.h" #include "vmobject.h" #include "io.h" #include "array.h" #include "properties.h" #include "vmarray.h" // Change this to shut up GC #define GC_VERB1( x ) x #define GC_VERB2( x ) bool gc_working_now = false; VMObject ** gc_stack; int gc_stack_size; int * gc_free; int gc_free_top = 0; int gc_free_size; void GC_init() { int i; static Property * prop =0; UseProperty( &prop, "GC_start_size", PROP_INT, "1000", nf_gtz, false); int gc_start_size = prop->getInt(); GC_VERB2( Cout << "GC_init:start with size " << gc_start_size << endl; ) gc_stack = new VMObject* [gc_start_size]; gc_stack_size = gc_start_size; memset( gc_stack, 0, gc_start_size * sizeof(VMObject*) ); gc_free_size = gc_start_size; gc_free = new int[gc_free_size]; for ( i =gc_start_size; i > 0 ; i--) { gc_free[gc_free_top] = i; gc_free_top++; } GC_VERB2( Cout << "GC_init:completed" <<endl; ) } inline void GC_growFree() { static Property * delta =0; UseProperty( &delta, "GC_grow_delta", PROP_INT, "100", nf_gtz ); int nsize = gc_free_size + delta->getInt(); int * ntable = new int[nsize]; memcpy(ntable, gc_free, sizeof(int) * gc_free_size ); delete gc_free; gc_free = ntable; gc_free_size = nsize; GC_VERB1( Cout << "GC_Free grown to size " << nsize <<endl; ) } inline void GC_growStack() { int i; static Property * delta = 0; UseProperty( &delta, "GC_grow_delta", PROP_INT, "100", nf_gtz ); int nsize = gc_stack_size + delta->getInt(); VMObject ** ntable = new VMObject*[nsize]; memcpy(ntable, gc_stack, sizeof(VMObject*) * gc_stack_size ); delete gc_stack; gc_stack = ntable; GC_VERB1( Cout << "GC_Stack grown to size " << nsize <<endl; ) if ( (gc_free_size - gc_free_top) < delta->getInt() ) GC_growFree(); for ( i = gc_stack_size; i < nsize; i++ ) { gc_stack[i] = 0; gc_free[gc_free_top] = i; gc_free_top++; } gc_stack_size = nsize; } inline void GC_putFreeRef( int i ) { if ( gc_free_top >= gc_free_size ) { GC_growFree(); } gc_free[gc_free_top] = i; gc_free_top++; } inline int GC_getFreeRef() { if ( gc_free_top <= 0 ) { GC_growStack(); } gc_free_top--; return gc_free[gc_free_top]; } void GC_register(VMObject * obj) { int index = GC_getFreeRef(); gc_stack[index] = obj; } // at vmachine.cpp void VMmark4GC(); extern Array<vmstack> vmstatvar_table; void GC_clean_and_mark() { int i; // CLEAN OLD MARKS for ( i =0; i < gc_stack_size; i++ ) if ( gc_stack[i] ) gc_stack[i]->GCunmark(); // MARK USED ONES // All working VMs stacks VMmark4GC(); // All static variables for ( i = vmstatvar_table.length() - 1; i >= 0; i--) { if ( IS_VMOBJ(vmstatvar_table[i].type) && vmstatvar_table[i].val.o ) vmstatvar_table[i].val.o->GCMark(); } } int GC_run() { int i; int total =0; struct timeval tstart; struct timeval tend; GC_VERB2( Cout << "GCollected : "; ) gettimeofday(&tstart, 0); gc_working_now = true; // MARK GC_clean_and_mark(); // SWEEP for ( i =0; i < gc_stack_size; i++ ) { if ( gc_stack[i] && !gc_stack[i]->getGCColor() ) { GC_VERB2( Cout << gc_stack[i]->getVMTypeName() << " "; ) delete gc_stack[i]; gc_stack[i] = 0; GC_putFreeRef(i); total++; } } GC_VERB2( Cout << endl; ) gc_working_now = false; gettimeofday(&tend, 0); // We will get things like 2s -117us , I'll correct this later GC_VERB1( Cout << "GCollector worked for " << tend.tv_sec - tstart.tv_sec << " seconds " << tend.tv_usec - tstart.tv_usec << " useconds." <<endl); GC_VERB1( Cout.flush() ); return total; } void GC_dump() { int i; int total =0; int invoid = 0; int willcollect = 0; GC_clean_and_mark(); for ( i =0; i < gc_stack_size; i ++) { if ( gc_stack[i] ) { Cout << gc_stack[i]->getVMTypeName() << ": " << (gc_stack[i]->inCWorld() ? 'C' : 'V') <<endl; total++; if ( !gc_stack[i]->inCWorld() ) invoid++; if ( !gc_stack[i]->getGCColor() ) willcollect++; } } Cout << "Total objects: " << total << endl; Cout << "Not in C World: " << invoid << endl; Cout << "GCinfuture: " << willcollect << endl; } int GC_getStackSize() { return gc_stack_size; } int GC_getFreeCount() { return gc_free_top; }