mirror of
https://github.com/izzy2lost/xenia-edge.git
synced 2026-07-06 00:20:26 -07:00
[Emulator] Fix crashes with in-process relaunch
Gracefully shutdown dispatch thread and ensure we don't persist alternate xex paths as separate discs
This commit is contained in:
@@ -1461,8 +1461,11 @@ void Emulator::RelaunchTitle(const std::string& host_path,
|
||||
// Tell WaitUntilExit not to fire on_exit when main thread dies.
|
||||
relaunching_ = true;
|
||||
|
||||
// Force-terminate all threads. Cooperative shutdown isn't possible since
|
||||
// workers may be stuck in processor_->Execute().
|
||||
// Stop the dispatch thread gracefully before force-terminating threads,
|
||||
// otherwise TerminateThread corrupts the CV it's blocked on.
|
||||
kernel_state_->ShutdownDispatchThread();
|
||||
|
||||
// Force-terminate remaining threads.
|
||||
{
|
||||
auto threads =
|
||||
kernel_state()->object_table()->GetObjectsByType<kernel::XThread>(
|
||||
@@ -2012,7 +2015,10 @@ X_STATUS Emulator::CompleteLaunch(const std::filesystem::path& path,
|
||||
|
||||
game_info_database_ =
|
||||
std::make_unique<kernel::util::GameInfoDatabase>(db.get());
|
||||
kernel_state_->xam_state()->LoadSpaInfo(db.get(), path);
|
||||
// Don't persist disc path during in-process relaunch; only for
|
||||
// user-initiated file opens.
|
||||
kernel_state_->xam_state()->LoadSpaInfo(
|
||||
db.get(), relaunching_ ? std::filesystem::path{} : path);
|
||||
|
||||
// AddTitleToPlayedList is now called inside LoadSpaInfo/UpdateSpaInfo
|
||||
|
||||
|
||||
@@ -80,15 +80,7 @@ KernelState::KernelState(Emulator* emulator)
|
||||
KernelState::~KernelState() {
|
||||
SetExecutableModule(nullptr);
|
||||
|
||||
if (dispatch_thread_running_) {
|
||||
dispatch_thread_running_ = false;
|
||||
if (dispatch_thread_ && dispatch_thread_->is_running()) {
|
||||
dispatch_cond_.notify_all();
|
||||
dispatch_thread_->Wait(0, 0, 0, nullptr);
|
||||
}
|
||||
// Skip notify/Wait if already force-terminated — mutex may be abandoned.
|
||||
dispatch_thread_.reset();
|
||||
}
|
||||
ShutdownDispatchThread();
|
||||
|
||||
executable_module_.reset();
|
||||
user_modules_.clear();
|
||||
@@ -103,6 +95,14 @@ KernelState::~KernelState() {
|
||||
shared_kernel_state_ = nullptr;
|
||||
}
|
||||
|
||||
void KernelState::ShutdownDispatchThread() {
|
||||
if (dispatch_thread_running_) {
|
||||
dispatch_thread_running_ = false;
|
||||
dispatch_cond_.notify_all();
|
||||
dispatch_thread_->Wait(0, 0, 0, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
KernelState* KernelState::shared() { return shared_kernel_state_; }
|
||||
|
||||
uint32_t KernelState::title_id() const {
|
||||
|
||||
@@ -262,6 +262,10 @@ class KernelState {
|
||||
// This DOES NOT RETURN if called from a guest thread!
|
||||
void TerminateTitle();
|
||||
|
||||
// Gracefully stops the dispatch thread. Call before force-terminating
|
||||
// threads to avoid corrupting the CV it's blocked on.
|
||||
void ShutdownDispatchThread();
|
||||
|
||||
void RegisterThread(XThread* thread);
|
||||
void UnregisterThread(XThread* thread);
|
||||
void OnThreadExecute(XThread* thread);
|
||||
|
||||
Reference in New Issue
Block a user