[squeak-dev] Freezing UI issue

Marcel Taeumel marcel.taeumel at hpi.de
Thu Jul 7 08:44:38 UTC 2022


Nope. ;-) You are encode the fact that "Processor activeProcess" is usually a UI process and thus the one where debugger actions originate.

But we should not have to rely on that.

>From a generic perspective
   "Processor activeProcess" is not directly related to "Project current uiProcess" 

Thus, I think that
   uiProcess == Project current uiProcess

Would be the better check. But we would need an extra temp binding:

| thisUIProcess |
thisUIProcess := [ ... uiProcess == thisUIProcess] ...
uiProcess := thisUIProcess.

Or something like that.

Best,
Marcel
Am 07.07.2022 10:36:35 schrieb Jaromir Matas <mail at jaromir.net>:
>> It's because uiProcess registers the process considered the active UI, so if an "inactive UI" tries the condition, it fails and leaves the cycle.
 
> Well, you want to check whether "I am the currently one and only UI process", right? If not, terminate as quickly as possible. It's not about #isActiveProcess but it is about "being the right one".
 
Precisely! The UI loop exit condition should check "I'm the right UI process" which I hoped  would translate to
                Processor activeProcess "I" == "am" uiProcess "the right one"
:)
Best,
Jaromir
 
From: Marcel Taeumel [mailto:marcel.taeumel at hpi.de]
Sent: Thursday, July 7, 2022 9:50
To: squeak-dev [mailto:squeak-dev at lists.squeakfoundation.org]
Subject: Re: [squeak-dev] Freezing UI issue
 
> It's because uiProcess registers the process considered the active UI, so if an "inactive UI" tries the condition, it fails and leaves the cycle.
 
Well, you want to check whether "I am the currently one and only UI process", right? If not, terminate as quickly as possible. It's not about #isActiveProcess but it is about "being the right one".
 
Best,
Marcel
Am 06.07.2022 14:18:28 schrieb Jaromir Matas <mail at jaromir.net>:
Hi Marcel,
 
many thanks for your feedback!
 
> Process simulation would not work, right?
 
Hmm, it didn't occur to me, thanks! I'll have to think about it...
 
> And if we argue that no one wants to simulate a Morphic UI process at that level, I would argue that no Morphic application code should wait for a custom semaphore in the UI loop. ;-)
 
Simulating a Morphic UI process sounds legitimate, of course :) As for a Morphic app using a custom semaphore - I hear your arguments; I've come across this just recently when added a semaphore to #terminate - which means any Morphic application that would call #terminate would end up waiting on a semaphore - but as you pointed out, Alt+. breaks the wait; and Abandoning the debugger works without blocking.
 
> The fact that we can actually closure the binding while creating it is nice, but do we have to rely on this really to fix our problem?
 
I lack experience to judge but Juan kindly agreed to try this setup in Cuis so I'll keep you posted :)
 
> Finally, I think you actually want to check
> uiProcess == Project current uiProcess
> because
> uiProcess isActiveProcess
> would always be true at that point.
 
No, I think it's right, because
uiProcess isActiveProcess
is equivalent to
Processor activeProcess == uiProcess
It's because uiProcess registers the process considered the active UI, so if an "inactive UI" tries the condition, it fails and leaves the cycle.
(I think `uiProcess == Project current uiProcess` is always true in the context of Morphic project)
 
Thanks again very much for discussing this; I'll keep playing with this and if I find something interesting I'll come back.
Best,
Jaromir
 
--
Jaromír Matas
mail at jaromir.net
 
From: Jaromir Matas [mailto:mail at jaromir.net]
Sent: Wednesday, July 6, 2022 10:25
To: The general-purpose Squeak developers list [mailto:squeak-dev at lists.squeakfoundation.org]
Subject: Re: [squeak-dev] Freezing UI issue
 
Hi Marcel, all,
 
I’ve sent Morphic-jar.2018 to the Inbox; it's a modification of the UI loop that adds an "exit condition" to the UI loop to allow a former UI process to finish its last cycle and terminate automatically. This change could allow UI processes blocked on custom semaphores to continue waiting for a signal and finish their previous job before terminating automatically.
 
