[squeak-dev] WorldState deferredUIMessages queue

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

[squeak-dev] WorldState deferredUIMessages queue

Chris Muller-4
(3.9 Morphic).  With Maui I occassionally get World lockups due to the
UI process waiting for the #next of the deferredUIMessages, which is
empty.

Specifically, the freeze, when it occurs, is always in
WorldState>>#runStepMethodsIn:.  There's a while loop to process
messages in the queue:

        "Dispatch deferred messages while maintaing rudimentary UI responsiveness."
        [i < numItems and: [(Time millisecondsSince: stamp) < limit]]
                whileTrue: [queue next value. i := i + 1].

and its hung waiting for "queue next".  But it seems like this
shouldn't be possible because, at the top of the method, "numItems" is
set to the size of the queue.

        numItems := queue size.

and so the only explanation is, somehow in processing one of the
messages, it causes another one to be removed from the queue.  This
appears to be possible if the first message calls a #doOneCycle,
leading it back through this same method..

I do have 4 or 5 #doOneCycles sprinkled around, in order to force
correct layout or screen redraws.  I'm pretty sure these are causing
the deadlock but.. when I tried taking some of them out I get the
layout/redraw problem..

Any advice is greatly appreciated.

 - Chris

Reply | Threaded
Open this post in threaded view
|

[squeak-dev] Re: WorldState deferredUIMessages queue

Andreas.Raab
Chris Muller wrote:

> (3.9 Morphic).  With Maui I occassionally get World lockups due to the
> UI process waiting for the #next of the deferredUIMessages, which is
> empty.
>
> Specifically, the freeze, when it occurs, is always in
> WorldState>>#runStepMethodsIn:.  There's a while loop to process
> messages in the queue:
>
> "Dispatch deferred messages while maintaing rudimentary UI responsiveness."
> [i < numItems and: [(Time millisecondsSince: stamp) < limit]]
> whileTrue: [queue next value. i := i + 1].

This is plain wrong. I don't know what the rationale of the change was
but you'll have much better success if you change this to e.g.,

        queue := self class deferredUIMessages.
        [(msg := queue nextOrNil) == nil] whileFalse: [
                msg value.
        ].

The reason why the original version is wrong is that there is absolutely
no assurance that some Morph won't call World doOneCycle which would
re-enter the above loop, pull out all of the events and leave the
original caller hanging; just as you report.

Cheers,
   - Andreas

Reply | Threaded
Open this post in threaded view
|

[squeak-dev] Re: WorldState deferredUIMessages queue

Andreas.Raab
In reply to this post by Chris Muller-4
Chris Muller wrote:
> Any advice is greatly appreciated.

Actually, here is a fun test to exercise the problem:

testDoOneCycleWorksWithDeferredQueue
        "Ensure that nested doOneCycles don't break deferred UI messages"
        | finished |
        [
                WorldState addDeferredUIMessage:[World doOneCycleNow].
                WorldState addDeferredUIMessage:["whatever"].
                World doOneCycleNow.
                finished := true.
        ] valueWithin: 1 second onTimeout:[finished := false].
        self assert: finished

Cheers,
   - Andreas


Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] Re: WorldState deferredUIMessages queue

Bert Freudenberg
In reply to this post by Andreas.Raab

On 24.03.2009, at 22:37, Andreas Raab wrote:

> Chris Muller wrote:
>> (3.9 Morphic).  With Maui I occassionally get World lockups due to  
>> the
>> UI process waiting for the #next of the deferredUIMessages, which is
>> empty.
>> Specifically, the freeze, when it occurs, is always in
>> WorldState>>#runStepMethodsIn:.  There's a while loop to process
>> messages in the queue:
>> "Dispatch deferred messages while maintaing rudimentary UI  
>> responsiveness."
>> [i < numItems and: [(Time millisecondsSince: stamp) < limit]]
>> whileTrue: [queue next value. i := i + 1].
>
> This is plain wrong. I don't know what the rationale of the change  
> was but you'll have much better success if you change this to e.g.,
>
> queue := self class deferredUIMessages.
> [(msg := queue nextOrNil) == nil] whileFalse: [
> msg value.
> ].
>
> The reason why the original version is wrong is that there is  
> absolutely no assurance that some Morph won't call World doOneCycle  
> which would re-enter the above loop, pull out all of the events and  
> leave the original caller hanging; just as you report.


FWIW, the 3.8 method looked like this:

        [queue isEmpty] whileFalse: [queue next value].

- Bert -


Reply | Threaded
Open this post in threaded view
|

[squeak-dev] Re: WorldState deferredUIMessages queue

Andreas.Raab
Bert Freudenberg wrote:

> On 24.03.2009, at 22:37, Andreas Raab wrote:
>> Chris Muller wrote:
>>> (3.9 Morphic).  With Maui I occassionally get World lockups due to the
>>> UI process waiting for the #next of the deferredUIMessages, which is
>>> empty.
>>> Specifically, the freeze, when it occurs, is always in
>>> WorldState>>#runStepMethodsIn:.  There's a while loop to process
>>> messages in the queue:
>>>     "Dispatch deferred messages while maintaing rudimentary UI
>>> responsiveness."
>>>     [i < numItems and: [(Time millisecondsSince: stamp) < limit]]
>>>         whileTrue: [queue next value. i := i + 1].
>>
>> This is plain wrong. I don't know what the rationale of the change was
>> but you'll have much better success if you change this to e.g.,
>>
>>     queue := self class deferredUIMessages.
>>     [(msg := queue nextOrNil) == nil] whileFalse: [
>>         msg value.
>>     ].
>>
>> The reason why the original version is wrong is that there is
>> absolutely no assurance that some Morph won't call World doOneCycle
>> which would re-enter the above loop, pull out all of the events and
>> leave the original caller hanging; just as you report.
>
>
> FWIW, the 3.8 method looked like this:
>
>     [queue isEmpty] whileFalse: [queue next value].
>

