diff --git a/src/run.c b/src/run.c new file mode 100644 index 0000000..ac9fb49 --- /dev/null +++ b/src/run.c @@ -0,0 +1,190 @@ +/* + VM handlers (and network message handlers) +*/ +#include "config.h" +#include "types.h" +#include "lexer.h" +#include "tokens.h" +#include "mem.h" +#include "reg.h" +#include "stack.h" +#include "ops.h" +#include "context.h" +#include "code.h" +#include "event.h" +#include "vm.h" +#include "var.h" +#include "printf.h" +#include "ccall.h" +#include "version.h" +#include "debug.h" +#include "cconst.h" +#include "net.h" +#include "run.h" +#include "debug.h" +#include "error.h" +#include "str.h" +#include "log.h" + +#ifdef IOAWAIT +/* + Main VM Execution and IO Loop + Returns: -1: error 0: no ready context, 1: ready context +*/ +int Loop(context_t *C0,char service) { + int error=0,status,idle=0,run=0,ready=0; + context_t *C=C0; // root context +#if DEBUG > 0 + log(LOGDEBUG1,"Loop: Enter.\n",NULL); +#endif + do { + C=C0; + idle=0;run=ready=0; + while (C) { + reg_t *R=C->R; +#if DEBUG>0 + log(LOGDEBUG2,"Loop: Context #%d ",CONTEXTID(C)); + if (log_level<=LOGDEBUG2) PrintState(C->R); +#endif + status=Run(C); + if (R->error) { + error=R->error; + break; + } + if (R->state&PIDLE) idle++; else run++; // still processing a program, maybe suspended + if (R->state&(PRUNNING|PHANDLER)) ready++; // pending VM ops + C=C->next; + } + if (!error && !ready && (run||service)) status=IOAWAIT(Context[0],ready); + } while (!error && (run||service)); +#if DEBUG > 0 + log(LOGDEBUG2,"Loop: Exit (ready=%d run=%d error=%d service=%d status=%d).\n",ready,run,error,service,status); +#endif + return error?-1:ready; +} +#else +/* + Main VM Execution Loop, embedded in an external main IO loop + Returns: -1: error 0: no ready context, 1: ready context +*/ +int Loop(context_t *C0) { + int error=0,status,idle=0,run=0,ready=0; + context_t *C=C0; // root context +#if DEBUG > 0 + log(LOGDEBUG2,"Loop enter.\n",NULL); +#endif + do { + C=C0; + idle=0;run=ready=0; + while (C) { + reg_t *R=C->R; +#if DEBUG>0 + log(LOGDEBUG2,"Loop: Context #%d ",CONTEXTID(C)); + if (log_level<=LOGDEBUG2) PrintState(C->R); +#endif + status=Run(C); + if (R->error) { + error=R->error; + break; + } + if (R->state&PIDLE) idle++; else run++; // still processing a program, maybe suspended + if (R->state&(PRUNNING|PHANDLER)) ready++; // pending VM ops + C=C->next; + } + } while (!error && ready); +#if DEBUG > 0 + log(LOGDEBUG2,"Loop: Exit (ready=%d run=%d error=%d service=%d status=%d).\n",ready,run,error,service,status); +#endif + return error?-1:ready; +} +#endif + +#if HAS_NET > 0 +/* + Program Code Message Handler +*/ +int MessageHandlerCode(port_t *P,message_type_t t) { + index_t top = P->rxTop; +#if PROFILE>0 + unsigned long t0,t1; +#endif + context_t *c=NULL; + lexer_t L; + mem_t *m; + if (!Context[0]) { P->rxBottom=top; return -1; } +#if DEBUG >0 + log(LOGDEBUG1,"MessageHandlerCode (%d) %d:[%s]\n",t,P->rxBottom,&P->rxBuffer[P->rxBottom]); +#endif + switch (t) { + case MSGPROGRAMPART: + c=Context[0]; + case MSGCOMMAND: + // compile and run command + // use 1 or 0 (if IDLE) for command lines + if (!c) c=Context[ContextTop>1?1:0]; + case MSGPROGRAM: + if (!c) c=Context[0]; // program for primary context + m=c->M; + if (string_cmp(&P->rxBuffer[P->rxBottom],"new",0)) { + // reset entire context chain including stacks, registers, events + ContextResetAll(NULL); + P->rxBottom=top; + return 0; + } + // TODO check IDLE state + if (t==MSGPROGRAM) ContextResetAll(NULL); // a new main program must reset the entire VM context chain! + else if (t==MSGCOMMAND) ContextReset(c); + log(LOGINFO,"MessageHandlerCode ContextReset(%d) \n",CONTEXTID(c)); +#if PROFILE>0 + t0=MICROS(); +#endif + // sync. compiling + Compile(&L,&P->rxBuffer[P->rxBottom],c,PRUNNING); + P->rxBottom=top; + if (P->rxBottom==P->rxTop) P->rxBottom=P->rxTop=0; +#if PROFILE>0 + t1=MICROS(); +#endif + if (c->R->error) { + log(LOGERROR,"Compiler error %d(%s) in line %d\n",c->R->error,Errors[c->R->error],L.line); +#if DEBUG >0 + PrintLexerToken(&L); +#endif + return -1; + } +#if PROFILE>0 + c->S->ntoken=L.ntoken; + c->S->micros=t1-t0; +#endif + log(LOGINFO,"MessageHandlerCode Done(%d) pc=%d state=%d\n",CONTEXTID(c),c->R->pc,c->R->state); + return 1; + break; + } + return -1; +} +/* handle received event message */ +int MessageHandlerEvent(port_t *P,message_type_t t) { + P->rxBottom=P->rxTop; +} +static index_t evmsgportall=-1; +/* handle received user message */ +int MessageHandlerUser(port_t *P,message_type_t t) { + // raise EVMESSAGE event + // speed up and cache event index + if (evmsgportall!=-1) { +#if DEBUG >0 + log(LOGDEBUG1,"MessageHandlerUser (%d)\n",evmsgportall); +#endif + RaiseEventIndex(evmsgportall); + return evmsgportall; + } + index_t evid=RaiseEvent("message",-1); // PORTALL + if (evid!=-1) evmsgportall=evid; +#if DEBUG >0 + log(LOGDEBUG1,"MessageHandlerUser (%d)\n",evid); +#endif + return evid; +} + + +#endif