Win32 Event VM prototype

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

Win32 Event VM prototype

Andreas.Raab
 
Folks -

I just finished a prototype of the Win32 event VM to illustrate some of
the practical impact. It makes a really nice demo:

1) Download the VM from

    http://squeakvm.org/win32/experimental/Squeak-3.11-EventVM.zip

2) Fire up an image with this VM (I used a trunk image) and execute

    AbstractSound stereoBachFugue play.

3) Observe the sound behavior you get when you:
    * drag the window around
    * go to the system menu
    * click the window close button
In all of the above situations the sound play will be interrupted,
replaying the current buffer over and over.

4) Execute the following:

    (ProcessorScheduler classPool at: #BackgroundProcess) terminate.

You should see a printf that tells you "entering windows main loop"
which indicates that you're now running under the new regime.

5) Observe the sound behavior you get when you:
    * drag the window around
    * go to the system menu
    * click the window close button
In all of these situations the sound will now keep playing. There can be
a temporary hickup due to lack of buffering but other than that
everything continues smoothly.

For those interested I'm attaching the relevant changes (only for
playing around; these changes are NOT ready to be integrated). The
Windows main loop has been changed to read like here:

   /* prepare active process and do first time interpret() for old images */
   prepareActiveProcess();
   /* do not allow recursive interpret() */
   allowInterpret = 0;
   /* interpret() will be left after nuking background process */
   interpret();

   /* now do a classic Windows main loop */
   printf("Entering Windows Main Loop\n");
   SetTimer(stWindow, 1, 50, NULL); /* make sure we interpret() every
50ms */
   allowInterpret = 1; /* okay to interpret() now */
   while (GetMessage(&msg, NULL, 0, 0) > 0) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
   }

and then you call interpret() whenever you feel like it. I'm doing that
from MainWndProc in response to Windows messages:

   /* A bit of extra paranoia: I'm not sure if calling interpret()
      through checkForInterrupt() recursion into ioProcessEvents()
      is safe (probably not). */
   if(!inProcessEvents && allowInterpret) interpret();

Of course, this isn't finished yet by any means. There are some odd
effects when a recursion does happen, and somewhere I'm loosing events.
But I think it does illustrate the point that I'm trying to make.

BTW, does anyone know if wxSqueak is still active? I think the behavior
of this VM would be a perfect fit for their needs.

Cheers,
   - Andreas


EventVM.1.cs (10K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: Win32 Event VM prototype

Stephen Pair
 
Andreas,

I think this recursion situation will lead to undesirable concurrency safety issues (you are interrupting squeak processes at unpredictable and likely unsafe points).  I'm sure you already know this.  I mentioned having two calls, one for interpret() and another for handling events (let's call it sendMessage()).  The latter (sendMessage()) might be implemented by having a general call that, rather than scheduling and interpreting all active squeak processes, just dispatches and executes one specific message uninterruptably and returns without allowing other processes to be scheduled.  You would somehow need to interrupt interpret() if it is actively running squeak processes for the duration of sendMessage() and you would probably want to disable GC during this call.  It might also work to simply make sendMessage() wait until interpret() completes (but then I think you might be more at the mercy of OS buffer overflow handling behavior rather than be able to do something more intelligent in  overflow situations inside your message enqueueing logic (i.e. giving priority to certain kinds of events while more eagerly dropping others)).

You would call sendMessage() in response to Windows messages (it would do nothing but safely and quickly enqueue messages for interpret()).  You could have a third call, waitUntilRunnable() and then you would have a loop in an OS level thread that repeatedly calls waitUntilRunnable() followed by interpret().  The Windows messages would be calling sendMessage() to unblock waitUntilRunnable() and queue up work for interpret().

- Stephen

On Sat, Nov 14, 2009 at 1:02 AM, Andreas Raab <[hidden email]> wrote:
 
Folks -

I just finished a prototype of the Win32 event VM to illustrate some of the practical impact. It makes a really nice demo:

1) Download the VM from

  http://squeakvm.org/win32/experimental/Squeak-3.11-EventVM.zip

2) Fire up an image with this VM (I used a trunk image) and execute

  AbstractSound stereoBachFugue play.

