From 8adec3f20be9af853e6554280e69ab69eed7fe90 Mon Sep 17 00:00:00 2001 From: Flyinghead Date: Tue, 11 Jun 2024 16:38:30 +0200 Subject: [PATCH] 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 --- core/achievements/achievements.cpp | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/core/achievements/achievements.cpp b/core/achievements/achievements.cpp index 094bc2e4a..41b1c0eae 100644 --- a/core/achievements/achievements.cpp +++ b/core/achievements/achievements.cpp @@ -75,6 +75,8 @@ private: std::pair getCachedImage(const char *url); void diskChange(); void asyncTask(std::function f); + void startThread(); + void stopThread(); void backgroundThread(); static void clientLoginWithTokenCallback(int result, const char *error_message, rc_client_t *client, void *userdata); @@ -195,6 +197,20 @@ void Achievements::asyncTask(std::function f) 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() { ThreadName _("RA-background"); @@ -227,8 +243,7 @@ bool Achievements::init() //rc_client_set_unofficial_enabled(rc_client, 0); //rc_client_set_spectator_mode_enabled(rc_client, 0); loadCache(); - threadRunning = true; - taskThread = std::thread(&Achievements::backgroundThread, this); + startThread(); if (!config::AchievementsUserName.get().empty() && !config::AchievementsToken.get().empty()) { @@ -342,10 +357,7 @@ void Achievements::term() if (rc_client == nullptr) return; unloadGame(); - threadRunning = false; - resetEvent.Set(); - if (taskThread.joinable()) - taskThread.join(); + stopThread(); rc_client_destroy(rc_client); rc_client = nullptr; } @@ -932,6 +944,9 @@ void Achievements::unloadGame() active = false; paused = false; EventManager::unlisten(Event::VBlank, emuEventCallback, this); + // wait for all async tasks before unloading the game + stopThread(); + startThread(); rc_client_unload_game(rc_client); settings.raHardcoreMode = false; }