/* ....[@@@..[@@@..............[@.................. 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 ------------------------------------------------------------------------------ vmachine.cpp */ #include "config.h" #include "io.h" #include "vmachine.h" #include "asmparser.h" #include "asmloader.h" #include "properties.h" Array <VMachine *> freeVMs; Array <VMachine *> dozingVMs; Array <VMachine *> sleepingVMs; // for opcode execution loop check vmrun.cpp void VMachine::buildStackTrace( String & str ) { if ( !live ) { str << "VMachine is not alive" << endl; return; } vmtrace * vmt; str << "VMachine at " << vmfun_table[funID].name << ':' << (int) (pmem - low_border -1) << endl; for ( vmt = pstrace-1; vmt >= tStack; vmt--) { str << "called from " << vmfun_table[vmt->funID].name << ':' << (int) (vmt->focus - vmfun_table[vmt->funID].low_border -1) << endl; } str << "called from mud++" << endl; } void VMachine::crit_error( const char * txt ) { if ( pmem == 0 ) { Cout << "VM Error: focus at NULL pointer" << endl; } else { Cout << "VM Error: opcode " << lookupOpcodeName((pmem-1)->s.opcode) << " : "<< txt << endl; } String str; buildStackTrace(str); Cout << str; live = false; exitCode = 1; // mark functions as bad ? } void VMachine::leave_trace(int offset) { pstrace->funID = funID; pstrace->focus = pmem + offset; pstrace->var_count = var_count; psvar += var_count; var_count = 0; pstrace++; } void VMachine::collect_trace() { if ( pstrace <= tStack ) { live = false; return; } pstrace--; funID = pstrace->funID; low_border = vmfun_table[funID].low_border; high_border = vmfun_table[funID].high_border; pmem = pstrace->focus; for ( var_count--; var_count >= 0; var_count-- ) { dereference_obj( psvar + var_count ); } var_count = pstrace->var_count; psvar -= var_count; } vmstack * VMachine::initp( int number ) { #if VM_SECURITY_LEVEL >= 1 if ( psvar + number > vStackCeiling ) { crit_error("Variable stack exceeded"); return NULL; } #if VM_SECURITY_LEVEL >= 2 if ( psobj < &oStack[number] ) { crit_error("Inited more parameters than was on stack.\n\r"); return NULL; } #endif #endif for ( ; number > 0 ; number-- ) { *(psvar + var_count) = *psobj; var_count++; psobj--; } return psvar; } void VMachine::putToSleep( float seconds ) { // traslate seconds to pulses or to vm_update_pulses (?) to_sleep = (int) (seconds); } void VMachine::defaultValues() { psobj = oStack; psvar = vStack; pstrace = tStack; var_count = 0; current_args = NULL; exitCode = 0; funID = -1; live = false; } void VMachine::run( int funnumber ) { funID = funnumber; low_border = vmfun_table[funID].low_border; high_border = vmfun_table[funID].high_border; pmem = low_border; live = true; schedule(); } void VMachine::schedule() { static Property * prop = 0; run(); UseProperty( &prop, "VM_dozing_barrier", PROP_INT, "60", nf_gtz, true); if ( !live ) freeVMs.add( this ); else if ( to_sleep < prop->getInt() ) dozingVMs.add( this ); else sleepingVMs.add(this); } VMachine * getFreeVM() { VMachine * vm; if ( (vm = freeVMs.removeTop()) != NULL ) return vm; vm = new VMachine(); return vm; } void VMstatistic( String & str ) { str << freeVMs.length() << " VMs are free" << endl << dozingVMs.length() << " VMs are dozing" << endl << sleepingVMs.length() << " VMs are sleeping" << endl; } void createVMs() { static Property * prop =0; UseProperty( &prop, "starting_number_of_VMs", PROP_INT, "10", NULL, false); int i; i = prop->getInt(); for ( ; i > 0; i-- ) { freeVMs.add( new VMachine() ); } } void pulseVM() { VMachine * vm; int i; // it has to go back, as it can be added to top after schedule for ( i = dozingVMs.length()-1 ; i >= 0; i -- ) { vm = dozingVMs[i]; if ( !vm->tick() ) { dozingVMs.remove(i); vm->schedule(); } } } int VMachine::bigTick(int doze) { to_sleep -= doze; return to_sleep; } void VMachine::mark() { int i; for (i = psobj - oStack; i > 0; i-- ) { if (IS_VMOBJ(oStack[i].type) && oStack[i].val.o) oStack[i].val.o->GCMark(); } for (i = var_count + psvar - oStack - 1; i >= 0; i-- ) { if (IS_VMOBJ(vStack[i].type) && vStack[i].val.o) vStack[i].val.o->GCMark(); } } void wakeSleepingVM() { static Property * prop = 0; UseProperty( &prop, "VM_dozing_barrier", PROP_INT, "60", nf_gtz, true); int i; int doze = prop->getInt(); VMachine * vm; for ( i = sleepingVMs.length()-1 ; i >= 0; i -- ) { vm = sleepingVMs[i]; if ( vm->bigTick(doze) < 0 ) { sleepingVMs.remove(i); dozingVMs.add(vm); } } } void VMmark4GC() { int i; for ( i=dozingVMs.length()-1; i >=0; i--) dozingVMs[i]->mark(); for ( i=sleepingVMs.length()-1; i >=0; i--) sleepingVMs[i]->mark(); }