achievements: crash when unloading a game with active async task

Async tasks may reference the active game and will crash if it's been
unloaded/freed.
Fixes MINIDUMP-38H
This commit is contained in:
Flyinghead 2024-06-11 16:38:30 +02:00
parent 4cd6278104
commit 8adec3f20b
1 changed files with 21 additions and 6 deletions

View File

@ -75,6 +75,8 @@ private:
std::pair<std::string, bool> getCachedImage(const char *url); std::pair<std::string, bool> getCachedImage(const char *url);
void diskChange(); void diskChange();
void asyncTask(std::function<void()> f); void asyncTask(std::function<void()> f);
void startThread();
void stopThread();
void backgroundThread(); void backgroundThread();
static void clientLoginWithTokenCallback(int result, const char *error_message, rc_client_t *client, void *userdata); static void clientLoginWithTokenCallback(int result, const char *error_message, rc_client_t *client, void *userdata);
@ -195,6 +197,20 @@ void Achievements::asyncTask(std::function<void()> f)
resetEvent.Set(); resetEvent.Set();
} }
void Achievements::startThread()
{
threadRunning = true;
taskThread = std::thread(&Achievements::backgroundThread, this);
}
void Achievements::stopThread()
{
threadRunning = false;
resetEvent.Set();
if (taskThread.joinable())
taskThread.join();
}
void Achievements::backgroundThread() void Achievements::backgroundThread()
{ {
ThreadName _("RA-background"); ThreadName _("RA-background");
@ -227,8 +243,7 @@ bool Achievements::init()
//rc_client_set_unofficial_enabled(rc_client, 0); //rc_client_set_unofficial_enabled(rc_client, 0);
//rc_client_set_spectator_mode_enabled(rc_client, 0); //rc_client_set_spectator_mode_enabled(rc_client, 0);
loadCache(); loadCache();
threadRunning = true; startThread();
taskThread = std::thread(&Achievements::backgroundThread, this);
if (!config::AchievementsUserName.get().empty() && !config::AchievementsToken.get().empty()) if (!config::AchievementsUserName.get().empty() && !config::AchievementsToken.get().empty())
{ {
@ -342,10 +357,7 @@ void Achievements::term()
if (rc_client == nullptr) if (rc_client == nullptr)
return; return;
unloadGame(); unloadGame();
threadRunning = false; stopThread();
resetEvent.Set();
if (taskThread.joinable())
taskThread.join();
rc_client_destroy(rc_client); rc_client_destroy(rc_client);
rc_client = nullptr; rc_client = nullptr;
} }
@ -932,6 +944,9 @@ void Achievements::unloadGame()
active = false; active = false;
paused = false; paused = false;
EventManager::unlisten(Event::VBlank, emuEventCallback, this); EventManager::unlisten(Event::VBlank, emuEventCallback, this);
// wait for all async tasks before unloading the game
stopThread();
startThread();
rc_client_unload_game(rc_client); rc_client_unload_game(rc_client);
settings.raHardcoreMode = false; settings.raHardcoreMode = false;
} }