[Cuis-dev] FW: FW: FW: Freezing UI - can't interrupt via Alt+.

Jaromir Matas mail at jaromir.net
Wed Aug 10 07:35:59 PDT 2022


Hi Juan,

Thank you very much for your brilliant explanations! Many missing pieces start to fit for me, thanks :)

Enclosing the .cs

> The implementation in Object is just to avoid creating references to UISupervisor all over the place

Makes perfect sense; I've just realized what confused me: the use of 'true' as a receiver :) I expected something like

`self runningWorld`

Sorry for the confusion, all clear now ;)

> #processPreemptionYields = false is the intended behavior in Smalltalk-80

Ahhh, I didn't know!

> In Cuis, no assumption is made. The way to protect access to Morphic state is to call #whenUIinSafeState: . So, #processPreemptionYields can be set to true. I believe this is what most people would expect in these days.

Yes! That was my naïve expectation when I started with Smalltalk (not long ago) but was utterly confused by Squeak's reverting (and sticking) to the cooperative mode. Preemptive multitasking is indeed less restricted and offers no "cheap" guarantee the processes of the same priority won't interleave (yield) but that's part of the fun to make things work even without the assumption :D

Many thanks again for the brain food :)
Best,
Jaromir

--

Jaromír Matas

mail at jaromir.net

From: Juan Vuletich<mailto:juan at cuis.st>
Sent: Wednesday, August 10, 2022 15:41
To: Discussion of Cuis Smalltalk<mailto:cuis-dev at lists.cuis.st>
Cc: Jaromir Matas<mailto:mail at jaromir.net>
Subject: Re: [Cuis-dev] FW: FW: FW: Freezing UI - can't interrupt via Alt+.

Hi Jaromir,

On 8/10/2022 9:24 AM, Jaromir Matas via Cuis-dev wrote:
Hi Juan,

I very much like your simplifying the code opening a debugger :)

I'm still just skimming the surface of the UI implementation but I'd like to ask a few questions:

(1) why is there Object >> #runningWorld
- wouldn't sending `UISupervisor runningWorld` instead of `true runningWorld` be sufficient e.g. in Debugger >> #openWindowLabel:usePreDebugWindow:preDebugMessage:?

Yes, of course. The implementation in Object is just to avoid creating references to UISupervisor all over the place, in case some day we want to replace it with something else. It is just that I wasn't so sure about UISupervisor when I created it. Not a big deal, IMO.


(2) Why not define UISupervisor >> runningWorld via #animatedUIOf: to avoid code duplicity?

UISupervisor >> runningWorld
                "
                UISupervisor runningWorld
                [ UISupervisor runningWorld print ] fork
                "
                ^self animatedUIOf: Processor activeProcess

Yeah. Good idea. Just post the .cs, so it has your initials :)


(3) I understand your intention when you lowered the former UI process's priority in #spawnNewMorphicProcessFor: by one; I believe it was in response to this example:

[1/0] fork.
5 seconds asDelay wait.
self error: 'error'

I've been wondering whether it's still relevant after your most recent changes - and unfortunately it seems that it is: changing the former UI process's priority back to the active priority will cause redraw glitches (e.g. Transcript background color in Dark mode won't display properly).

However, there seems to be a very similar redraw blip *despite* the lower priority tweak when running e.g.
[1/0] fork.
[1/0] fork
... the Transcript window won't get redrawn correctly in the Dark mode: it won't change its background color properly. It puzzles me why the Transcript window is the only one affected.

The Transcript is special. It will do the same in any Theme, although the difference may be less obvious. Try `1 to: 4 do: [ :i | i print. 100000 factorial ]` in a Workspace. Do it with another window partially covering the Transcript. The thing here is that the Transcript gets immediate updates, without waiting for the next Morphic cycle. This is extremely useful for debugging, and especially for debugging Morphic itself. Browse a bit Transcript and you'll see.

The reason to lower the older Morphic priority is to guarantee a responsive UI, a focus of yours in the last months. Besides, given that (see below) in Cuis two processes of the same priority can interrupt each other at any time, and given that Morphic is not thread safe, then, as we want the old Morphic process to finish its stuff (as many of your examples required), we need to make that with a lower priority than the main UI process, to reduce the risk of the old process breaking state needed by the new one.