Which is not entirely safe either since there can a contention for the
queue inbetween #isEmpty and #next. We found this when we were still
using Morphic worlds in Croquet that would execute concurrently (bad
idea ;-)

Cheers
   - Andreas

Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] Re: WorldState deferredUIMessages queue

Igor Stasenko
Hmm.. what purpose of timestamp there?
Both variants (3.8 and Andreas) don't checking it.
Maybe the purspose of change were to include the timestamp checking,
but it was introduced a bug with incorrent queue handling.

2009/3/25 Andreas Raab <[hidden email]>:

> Bert Freudenberg wrote:
>>
>> On 24.03.2009, at 22:37, Andreas Raab wrote:
>>>
>>> Chris Muller wrote:
>>>>
>>>> (3.9 Morphic).  With Maui I occassionally get World lockups due to the
>>>> UI process waiting for the #next of the deferredUIMessages, which is
>>>> empty.
>>>> Specifically, the freeze, when it occurs, is always in
>>>> WorldState>>#runStepMethodsIn:.  There's a while loop to process
>>>> messages in the queue:
>>>>    "Dispatch deferred messages while maintaing rudimentary UI
>>>> responsiveness."
>>>>    [i < numItems and: [(Time millisecondsSince: stamp) < limit]]
>>>>        whileTrue: [queue next value. i := i + 1].
>>>
>>> This is plain wrong. I don't know what the rationale of the change was
>>> but you'll have much better success if you change this to e.g.,
>>>
>>>    queue := self class deferredUIMessages.
>>>    [(msg := queue nextOrNil) == nil] whileFalse: [
>>>        msg value.
>>>    ].
>>>
>>> The reason why the original version is wrong is that there is absolutely
>>> no assurance that some Morph won't call World doOneCycle which would
>>> re-enter the above loop, pull out all of the events and leave the original
>>> caller hanging; just as you report.
>>
>>
>> FWIW, the 3.8 method looked like this:
>>
>>    [queue isEmpty] whileFalse: [queue next value].
>>
>
> Which is not entirely safe either since there can a contention for the queue
> inbetween #isEmpty and #next. We found this when we were still using Morphic
> worlds in Croquet that would execute concurrently (bad idea ;-)
>
> Cheers
>  - Andreas
>
>



--
Best regards,
Igor Stasenko AKA sig.

Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] Re: WorldState deferredUIMessages queue

Chris Muller-3
In reply to this post by Andreas.Raab
Thanks, with the #nextOrNil approach I haven't had a lock up in the
last 24 hours.

I'm curious, though, like sig what the premise of the 3.9 timing "for
UI responsiveness" was about.  I didn't include it in my my fix for
now, I'm curious what the exact effect is..  Based on my observation,
to allow input events continue to be accepted always at a reasonable
rate (200 ms) gave the appearance of  "background" redraws, because
the MouseOver events were definitely firing while it was drawing..  An
interesting consideration, I'm not sure yet whether to prefer that or
the slight delay but with better overall Morph-drawing throughput,
which is what I get with the 3.8 approach..


On Tue, Mar 24, 2009 at 4:43 PM, Andreas Raab <[hidden email]> wrote:

> Chris Muller wrote:
>>
>> Any advice is greatly appreciated.
>
> Actually, here is a fun test to exercise the problem:
>
> testDoOneCycleWorksWithDeferredQueue
>        "Ensure that nested doOneCycles don't break deferred UI messages"
>        | finished |
>        [
>                WorldState addDeferredUIMessage:[World doOneCycleNow].
>                WorldState addDeferredUIMessage:["whatever"].
>                World doOneCycleNow.
>                finished := true.
>        ] valueWithin: 1 second onTimeout:[finished := false].
>        self assert: finished
>
> Cheers,
>  - Andreas
>
>
>

Reply | Threaded
Open this post in threaded view
|

[squeak-dev] Re: WorldState deferredUIMessages queue

Andreas.Raab
Chris Muller wrote:
> I'm curious, though, like sig what the premise of the 3.9 timing "for
> UI responsiveness" was about.  I didn't include it in my my fix for
> now, I'm curious what the exact effect is..  Based on my observation,
> to allow input events continue to be accepted always at a reasonable
> rate (200 ms) gave the appearance of  "background" redraws, because
> the MouseOver events were definitely firing while it was drawing..  An
> interesting consideration, I'm not sure yet whether to prefer that or
> the slight delay but with better overall Morph-drawing throughput,
> which is what I get with the 3.8 approach.

I suspect that the background of the change is some fairly application
specific situation. I could imagine that if someone fired tons and tons
and tons of deferred UI messages from a background thread this could
conceivably lead to a UI lockup since the UI does nothing but process
these messages. But I can't really see this happening since there are
few users of deferred UI messages.

In any case, we can have our cake and eat it, too by doing something
along the lines of:

        startTime := Time millisecondClockValue.
        [(msg := queue nextOrNil) == nil] whileFalse:[
                msg value.
                (Time millisecondsSince: startTime) > threshold ifTrue:[^self].
        ]

Cheers,
   - Andreas