Skip to content
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

GraphicPacksWindow2: Disable update button when a game is running #1137

Merged
merged 4 commits into from Mar 26, 2024

Conversation

goeiecool9999
Copy link
Contributor

@goeiecool9999 goeiecool9999 commented Mar 24, 2024

Constructing DownloadGraphicPacksWindow launches a thread to run the graphic packs update tasks on. When a game is running the thread instead calls wxMessageBox to display an error and immediately returns. On windows this likely uses the system's MessageBox functions, which I believe spawn a window controlled by some system-level process meaning the application only has to read the result. However linux doesn't have native messagebox functionality like that and in order for an application to display any kind of window it has to manage it's event loop. For whatever reason wxMessageBox in the update thread gets stuck and the messagebox cannot be closed. The debugger shows that both the main UI thread and the graphic pack update thread are running a GTK event loop, either waiting for a condition variable or stuck in a poll syscall. This looks like a deadlock, but it's not as when I press the close button on the DownloadGraphicPacksWindow it does actually call OnClose(), which then also locks up the main thread because it tries to join the spawned update thread that is stuck in wxMessageBox.
I don't know if this is a bug in wxWidgets or if calling wxwidgets functions from multiple threads just isn't supported.
I worked around this issue by changing DownloadGraphicPacksWindow so it doesn't launch the thread upon construction but in ShowModal instead and shows the message box on the main UI thread if a title is running.
But then I realised it's kind of bad design to have the button be clickable if it'll immediately tell you it can't perform the action, so I also decided to update the button from FileLoad so it's greyed out when a game starts and made clickable when a game stops. For this I made the new function MainWindow::UpdateChildWindowTitleRunningState in case other windows need similar updates. This effectively means that the message box in DownloadGraphicPacksWindow serves only as a run-time check.

@Exzap
Copy link
Contributor

Exzap commented Mar 25, 2024

I think the only rule is that wxWidgets functions have to be called from the wx thread (unless otherwise specified). Did you try moving wxMessageBox out of the update thread and instead into the constructor of DownloadGraphicPacksWindow or into the function where it gets constructed from (OnCheckForUpdates)?

src/gui/MainWindow.cpp Outdated Show resolved Hide resolved
@goeiecool9999
Copy link
Contributor Author

goeiecool9999 commented Mar 25, 2024

I think the only rule is that wxWidgets functions have to be called from the wx thread (unless otherwise specified). Did you try moving wxMessageBox out of the update thread and instead into the constructor of DownloadGraphicPacksWindow or into the function where it gets constructed from (OnCheckForUpdates)?

I think it might be a race condition, the thread is launched in the constructor, but the wxMessageBox calls pass the window that's being constructed as their parent. The other wxMessageBox's being called from the thread work just fine now (at least the "no updates" box). Maybe there's still a thread-safety issue but I've not observed freezes or crashes since I changed it to start the thread right before the parent window's ShowModal call.

Not all wxMessageBox calls can be easily moved out of the thread, because not all message boxes indicate success or error status. Some of them indicate intermediate status or ask the user to make a decision.

@goeiecool9999
Copy link
Contributor Author

goeiecool9999 commented Mar 25, 2024

Did you try moving wxMessageBox out of the update thread and instead into the constructor of DownloadGraphicPacksWindow or into the function where it gets constructed from (OnCheckForUpdates)

If I moved it into the constructor the check would display a message but I'd have no way of preventing the window from opening. At most I could make it open and immediately close because the thread isn't running.
If I moved it to the function in charge of creating the dialog then that places a burden on every function that wants to create DownloadGraphicPacksWindow to check if a title is running or not. That's why I chose to move it to ShowModal instead.
But since I disable the button it should never appear in the first place. Unless some future function creates it without checking. I guess the burden isn't completely gone, it's now just safer to do it anyway 😅

@Exzap Exzap merged commit 4f3d462 into cemu-project:main Mar 26, 2024
5 checks passed
@goeiecool9999 goeiecool9999 deleted the gpupdatefreezefix branch March 27, 2024 15:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants