[Vm-dev] An event driven Squeak VM

Andreas Raab andreas.raab at gmx.de
Tue Nov 10 08:00:18 UTC 2009


Folks -

I had an interesting thought today that I'd like to run by you because I 
think it might just work. I have been thinking for a long time how to 
make the Squeak VM be "truly event driven" that is invoke it in response 
to OS or other events instead of having the VM poll. There are lots of 
good reasons for this starting from not blocking when popping up an OS 
context menu or standard dialog, over being able to embed the VM into 
other apps (browser plugin etc), up to properly dealing with 
suspend/resume. There are various problems that could be dealt with more 
easily if the VM would be truly event driven.

Today it occurred to me that there might be a relatively simple way to 
deal with that problem merely by 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



More information about the Vm-dev mailing list