mud++0.35/etc/
mud++0.35/etc/guilds/
mud++0.35/help/propert/
mud++0.35/mudC/
mud++0.35/player/
mud++0.35/src/interface/
mud++0.35/src/os/cygwin32/
mud++0.35/src/os/win32/
mud++0.35/src/os/win32/bcppbuilder/
mud++0.35/src/osaddon/
mud++0.35/src/util/
/*
....[@@@..[@@@..............[@.................. 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;
}