3) Observe the sound behavior you get when you:
  * drag the window around
  * go to the system menu
  * click the window close button
In all of the above situations the sound play will be interrupted, replaying the current buffer over and over.

4) Execute the following:

  (ProcessorScheduler classPool at: #BackgroundProcess) terminate.

You should see a printf that tells you "entering windows main loop" which indicates that you're now running under the new regime.

5) Observe the sound behavior you get when you:
  * drag the window around
  * go to the system menu
  * click the window close button
In all of these situations the sound will now keep playing. There can be a temporary hickup due to lack of buffering but other than that everything continues smoothly.

For those interested I'm attaching the relevant changes (only for playing around; these changes are NOT ready to be integrated). The Windows main loop has been changed to read like here:

 /* prepare active process and do first time interpret() for old images */
 prepareActiveProcess();
 /* do not allow recursive interpret() */
 allowInterpret = 0;
 /* interpret() will be left after nuking background process */
 interpret();

 /* now do a classic Windows main loop */
 printf("Entering Windows Main Loop\n");
 SetTimer(stWindow, 1, 50, NULL); /* make sure we interpret() every 50ms */
 allowInterpret = 1; /* okay to interpret() now */
 while (GetMessage(&msg, NULL, 0, 0) > 0) {
       TranslateMessage(&msg);
       DispatchMessage(&msg);
 }

and then you call interpret() whenever you feel like it. I'm doing that from MainWndProc in response to Windows messages:

 /* A bit of extra paranoia: I'm not sure if calling interpret()
    through checkForInterrupt() recursion into ioProcessEvents()
    is safe (probably not). */
 if(!inProcessEvents && allowInterpret) interpret();

Of course, this isn't finished yet by any means. There are some odd effects when a recursion does happen, and somewhere I'm loosing events. But I think it does illustrate the point that I'm trying to make.

BTW, does anyone know if wxSqueak is still active? I think the behavior of this VM would be a perfect fit for their needs.

Cheers,
 - Andreas



Reply | Threaded
Open this post in threaded view
|

Re: Win32 Event VM prototype

Igor Stasenko

2009/11/14 Stephen Pair <[hidden email]>:
>
> Andreas,
> I think this recursion situation will lead to undesirable concurrency safety issues (you are interrupting squeak processes at unpredictable and likely unsafe points). I'm sure you already know this.  I mentioned having two calls, one for interpret() and another for handling events (let's call it sendMessage()).  The latter (sendMessage()) might be implemented by having a general call that, rather than scheduling and interpreting all active squeak processes, just dispatches and executes one specific message uninterruptably and returns without allowing other processes to be scheduled.  You would somehow need to interrupt interpret() if it is actively running squeak processes for the duration of sendMessage() and you would probably want to disable GC during this call.  It might also work to simply make sendMessage() wait until interpret() completes (but then I think you might be more at the mercy of OS buffer overflow handling behavior rather than be able to do something more intelligent in  overflow situations inside your message enqueueing logic (i.e. giving priority to certain kinds of events while more eagerly dropping others)).
> You would call sendMessage() in response to Windows messages (it would do nothing but safely and quickly enqueue messages for interpret()).  You could have a third call, waitUntilRunnable() and then you would have a loop in an OS level thread that repeatedly calls waitUntilRunnable() followed by interpret().  The Windows messages would be calling sendMessage() to unblock waitUntilRunnable() and queue up work for interpret().

i'm not sure i get everything.. but given the complexity and
constraints (non-interruptable, no GC).. is a bit high.
I think better would be to make sure there is no recursive call to
interpret(), rather than deal with consequences.
I'm already proposed that.