What I'm trying to figure out is: if the computation carried out by this former UI process involves references to Processor activePriority the priority-lowering tweak may change the semantics of a computation involving forking processes at different relative priorities (in other words changing the priority of the process in the middle of the computation by an *unrelated* "outsider" process feels dangerous); just a theoretical idea though, unfortunately I don't have any practical example or any further suggestion; I'll return to this later after some more educating myself :)

But it is not an *unrelated* process. It is the UISupervisor, who created it in the first place, gave it the chore of running the World, and is now replacing it with a new one.


About the processPreemptionYields flag:

> I think it would be important to understand why would someone want #processPreemptionYields = false. Their reasons for requesting a process to never yield to others of same priority (even if some higher process wakes up in between) may also mean they don't want new UI processes to be started so lightly.

Here's Eliot's explanation why he chose #processPreemptionYields = false over the previous functionality: https://forum.world.st/about-signal-tp5109735p5109862.html

I know. I've been here since before Squeak ran Morphic, and it was MVC only. I understand MVC process scheduling in Smalltalk-80 and its evolution through Morphic.

#processPreemptionYields = false is the intended behavior in Smalltalk-80. In Smalltalk-80 a process can only be preempted by one of a higher priority. This means that no real access protection is needed between processes of the same priority (given that they only #yield at safe places). This is akin to Corroutines (and #resumeNext semantics). But the original Squeak VM, when resuming a high priority process, will put the active process at the back of the process queue, possibly breaking older code. This is the #processPreemptionYields = true behavior. Squeak needed then to adapt to this behavior. Much later, Eliot added the #processPeemptionYields = false to restore the original Smalltalk-80 intended behavior, which could be safer for code unaware of these issues.

In Cuis, no assumption is made. The way to protect access to Morphic state is to call #whenUIinSafeState: . So, #processPreemptionYields can be set to true. I believe this is what most people would expect in these days. The last mainstream OS that switched from "cooperative multitasking" to "preemptive multitasking" was MacOS about 20 years ago!


My understanding is he simply thinks #processPreemptionYields = true produces an inconsistent/erroneous behavior in the sense that unless a process *explicitly* yields control it should stay in control (unless preempted by a higher priority process in which case it should get back control once the higher priority process gives up control, i.e. stay at the front of the run queue).

In case of Squeak (which is on #processPreemptionYields = false) each world cycle does contain an explicit yield anyway so opening each debugger in a new UI doesn't seem to clash with this stricter cooperative-within-priorities scheduling approach imho :)

A while ago I asked Marcel about the preemption modes and the answer was (roughly) that #processPreemptionYields = false offers more predictability (understandably) plus something about thread-safe-ness of Morphic structures (which is still way beyond my skills level).

Is there a reason why you'd prefer #processPreemptionYields = true or is it just for historic reasons? ("why fix something that works" type of situation? :) )

Absolutely the contrary!

#processPreemptionYields = false is to keep the Smalltalk-80 cooperative multitasking style that was widespread until mid 90's, when Linux and Windows made the transition, followed a few years later by MacOS. In Cuis we explicitly made the change to #processPreemptionYields = true about a decade ago to be in line with modern practice. In doing so, I needed to come up with #whenUIinSafeState: and make sure that nothing broke. Another situation where Cuis favors progress in spite of back compatibility.




Thanks again very much for discussing these issues!

Best regards,
Jaromir


--

Jaromír Matas

mail at jaromir.net<mailto:mail at jaromir.net>


Cheers,


--

Juan Vuletich

cuis.st

github.com/jvuletich

researchgate.net/profile/Juan-Vuletich

independent.academia.edu/JuanVuletich

patents.justia.com/inventor/juan-manuel-vuletich

linkedin.com/in/juan-vuletich-75611b3

twitter.com/JuanVuletich

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.cuis.st/mailman/archives/cuis-dev/attachments/20220810/20dafa78/attachment-0001.htm>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: UISupervisor class-runningWorld.st
Type: application/octet-stream
Size: 285 bytes
Desc: UISupervisor class-runningWorld.st
URL: <http://lists.cuis.st/mailman/archives/cuis-dev/attachments/20220810/20dafa78/attachment-0001.obj>


More information about the Cuis-dev mailing list