As an immediate bonus, it allows to create a new UI without the need to explicitly terminate the old one because a UI process will terminate automatically once it's replaced by a new one. Also, it prevents two UI processes to exist at the same time; only the one registered in the 'uiProcess' variable is allowed to cycle.
 
Many thanks for any feedback.
 
Best,
Jaromir
 
 
From: Jaromir Matas [mailto:mail at jaromir.net]
Sent: Monday, July 4, 2022 14:58
To: The general-purpose Squeak developers list [mailto:squeak-dev at lists.squeakfoundation.org]
Subject: Re: [squeak-dev] Freezing UI issue
 
Hi Marcel, all
 
thanks again for your time;  I've been thinking about your comments and yes, my main argument is really about consistency: I'd like to expect that the following examples will behave similarly, i.e. regardless of whether the code is run in the UI or not:
 
s := Semaphore new.
[[1/0] ensure: [s signal]] fork.
s wait.
Transcript cr; show: 'done'
 
[s := Semaphore new.
[[1/0] ensure: [s signal]] fork.
s wait.
Transcript cr; show: 'done'] fork
 
There are two important points:
1) The UI should stay blocked until it receives the signal and then should be able to continue (i.e. 'done' should be printed after closing the debugger, not before)
2) The old UI process must not be allowed to keep cycling
 
The idea is: To keep the system responsive, start a new UI process and let the old one finish just its last cycle and then *terminate*; please check the attached changeset; this is how automatically terminating a former UI process could work:
 
#spawnNewProcess
 
                uiProcess := [
                                [world doOneCycle. Project uiProcess isActiveProcess ifFalse: [Processor terminateActive]. Processor yield] repeat.
                ] newProcess priority: Processor userSchedulingPriority.
                uiProcess resume
 
I can't judge whether this is an acceptable change and what the system-wide consequences might be. If you try
 
Project current spawnNewProcess
 
the new UI just replaces the old one and the old one terminates.
 
Please take this as just exploring possible ways to solve the issue in case it is something we would like solved :) I don't have an urgent problem I need to fix; it's just a functionality (increased consistency) I'd consider an improvement :) (provided the solution is very simple and maintainable)
 
Thanks a lot for your ideas.
 
Best,
Jaromir
 
--
Jaromír Matas
mail at jaromir.net
 
From: Jaromir Matas [mailto:mail at jaromir.net]
Sent: Sunday, July 3, 2022 15:09
To: The general-purpose Squeak developers list [mailto:squeak-dev at lists.squeakfoundation.org]
Subject: Re: [squeak-dev] Freezing UI issue
 
Hi Marcel,
 
>> Could we check if the UI process is waiting on interCycleDelay semaphore to exclude the inter cycle pause case?
 
> Such an explicit check would be smelly and increase maintenance cost and impair readability and information hiding and... :-)
 
Yes, yes, I see, a bad idea :)
 
> This is where I would urge you to stop and *really* think about whether we need to fix this.
 
Well, *need to fix this* means there's something broken; I don't know whether it's broken; it's just that I expected the example
 
                s := Semaphore new.
                [1/0. s signal] fork.
                s wait.
 
just "work" without freezing the UI :) I'm aware of the reason why it's not and starting to understand it may be pretty tricky to "fix" it :)
 
So in the end it's just a question of consistency of the behavior regardless whether the process is UI or not.
 
In the special case of #terminate I have an ugly workaround to keep the UI responsive during errors inside unwind blocks but imo #terminate shouldn't really care whether it terminates a UI or non-UI process... I'm talking about this example where you *terminate* instead of abandon the debugger after the halt:
                [self halt] ensure: [self error]
 
> Besides experimentation in a workspace, what kind of Morphic application would actively wait on a custom semaphore in the UI process?
 
No idea, frankly, but I haven't written any Morphic app yet ;)
 
Thanks very much for taking the time to discuss this,
Best,
Jaromir
 