> - Stephen
> On Sat, Nov 14, 2009 at 1:02 AM, Andreas Raab <[hidden email]> wrote:
>>
>>
>> Folks -
>>
>> I just finished a prototype of the Win32 event VM to illustrate some of the practical impact. It makes a really nice demo:
>>
>> 1) Download the VM from
>>
>>   http://squeakvm.org/win32/experimental/Squeak-3.11-EventVM.zip
>>
>> 2) Fire up an image with this VM (I used a trunk image) and execute
>>
>>   AbstractSound stereoBachFugue play.
>>
>> 3) Observe the sound behavior you get when you:
>>   * drag the window around
>>   * go to the system menu
>>   * click the window close button
>> In all of the above situations the sound play will be interrupted, replaying the current buffer over and over.
>>
>> 4) Execute the following:
>>
>>   (ProcessorScheduler classPool at: #BackgroundProcess) terminate.
>>
>> You should see a printf that tells you "entering windows main loop" which indicates that you're now running under the new regime.
>>
>> 5) Observe the sound behavior you get when you:
>>   * drag the window around
>>   * go to the system menu
>>   * click the window close button
>> In all of these situations the sound will now keep playing. There can be a temporary hickup due to lack of buffering but other than that everything continues smoothly.
>>
>> For those interested I'm attaching the relevant changes (only for playing around; these changes are NOT ready to be integrated). The Windows main loop has been changed to read like here:
>>
>>  /* prepare active process and do first time interpret() for old images */
>>  prepareActiveProcess();
>>  /* do not allow recursive interpret() */
>>  allowInterpret = 0;
>>  /* interpret() will be left after nuking background process */
>>  interpret();
>>
>>  /* now do a classic Windows main loop */
>>  printf("Entering Windows Main Loop\n");
>>  SetTimer(stWindow, 1, 50, NULL); /* make sure we interpret() every 50ms */
>>  allowInterpret = 1; /* okay to interpret() now */
>>  while (GetMessage(&msg, NULL, 0, 0) > 0) {
>>        TranslateMessage(&msg);
>>        DispatchMessage(&msg);
>>  }
>>
>> and then you call interpret() whenever you feel like it. I'm doing that from MainWndProc in response to Windows messages:
>>
>>  /* A bit of extra paranoia: I'm not sure if calling interpret()
>>     through checkForInterrupt() recursion into ioProcessEvents()
>>     is safe (probably not). */
>>  if(!inProcessEvents && allowInterpret) interpret();
>>
>> Of course, this isn't finished yet by any means. There are some odd effects when a recursion does happen, and somewhere I'm loosing events. But I think it does illustrate the point that I'm trying to make.
>>
>> BTW, does anyone know if wxSqueak is still active? I think the behavior of this VM would be a perfect fit for their needs.
>>
>> Cheers,
>>  - Andreas
>>
>>
>
>
>



--
Best regards,
Igor Stasenko AKA sig.
Reply | Threaded
Open this post in threaded view
|

Re: Win32 Event VM prototype

Andreas.Raab
In reply to this post by Stephen Pair
 
Stephen Pair wrote:
> You would call sendMessage() in response to Windows messages (it would
> do nothing but safely and quickly enqueue messages for interpret()).
> You could have a third call, waitUntilRunnable() and then you would
> have a loop in an OS level thread that repeatedly calls
> waitUntilRunnable() followed by interpret().  The Windows messages would
> be calling sendMessage() to unblock waitUntilRunnable() and queue up
> work for interpret().

Interestingly, we have all that just under different names. The
sendMessage() call is implemented in C (via recordMouseEvent,
recordKeyboardEvent etc) in such that its purpose is to "safely and
quickly enqueues the nessage for interpret" ;-)

The function waitUntilRunnable() is implemented implicitly via having
interpret call from the MainWndProc (which isn't called unless there's
an event) but in an earlier version I wrote a more explicit loop like:

   while(1) {
     /* here goes waitUntilRunnable */
     ioRelinquishProcessorForMicroseconds(1000);
     ioProcessEvents();
     /* and finally interpret() */
     interpret();
   }

The issue with recursion is not as difficult as it might seem. The
important thing (as you said) is knowing when a callback is "safe". And
that's actually quite easy to determine - callbacks are safe if and only
if you're in a primitive because only then all necessary interpreter
state is sufficiently externalized. The callbackEnter implementation
already makes use of that and I just haven't adapted all the necessary
code. (I did prevent callbacks via ioProcessEvents since this is called
from checkForInterrupts in strange places but that doesn't seem to be
enough).

Cheers,
   - Andreas