[Vm-dev] An event driven Squeak VM

Andreas Raab andreas.raab at gmx.de
Tue Dec 8 08:38:30 UTC 2009

Hi Ang -

I haven't completed the work. At this point I've been able to run the 
VM, execute a blocking FFI call (MessageBox, OpenFile) have the VM run 
happily in the background until I hit OK in the dialog. When the VM 
should return from the callback, it violently crashes :( There is some 
state that isn't preserved correctly but it's hard to find these things. 
I'll keep folks informed how this unfolds.

   - Andreas

Ang BeePeng wrote:
> 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

More information about the Vm-dev mailing list