--
Jaromír Matas
mail at jaromir.net
 
From: Marcel Taeumel [mailto:marcel.taeumel at hpi.de]
Sent: Sunday, July 3, 2022 13:29
To: squeak-dev [mailto:squeak-dev at lists.squeakfoundation.org]
Subject: Re: [squeak-dev] Freezing UI issue
 
Hi Jaromir --
 
> Could we check if the UI process is waiting on interCycleDelay semaphore to exclude the inter cycle pause case?
 
This is where I would urge you to stop and *really* think about whether we need to fix this. Such an explicit check would be smelly and increase maintenance cost and impair readability and information hiding and... :-)
 
Besides experimentation in a workspace, what kind of Morphic application would actively wait on a custom semaphore in the UI process? This is bad style. :-)
 
Yet, if Squot needs it, we might want to think about solving it somehow.
 
Best,
Marcel
Am 03.07.2022 13:08:16 schrieb Jaromir Matas <mail at jaromir.net>:
Hi Marcel,
 
thanks for taking a look at the issue :)
 
> What would be the reason for such a strange "semaphore wait" in the UI process
 
Here's my original example:
 
p := [ [Semaphore new wait] ensure: [1/0] ] fork.   "terminatee process -> error during unwind"
Processor yield.
p terminate.   "terminator process = UI Process"
 
I know you can recover it via Alt+. but it doesn't feel right imo to use such brute force for innocent examples :)
 
If you apply Morphic-mt.2016 the UI won't freeze but as you pointed out, it won't proceed. In the following example 'done' won't be printed:
 
s := Semaphore new.
[1/0. s signal] fork.
s wait.
Transcript cr; show: 'done'
 
I understand juggling with two UIs, one blocked or busy and another one keeping the screen responsive isn't trivial; I remember your discussion with Jakob about what seems to me now a similar situation in Squot (SquotGUI>>#waitFor) where Jakob needs to keep the UI responsive while it's waiting on a resource or something; similar situation is dealt with in InstallerSqueakMap>>#update. I tried to apply the strategy here but failed miserably :D
 
My question is: is the above example from Squot the same type of problem? Could it be solved similarly? Would such solution remove the need for an ad-hoc solution like in Squot? Sorry if this doesn't make much sense; I'm far from sure what I'm talking about :)
 
> How can we now that that #isBlocked state will not resolve itself soon? Can we?
 
Could we check if the UI process is waiting on interCycleDelay semaphore to exclude the inter cycle pause case?
 
Thanks again,
Jaromir
 
--
Jaromír Matas
mail at jaromir.net
 
From: Marcel Taeumel [mailto:marcel.taeumel at hpi.de]
Sent: Sunday, July 3, 2022 11:22
To: squeak-dev [mailto:squeak-dev at lists.squeakfoundation.org]
Subject: Re: [squeak-dev] Freezing UI issue
 
Hi all --
 
I did a small spike via Morphic-mt.2016 (Inbox).
 
Not sure whether this issue is actually relevant in Morphic applications. CMD+Dot will help you anyway. What would be the reason for such a strange "semaphore wait" in the UI process other than what the framework does anyway?
 
Best,
Marcel
Am 03.07.2022 01:13:27 schrieb Eliot Miranda <eliot.miranda at gmail.com>:
 
 
On Jul 2, 2022, at 2:13 PM, Jaromir Matas <mail at jaromir.net> wrote:

Hi Eliot, Marcel, all
 
> This sounds right to me.  The important things would be 
- is the activeProcess (in which the exception occurs) the UI process?  If so don’t create a new UI process.
- is the UI process blocked temporarily or long-term?  I’m guessing there are delays in the UI process’s stepping/rendering so some simple test for blocking might assume the UI process was blocked while in fact it was just pausing.
 
Yes, I realize the UI may be in a blocked state most of the time because of the intercycle pause which is not the case we need to isolate; so yes, we need some more clever test than simple #isBlocked.
 
Another thing is that the blocked UI will/may eventually (when signaled) become active again so if we create a new UI to deal with a subsequent error (i.e. a request to open a debugger) then this new UI should really be just “temporary” and should be closed when the original UI becomes active again; and this is at the moment way beyond my skills; I’m not even sure this is the right approach :)
 
> But I really *don’t* know what I’m talking about here.  I would talk it over with Marcel; he’s much more familiar with the code and co-located.
 
That would be a great help indeed :))
 
Can I assume we can agree that it would be nice and reasonable if this motivation example opened the ZeroDivide without freezing the UI ?
 
s := Semaphore new.
[1/0. s signal] fork.
s wait

Yes, at least I can.  It’s a bad thing when errors in background processes don’t show up (although there is a potential issue with a flood of such events).  It’s far worse when such events cause the UI to lock up.  It would be great if the debugger clearly identified an error in a named background process (such as the finalization process) since simply closing the debugger leaves the image in a bad state.
 
 
Thanks!
 
--
Jaromír Matas
mail at jaromir.net
 
From: Eliot Miranda [mailto:eliot.miranda at gmail.com]
Sent: Saturday, July 2, 2022 19:23
To: The general-purpose Squeak developers list [mailto:squeak-dev at lists.squeakfoundation.org]
Subject: Re: [squeak-dev] Freezing UI issue
 
Hi Jaromir,
 
On Jul 1, 2022, at 2:43 AM, Jaromir Matas <mail at jaromir.net> wrote:

Hi All,
 
I'd like to ask you to help me understand this: If you run the following example in the Workspace, the UI will freeze (Alt + . recoverable indeed)
 
s := Semaphore new.
[1/0. s signal] fork.
s wait
 
The reason is obvious - the example runs inside the UI and hence the UI will start waiting on the semaphore s. At the same time the newly forked process will try to evaluate 1/0 and will request the UI to open a debugger but this won't happen because the UI is waiting on a semaphore.
 
Now the question: Why the system won't start the debugger in a new UI? There's no 'fundamental' reason why the UI should get stuck on a semaphore instead of taking care of the new error that occurred elsewhere in the meantime. Look at  #spawnNewProcessIfThisIsUI: : the method tries to make sure there's a running UI so that a new debugger can be opened in case the UI is missing or is suspended. It feels like the situation where the UI *is blocked* has been left off - and I can't figure out whether by omission or intentionally.
 
I've tried to modify it like this:
 
spawnNewProcessIfThisIsUI: suspendedProcess
                "Initialize a UI process if needed. Answer true if suspendedProcess was interrupted
                from a UI process."
                self uiProcess == suspendedProcess ifTrue: [
                                self spawnNewProcess.
                                ^true
                ].
 
                "Ensure that the UI process is running."
                self uiProcess
                                ifNil: [self spawnNewProcess]
                                ifNotNil: [:p | (p isSuspended or: [p isBlocked]) ifTrue: [     "<------- here's my change... or: [p isBlocked]"
                                                self restoreDisplay.
                                                self uiProcess resume]].
 
                ^false                    "no new process was created"
 
... and the example above no longer blocks the UI !
 
I'm not saying this is a fix (I don't have any debugger/UI experience to fix it correctly); I'm just trying to demonstrate the functionality I'd like to achieve :) A real fix should maybe open a new UI instead of unblocking the existing one, I don't know…
 
This sounds right to me.  The important things would be 
- is the activeProcess (in which the exception occurs) the UI process?  If so don’t create a new UI process.
- is the UI process blocked temporarily or long-term?  I’m guessing there are delays in the UI process’s stepping/rendering so some simple test for blocking might assume the UI process was blocked while in fact it was just pausing.
 
But I really *don’t* know what I’m talking about here.  I would talk it over with Marcel; he’s much more familiar with the code and co-located.
 
 
Thanks very much for any input on this.
best,
Jaromir
 
--
Jaromír Matas
mail at jaromir.net
 
 
 
 
 
 
 
 
 
 
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.squeakfoundation.org/pipermail/squeak-dev/attachments/20220707/d2123301/attachment-0001.html>


More information about the Squeak-dev mailing list