Hi,
I'd like to make my interpreter run until there's no more work to do, and return. I'm not good enough to put things that you explained into coding. Can you show or lead me to get it work?
Or, maybe, can you share the source of event-driven Squeak VM, so that I can learn from the code?
Thanks.
Ang Beepeng
Andreas Raab wrote:
having interpret() run until "there is no more work to do" and return from interpret() when it's all said and done. The trick is that instead of running the idle loop, the VM would determine that it has no more work to do when there is no runnable process, so when it finds that there is no runnable process it would return from interpret saying "my work's done here, there is no more code to run at this point, ask me again when an external event comes in".
The changes would be fairly straight forward: First, nuke the idle loop and allow wakeHighestPriority to return nil when there's no runnable process. Second, have transferTo: do a longjmp to the registered vmExitBuf to leave interpret(). Third, have interpret register the vmExitBuf and wake up the highest priorty process like here:
interpret "install jmpbuf for main interpreter" (self setjmp: vmExitBuf) == 0 ifTrue:[ self checkForInterrupts. "timers etc" "transferTo: longjmps if arg is nil so no need to check" self transferTo: self wakeHighestPriority.
"this is the current interpret() implementation" self internalizeIPandSP.
self fetchNextBytecode. [true] whileTrue: [self dispatchOn: currentBytecode in: BytecodeTable].
].
At this point we can write a client loop that effectively looks like:
/* run the interpreter */ while(!done) { /* check for new events */ ioProcessEvents(); /* run processes resulting from the events */ interpret(); }
Now, obviously this is inefficient, we'd want to replace the ioProcessEvents() call with something more elaborate that reacts to the incoming OS events, takes the next scheduled delay into account, checks for socket handles etc. But I'm sure you're getting the idea. Instead of wasting our time in the idleProcess, we just return when there's no more work to do and it's up to the caller to run interpret() as often or as rarely as desired.
I also think that this scheme could be made backwards compatible by ensuring that we never call interpret() recursively. In this case an "old" image with the idle process would run the way it does today, and a "new" image without the idle process would live in the shiny new event driven world and return as needed.
What do you think? Any reasons why this wouldn't work?
Cheers,
- Andreas