VM will no longer block cooperative multitasking.
This commit is contained in:
parent
eb5e4e567e
commit
626befa664
1 changed files with 56 additions and 57 deletions
|
|
@ -20,6 +20,11 @@
|
||||||
// Prototypes
|
// Prototypes
|
||||||
// ============================================================
|
// ============================================================
|
||||||
|
|
||||||
|
// Steps to execute between doEvents yields during subroutine calls.
|
||||||
|
// This keeps the GUI responsive without excessive overhead from
|
||||||
|
// calling doEvents on every instruction.
|
||||||
|
#define SUB_YIELD_INTERVAL 500
|
||||||
|
|
||||||
static BasCallFrameT *currentFrame(BasVmT *vm);
|
static BasCallFrameT *currentFrame(BasVmT *vm);
|
||||||
static void defaultPrint(void *ctx, const char *text, bool newline);
|
static void defaultPrint(void *ctx, const char *text, bool newline);
|
||||||
static BasVmResultE execArith(BasVmT *vm, uint8_t op);
|
static BasVmResultE execArith(BasVmT *vm, uint8_t op);
|
||||||
|
|
@ -37,6 +42,51 @@ static uint16_t readUint16(BasVmT *vm);
|
||||||
static void runtimeError(BasVmT *vm, int32_t errNum, const char *msg);
|
static void runtimeError(BasVmT *vm, int32_t errNum, const char *msg);
|
||||||
|
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// runSubLoop -- shared inner loop for basVmCallSub variants
|
||||||
|
// ============================================================
|
||||||
|
//
|
||||||
|
// Executes instructions until callDepth drops back to savedCallDepth
|
||||||
|
// (meaning the subroutine returned). Periodically yields via the
|
||||||
|
// doEvents callback to keep the GUI responsive during long-running
|
||||||
|
// event handlers.
|
||||||
|
|
||||||
|
static bool runSubLoop(BasVmT *vm, int32_t savedPc, int32_t savedCallDepth, bool savedRunning) {
|
||||||
|
int32_t stepsSinceYield = 0;
|
||||||
|
|
||||||
|
while (vm->running && vm->callDepth > savedCallDepth) {
|
||||||
|
BasVmResultE result = basVmStep(vm);
|
||||||
|
|
||||||
|
if (result == BAS_VM_HALTED) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result != BAS_VM_OK) {
|
||||||
|
vm->pc = savedPc;
|
||||||
|
vm->callDepth = savedCallDepth;
|
||||||
|
vm->running = savedRunning;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Yield periodically to keep the GUI responsive
|
||||||
|
if (++stepsSinceYield >= SUB_YIELD_INTERVAL) {
|
||||||
|
stepsSinceYield = 0;
|
||||||
|
|
||||||
|
if (vm->doEventsFn) {
|
||||||
|
if (!vm->doEventsFn(vm->doEventsCtx)) {
|
||||||
|
vm->running = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vm->pc = savedPc;
|
||||||
|
vm->running = savedRunning;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
// basVmCallSub
|
// basVmCallSub
|
||||||
// ============================================================
|
// ============================================================
|
||||||
|
|
@ -70,26 +120,7 @@ bool basVmCallSub(BasVmT *vm, int32_t codeAddr) {
|
||||||
vm->pc = codeAddr;
|
vm->pc = codeAddr;
|
||||||
vm->running = true;
|
vm->running = true;
|
||||||
|
|
||||||
// Run until the SUB returns (callDepth drops back).
|
return runSubLoop(vm, savedPc, savedCallDepth, savedRunning);
|
||||||
// No step limit -- event handlers must run to completion.
|
|
||||||
while (vm->running && vm->callDepth > savedCallDepth) {
|
|
||||||
BasVmResultE result = basVmStep(vm);
|
|
||||||
|
|
||||||
if (result == BAS_VM_HALTED) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result != BAS_VM_OK) {
|
|
||||||
vm->pc = savedPc;
|
|
||||||
vm->callDepth = savedCallDepth;
|
|
||||||
vm->running = savedRunning;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vm->pc = savedPc;
|
|
||||||
vm->running = savedRunning;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -127,24 +158,7 @@ bool basVmCallSubWithArgs(BasVmT *vm, int32_t codeAddr, const BasValueT *args, i
|
||||||
vm->pc = codeAddr;
|
vm->pc = codeAddr;
|
||||||
vm->running = true;
|
vm->running = true;
|
||||||
|
|
||||||
while (vm->running && vm->callDepth > savedCallDepth) {
|
return runSubLoop(vm, savedPc, savedCallDepth, savedRunning);
|
||||||
BasVmResultE result = basVmStep(vm);
|
|
||||||
|
|
||||||
if (result == BAS_VM_HALTED) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result != BAS_VM_OK) {
|
|
||||||
vm->pc = savedPc;
|
|
||||||
vm->callDepth = savedCallDepth;
|
|
||||||
vm->running = savedRunning;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vm->pc = savedPc;
|
|
||||||
vm->running = savedRunning;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -181,25 +195,12 @@ bool basVmCallSubWithArgsOut(BasVmT *vm, int32_t codeAddr, const BasValueT *args
|
||||||
vm->pc = codeAddr;
|
vm->pc = codeAddr;
|
||||||
vm->running = true;
|
vm->running = true;
|
||||||
|
|
||||||
while (vm->running && vm->callDepth > savedCallDepth) {
|
bool ok = runSubLoop(vm, savedPc, savedCallDepth, savedRunning);
|
||||||
BasVmResultE result = basVmStep(vm);
|
|
||||||
|
|
||||||
if (result == BAS_VM_HALTED) {
|
// Read back modified locals before the frame is reused.
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result != BAS_VM_OK) {
|
|
||||||
vm->pc = savedPc;
|
|
||||||
vm->callDepth = savedCallDepth;
|
|
||||||
vm->running = savedRunning;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read back modified locals before restoring state.
|
|
||||||
// The frame at savedCallDepth still has the data even
|
// The frame at savedCallDepth still has the data even
|
||||||
// though callDepth was decremented by RET.
|
// though callDepth was decremented by RET.
|
||||||
if (outArgs && outCount > 0) {
|
if (ok && outArgs && outCount > 0) {
|
||||||
BasCallFrameT *doneFrame = &vm->callStack[savedCallDepth];
|
BasCallFrameT *doneFrame = &vm->callStack[savedCallDepth];
|
||||||
|
|
||||||
for (int32_t i = 0; i < outCount && i < BAS_VM_MAX_LOCALS; i++) {
|
for (int32_t i = 0; i < outCount && i < BAS_VM_MAX_LOCALS; i++) {
|
||||||
|
|
@ -207,9 +208,7 @@ bool basVmCallSubWithArgsOut(BasVmT *vm, int32_t codeAddr, const BasValueT *args
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vm->pc = savedPc;
|
return ok;
|
||||||
vm->running = savedRunning;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue