-
Notifications
You must be signed in to change notification settings - Fork 8.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Avoid async infinite loop on tab close #15335
Conversation
if (tab == _settingsTab) | ||
{ | ||
_settingsTab = nullptr; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I felt like this is a more robust way to express the same idea of "there's just one instance of settings and closing it destroys it".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about when a tab closes itself, like when the terminal connection inside it exits? That does not come in on the main dispatcher thread, therefore interacting with UI elements during the Close callback is a danger.
Are we certain that Close always comes in on the right thread?
@@ -1843,135 +1842,128 @@ void Pane::_CloseChild(const bool closeFirst, const bool isDetaching) | |||
closedChild->_ClosedByParentHandlers(); | |||
} | |||
|
|||
winrt::fire_and_forget Pane::_CloseChildRoutine(const bool closeFirst) | |||
void Pane::_CloseChildRoutine(const bool closeFirst) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You need to view this changeset with whitespace changes suppressed. :)
You're right, it didn't. In my original PR it worked, because I also made it so that the close event gets emitted on the UI thread. I now brought those changes into this PR as well, but unfortunately it increases the diff size. It's easier to view with whitespace changes suppressed. |
@@ -683,8 +683,6 @@ bool Pane::SwapPanes(std::shared_ptr<Pane> first, std::shared_ptr<Pane> second) | |||
return false; | |||
} | |||
|
|||
std::unique_lock lock{ _createCloseLock }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you know what this was guarding and how we are now safe without it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I understand why this works. Thanks!
1.18 material?
Oh, you removed it from 1.18. OK |
Yeah I think I'd like to wait with this until 1.19... There's still these comments in the code and I'd like to 110% grasp what they mean in practice and if it was a practical concern to begin with:
...because to be honest I don't think any of this worked the way we imagined it would. I'm pretty sure all of that |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This all seems good. The only thing I want to double check with you on is why we're removing the lock from...
SwapPanes()
_CloseTerminalRequestedHandler()
Shutdown()
_CloseChild()
_CloseChildRoutine()
I get that's the point of this PR haha, but why is it safe to do that now?
@carlos-zamora Sorry for the late response. As far as I can tell, The reason I removed it is simply because that mutex provides a false sense of security. We can't use it to make shutdown secure, when Pane has ~50 member functions and only 6 of them are thread safe. 😅 It just doesn't work at all and never did. 😅😅 |
This has ✅✅, but never merged while I was out. I haven't read it yet. Should we include this in the bug bash? |
Yes, please. I've merged in main just now to resolve the conflict. |
When a tab gets closed,
_RemoveTab
will callTabBase::Shutdown()
,which then re-raises the
Closed
event, which will end up calling_RemoveTab
again, etc. The only reason this didn't crash WT so faris because
_RemoveOnCloseRoutine
contains aresume_foreground
,which would resolve the recursion and turn it into CPU usage.
It would spin as long as WinUI hasn't discard the tab object,
which takes an unpredictable amount of time.
Raising the
Closed
event fromShutdown()
is unnecessary, becausethe handlers of the event end up calling
_RemoveTab
anyways.Technically the entire
Closed
event can be removed now, but I left itin anyways because resolving the architectural "knot" around the way
tab closing after the last pane closes is implemented requires much
more significant changes.
This commit additionally removes the
_createCloseLock
mutex inPane
as it was very likely not working as intended anyways. Only some methods
were protected by it and it doesn't avoid any STA/MTA/NA issues either.
Validation Steps Performed
Shutdown()
✅Closes #14898