Implement Emulator::GracefulShutdown()

This commit is contained in:
Eladash 2022-02-05 12:49:29 +02:00 committed by GitHub
parent 6c5b8dc31c
commit e951c619c5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 180 additions and 89 deletions

View file

@ -179,7 +179,7 @@ public:
// Callback for thread_ctrl::wait or RSX wait // Callback for thread_ctrl::wait or RSX wait
virtual void cpu_wait(bs_t<cpu_flag> old); virtual void cpu_wait(bs_t<cpu_flag> old);
// Callback for function abortion stats on Emu.Stop() // Callback for function abortion stats on Emu.Kill()
virtual void cpu_on_stop() {} virtual void cpu_on_stop() {}
// For internal use // For internal use

View file

@ -56,8 +56,10 @@ extern void sysutil_register_cb(std::function<s32(ppu_thread&)>&& cb)
cbm.registered.push(std::move(cb)); cbm.registered.push(std::move(cb));
} }
extern void sysutil_send_system_cmd(u64 status, u64 param) extern u32 sysutil_send_system_cmd(u64 status, u64 param)
{ {
u32 count = 0;
if (auto cbm = g_fxo->try_get<sysutil_cb_manager>()) if (auto cbm = g_fxo->try_get<sysutil_cb_manager>())
{ {
for (sysutil_cb_manager::registered_cb cb : cbm->callbacks) for (sysutil_cb_manager::registered_cb cb : cbm->callbacks)
@ -70,9 +72,13 @@ extern void sysutil_send_system_cmd(u64 status, u64 param)
cb.first(ppu, status, param, cb.second); cb.first(ppu, status, param, cb.second);
return CELL_OK; return CELL_OK;
}); });
count++;
} }
} }
} }
return count;
} }
template <> template <>

View file

@ -301,5 +301,5 @@ struct CellSysCacheParam
}; };
extern void sysutil_register_cb(std::function<s32(ppu_thread&)>&&); extern void sysutil_register_cb(std::function<s32(ppu_thread&)>&&);
extern void sysutil_send_system_cmd(u64 status, u64 param); extern u32 sysutil_send_system_cmd(u64 status, u64 param);
s32 sysutil_check_name_string(const char* src, s32 minlen, s32 maxlen); s32 sysutil_check_name_string(const char* src, s32 minlen, s32 maxlen);

View file

@ -3405,7 +3405,7 @@ static void ppu_initialize2(jit_compiler& jit, const ppu_module& module_part, co
{ {
out.flush(); out.flush();
ppu_log.error("LLVM: Verification failed for %s:\n%s", obj_name, result); ppu_log.error("LLVM: Verification failed for %s:\n%s", obj_name, result);
Emu.CallAfter([]{ Emu.Stop(); }); Emu.CallAfter([]{ Emu.GracefulShutdown(false, true); });
return; return;
} }

View file

@ -349,7 +349,7 @@ void _sys_process_exit(ppu_thread& ppu, s32 status, u32 arg2, u32 arg3)
Emu.CallAfter([]() Emu.CallAfter([]()
{ {
sys_process.success("Process finished"); sys_process.success("Process finished");
Emu.Stop(); Emu.Kill();
}); });
// Wait for GUI thread // Wait for GUI thread
@ -415,8 +415,7 @@ void _sys_process_exit2(ppu_thread& ppu, s32 status, vm::ptr<sys_exit2_param> ar
, hdd1 = std::move(hdd1), klic = g_fxo->get<loaded_npdrm_keys>().last_key(), old_config = Emu.GetUsedConfig()]() mutable , hdd1 = std::move(hdd1), klic = g_fxo->get<loaded_npdrm_keys>().last_key(), old_config = Emu.GetUsedConfig()]() mutable
{ {
sys_process.success("Process finished -> %s", argv[0]); sys_process.success("Process finished -> %s", argv[0]);
Emu.SetForceBoot(true); Emu.Kill(false);
Emu.Stop();
Emu.argv = std::move(argv); Emu.argv = std::move(argv);
Emu.envp = std::move(envp); Emu.envp = std::move(envp);
Emu.data = std::move(data); Emu.data = std::move(data);
@ -435,7 +434,7 @@ void _sys_process_exit2(ppu_thread& ppu, s32 status, vm::ptr<sys_exit2_param> ar
if (res != game_boot_result::no_errors) if (res != game_boot_result::no_errors)
{ {
sys_process.fatal("Failed to boot from exitspawn! (path=\"%s\", error=%s)", path, res); sys_process.fatal("Failed to boot from exitspawn! (path=\"%s\", error=%s)", path, res);
Emu.Stop(); Emu.Kill();
} }
}); });

View file

@ -719,7 +719,7 @@ bool gdb_thread::cmd_attached_to_what(gdb_cmd&)
bool gdb_thread::cmd_kill(gdb_cmd&) bool gdb_thread::cmd_kill(gdb_cmd&)
{ {
GDB.notice("Kill command issued"); GDB.notice("Kill command issued");
Emu.Stop(); Emu.CallAfter([](){ Emu.GracefulShutdown(); });
return true; return true;
} }

View file

@ -21,7 +21,7 @@ namespace rsx
Emu.CallAfter([]() Emu.CallAfter([]()
{ {
rsx_log.notice("Aborted shader loading dialog"); rsx_log.notice("Aborted shader loading dialog");
Emu.Stop(); Emu.Kill(false);
}); });
}; };

View file

@ -24,7 +24,7 @@ namespace rsx
if (status != CELL_OK) if (status != CELL_OK)
{ {
rsx_log.notice("Aborted shader loading dialog"); rsx_log.notice("Aborted shader loading dialog");
Emu.Stop(); Emu.Kill(false);
} }
}); });
} }

View file

@ -558,7 +558,7 @@ game_boot_result Emulator::Load(const std::string& title_id, bool add_only, bool
if (!IsStopped()) if (!IsStopped())
{ {
Stop(); Kill();
} }
if (!title_id.empty()) if (!title_id.empty())
@ -886,8 +886,7 @@ game_boot_result Emulator::Load(const std::string& title_id, bool add_only, bool
// Exit "process" // Exit "process"
CallAfter([] CallAfter([]
{ {
Emu.SetForceBoot(true); Emu.Kill(false);
Emu.Stop();
}); });
m_path = m_path_old; // Reset m_path to fix boot from gui m_path = m_path_old; // Reset m_path to fix boot from gui
@ -1408,8 +1407,7 @@ game_boot_result Emulator::Load(const std::string& title_id, bool add_only, bool
if (ppu_exec != elf_error::ok) if (ppu_exec != elf_error::ok)
{ {
SetForceBoot(true); Kill(false);
Stop();
sys_log.error("Invalid or unsupported PPU executable format: %s", elf_path); sys_log.error("Invalid or unsupported PPU executable format: %s", elf_path);
@ -1440,8 +1438,7 @@ game_boot_result Emulator::Load(const std::string& title_id, bool add_only, bool
sys_log.warning("** ppu_prx -> %s", ppu_prx.get_error()); sys_log.warning("** ppu_prx -> %s", ppu_prx.get_error());
sys_log.warning("** spu_exec -> %s", spu_exec.get_error()); sys_log.warning("** spu_exec -> %s", spu_exec.get_error());
SetForceBoot(true); Kill(false);
Stop();
return game_boot_result::invalid_file_or_folder; return game_boot_result::invalid_file_or_folder;
} }
@ -1458,8 +1455,7 @@ game_boot_result Emulator::Load(const std::string& title_id, bool add_only, bool
return libs.count(std::string(lib.first) + ":lle") || (!lib.second && !libs.count(std::string(lib.first) + ":hle")); return libs.count(std::string(lib.first) + ":lle") || (!lib.second && !libs.count(std::string(lib.first) + ":hle"));
})) }))
{ {
SetForceBoot(true); Kill(false);
Stop();
CallAfter([this]() CallAfter([this]()
{ {
@ -1581,17 +1577,13 @@ bool Emulator::Pause(bool freeze_emulation)
void Emulator::Resume() void Emulator::Resume()
{ {
// Get pause start time if (m_state != system_state::paused)
const u64 time = m_pause_start_time.exchange(0);
// Try to increment summary pause time
if (time)
{ {
m_pause_amend_time += get_system_time() - time; return;
} }
// Print and reset debug data collected // Print and reset debug data collected
if (m_state == system_state::paused && g_cfg.core.ppu_debug) if (g_cfg.core.ppu_debug)
{ {
PPUDisAsm dis_asm(cpu_disasm_mode::dump, vm::g_sudo_addr); PPUDisAsm dis_asm(cpu_disasm_mode::dump, vm::g_sudo_addr);
@ -1619,19 +1611,27 @@ void Emulator::Resume()
ppu_log.notice("[RESUME] Dumping instruction stats:%s", dump); ppu_log.notice("[RESUME] Dumping instruction stats:%s", dump);
} }
perf_stat_base::report();
// Try to resume // Try to resume
if (!m_state.compare_and_swap_test(system_state::paused, system_state::running)) if (!m_state.compare_and_swap_test(system_state::paused, system_state::running))
{ {
return; return;
} }
if (!time) // Get pause start time
const u64 time = m_pause_start_time.exchange(0);
// Try to increment summary pause time
if (time)
{
m_pause_amend_time += get_system_time() - time;
}
else
{ {
sys_log.error("Emulator::Resume() error: concurrent access"); sys_log.error("Emulator::Resume() error: concurrent access");
} }
perf_stat_base::report();
auto on_select = [](u32, cpu_thread& cpu) auto on_select = [](u32, cpu_thread& cpu)
{ {
cpu.state -= cpu_flag::dbg_global_pause; cpu.state -= cpu_flag::dbg_global_pause;
@ -1657,25 +1657,70 @@ void Emulator::Resume()
} }
} }
void Emulator::Stop(bool restart) u32 sysutil_send_system_cmd(u64 status, u64 param);
void process_qt_events();
void Emulator::GracefulShutdown(bool allow_autoexit, bool async_op)
{
const auto old_state = m_state.load();
if (old_state == system_state::stopped)
{
return;
}
if (old_state == system_state::paused)
{
Resume();
}
if (old_state == system_state::frozen || !sysutil_send_system_cmd(0x0101 /* CELL_SYSUTIL_REQUEST_EXITGAME */, 0))
{
// The callback has been rudely ignored, we have no other option but to force termination
Kill(allow_autoexit);
return;
}
auto perform_kill = [allow_autoexit, this, info = ProcureCurrentEmulationCourseInformation()]()
{
for (u32 i = 0; i < 50; i++)
{
std::this_thread::sleep_for(50ms);
Resume(); // TODO: Prevent pausing by other threads while in this loop
process_qt_events(); // Is nullified when performed on non-main thread
if (static_cast<u64>(info) != m_stop_ctr)
{
return;
}
}
// An inevitable attempt to terminate the *current* emulation course will be issued after 5s
CallAfter([allow_autoexit, this]()
{
Kill(allow_autoexit);
}, info);
};
if (async_op)
{
std::thread{perform_kill}.detach();
}
else
{
perform_kill();
}
}
void Emulator::Kill(bool allow_autoexit)
{ {
if (m_state.exchange(system_state::stopped) == system_state::stopped) if (m_state.exchange(system_state::stopped) == system_state::stopped)
{ {
if (restart)
{
// Reload with prior configs.
if (const auto error = Load(m_title_id); error != game_boot_result::no_errors)
sys_log.error("Restart failed: %s", error);
return;
}
m_force_boot = false;
return; return;
} }
sys_log.notice("Stopping emulator..."); sys_log.notice("Stopping emulator...");
if (!restart)
{ {
// Show visual feedback to the user in case that stopping takes a while. // Show visual feedback to the user in case that stopping takes a while.
// This needs to be done before actually stopping, because otherwise the necessary threads will be terminated before we can show an image. // This needs to be done before actually stopping, because otherwise the necessary threads will be terminated before we can show an image.
@ -1783,15 +1828,7 @@ void Emulator::Stop(bool restart)
m_stop_ctr++; m_stop_ctr++;
m_stop_ctr.notify_all(); m_stop_ctr.notify_all();
if (restart) // Boot arg cleanup
{
// Reload with prior configs.
if (const auto error = Load(m_title_id); error != game_boot_result::no_errors)
sys_log.error("Restart failed: %s", error);
return;
}
// Boot arg cleanup (preserved in the case restarting)
argv.clear(); argv.clear();
envp.clear(); envp.clear();
data.clear(); data.clear();
@ -1804,15 +1841,36 @@ void Emulator::Stop(bool restart)
// Always Enable display sleep, not only if it was prevented. // Always Enable display sleep, not only if it was prevented.
enable_display_sleep(); enable_display_sleep();
if (!m_force_boot) if (allow_autoexit)
{ {
if (Quit(g_cfg.misc.autoexit.get())) if (Quit(g_cfg.misc.autoexit.get()))
{ {
return; return;
} }
} }
}
m_force_boot = false; game_boot_result Emulator::Restart()
{
if (m_state == system_state::stopped)
{
return game_boot_result::generic_error;
}
auto save_args = std::make_tuple(argv, envp, data, disc, klic, hdd1, m_config_mode, m_config_mode);
GracefulShutdown(false, false);
std::tie(argv, envp, data, disc, klic, hdd1, m_config_mode, m_config_mode) = std::move(save_args);
// Reload with prior configs.
if (const auto error = Load(m_title_id); error != game_boot_result::no_errors)
{
sys_log.error("Restart failed: %s", error);
return error;
}
return game_boot_result::no_errors;
} }
bool Emulator::Quit(bool force_quit) bool Emulator::Quit(bool force_quit)

View file

@ -111,9 +111,9 @@ class Emulator final
std::string m_usr{"00000001"}; std::string m_usr{"00000001"};
u32 m_usrid{1}; u32 m_usrid{1};
// This flag should be adjusted before each Stop() or each BootGame() and similar because: // This flag should be adjusted before each Kill() or each BootGame() and similar because:
// 1. It forces an application to boot immediately by calling Run() in Load(). // 1. It forces an application to boot immediately by calling Run() in Load().
// 2. It signifies that we don't want to exit on Stop(), for example if we want to transition to another application. // 2. It signifies that we don't want to exit on Kill(), for example if we want to transition to another application.
bool m_force_boot = false; bool m_force_boot = false;
bool m_has_gui = true; bool m_has_gui = true;
@ -132,14 +132,14 @@ public:
} }
// Call from the GUI thread // Call from the GUI thread
void CallAfter(std::function<void()>&& func, bool track_emu_state = true) const void CallAfter(std::function<void()>&& func, bool track_emu_state = true, u64 stop_ctr = umax) const
{ {
if (!track_emu_state) if (!track_emu_state)
{ {
return m_cb.call_after(std::move(func)); return m_cb.call_after(std::move(func));
} }
std::function<void()> final_func = [this, before = IsStopped(), count = +m_stop_ctr, func = std::move(func)] std::function<void()> final_func = [this, before = IsStopped(), count = (stop_ctr == umax ? +m_stop_ctr : stop_ctr), func = std::move(func)]
{ {
if (count == m_stop_ctr && before == IsStopped()) if (count == m_stop_ctr && before == IsStopped())
{ {
@ -150,6 +150,18 @@ public:
return m_cb.call_after(std::move(final_func)); return m_cb.call_after(std::move(final_func));
} }
enum class stop_counter_t : u64{};
stop_counter_t ProcureCurrentEmulationCourseInformation() const
{
return stop_counter_t{+m_stop_ctr};
}
void CallAfter(std::function<void()>&& func, stop_counter_t counter) const
{
CallAfter(std::move(func), true, static_cast<u64>(counter));
}
/** Set emulator mode to running unconditionnaly. /** Set emulator mode to running unconditionnaly.
* Required to execute various part (PPUInterpreter, memory manager...) outside of rpcs3. * Required to execute various part (PPUInterpreter, memory manager...) outside of rpcs3.
*/ */
@ -244,8 +256,9 @@ public:
void Run(bool start_playtime); void Run(bool start_playtime);
bool Pause(bool freeze_emulation = false); bool Pause(bool freeze_emulation = false);
void Resume(); void Resume();
void Stop(bool restart = false); void GracefulShutdown(bool allow_autoexit = true, bool async_op = false);
void Restart() { Stop(true); } void Kill(bool allow_autoexit = true);
game_boot_result Restart();
bool Quit(bool force_quit); bool Quit(bool force_quit);
static void CleanUp(); static void CleanUp();

View file

@ -92,7 +92,7 @@ void progress_dialog_server::operator()()
{ {
// Abort everything // Abort everything
sys_log.notice("Aborted progress dialog"); sys_log.notice("Aborted progress dialog");
Emu.Stop(); Emu.GracefulShutdown(false, true);
}); });
g_system_progress_canceled = true; g_system_progress_canceled = true;

View file

@ -62,8 +62,7 @@ auto_pause_settings_dialog::auto_pause_settings_dialog(QWidget *parent) : QDialo
}); });
connect(cancelButton, &QAbstractButton::clicked, this, &QWidget::close); connect(cancelButton, &QAbstractButton::clicked, this, &QWidget::close);
Emu.SetForceBoot(true); Emu.GracefulShutdown(false);
Emu.Stop();
LoadEntries(); LoadEntries();
UpdateList(); UpdateList();

View file

@ -1402,8 +1402,7 @@ void game_list_frame::ShowContextMenu(const QPoint &pos)
bool game_list_frame::CreatePPUCache(const std::string& path, const std::string& serial) bool game_list_frame::CreatePPUCache(const std::string& path, const std::string& serial)
{ {
Emu.SetForceBoot(true); Emu.GracefulShutdown(false);
Emu.Stop();
Emu.SetForceBoot(true); Emu.SetForceBoot(true);
if (const auto error = Emu.BootGame(path, serial, true); error != game_boot_result::no_errors) if (const auto error = Emu.BootGame(path, serial, true); error != game_boot_result::no_errors)
@ -1701,7 +1700,7 @@ void game_list_frame::BatchCreatePPUCaches()
if (!Emu.IsStopped()) if (!Emu.IsStopped())
{ {
QApplication::processEvents(); QApplication::processEvents();
Emu.Stop(); Emu.GracefulShutdown(false);
} }
if (!pdlg->wasCanceled()) if (!pdlg->wasCanceled())

View file

@ -363,7 +363,7 @@ void gs_frame::close()
if (!Emu.IsStopped()) if (!Emu.IsStopped())
{ {
Emu.Stop(); Emu.GracefulShutdown(true, false);
} }
deleteLater(); deleteLater();

View file

@ -69,6 +69,14 @@ std::shared_ptr<CPUDisAsm> make_basic_ppu_disasm();
inline std::string sstr(const QString& _in) { return _in.toStdString(); } inline std::string sstr(const QString& _in) { return _in.toStdString(); }
extern void process_qt_events()
{
if (thread_ctrl::is_main())
{
QApplication::processEvents();
}
}
main_window::main_window(std::shared_ptr<gui_settings> gui_settings, std::shared_ptr<emu_settings> emu_settings, std::shared_ptr<persistent_settings> persistent_settings, QWidget *parent) main_window::main_window(std::shared_ptr<gui_settings> gui_settings, std::shared_ptr<emu_settings> emu_settings, std::shared_ptr<persistent_settings> persistent_settings, QWidget *parent)
: QMainWindow(parent) : QMainWindow(parent)
, ui(new Ui::main_window) , ui(new Ui::main_window)
@ -189,7 +197,7 @@ bool main_window::Init(bool with_cli_boot)
connect(m_thumb_stop, &QWinThumbnailToolButton::clicked, this, []() connect(m_thumb_stop, &QWinThumbnailToolButton::clicked, this, []()
{ {
gui_log.notice("User clicked stop button on thumbnail toolbar"); gui_log.notice("User clicked stop button on thumbnail toolbar");
Emu.Stop(); Emu.GracefulShutdown(false, true);
}); });
connect(m_thumb_restart, &QWinThumbnailToolButton::clicked, this, []() connect(m_thumb_restart, &QWinThumbnailToolButton::clicked, this, []()
{ {
@ -399,10 +407,9 @@ void main_window::Boot(const std::string& path, const std::string& title_id, boo
return; return;
} }
m_app_icon = gui::utils::get_app_icon_from_path(path, title_id); Emu.GracefulShutdown(false);
Emu.SetForceBoot(true); m_app_icon = gui::utils::get_app_icon_from_path(path, title_id);
Emu.Stop();
if (const auto error = Emu.BootGame(path, title_id, direct, add_only, config_mode, config_path); error != game_boot_result::no_errors) if (const auto error = Emu.BootGame(path, title_id, direct, add_only, config_mode, config_path); error != game_boot_result::no_errors)
{ {
@ -524,8 +531,7 @@ void main_window::BootRsxCapture(std::string path)
return; return;
} }
Emu.SetForceBoot(true); Emu.GracefulShutdown(false);
Emu.Stop();
if (!Emu.BootRsxCapture(path)) if (!Emu.BootRsxCapture(path))
{ {
@ -651,6 +657,17 @@ void main_window::InstallPackages(QStringList file_paths)
} }
} }
if (!m_gui_settings->GetBootConfirmation(this))
{
// Last chance to cancel the operation
return;
}
if (!Emu.IsStopped())
{
Emu.GracefulShutdown(false);
}
// Install rap files if available // Install rap files if available
int installed_rap_and_edat_count = 0; int installed_rap_and_edat_count = 0;
@ -732,6 +749,8 @@ void main_window::HandlePackageInstallation(QStringList file_paths)
return; return;
} }
Emu.GracefulShutdown(false);
progress_dialog pdlg(tr("RPCS3 Package Installer"), tr("Installing package, please wait..."), tr("Cancel"), 0, 1000, false, this); progress_dialog pdlg(tr("RPCS3 Package Installer"), tr("Installing package, please wait..."), tr("Cancel"), 0, 1000, false, this);
pdlg.setAutoClose(false); pdlg.setAutoClose(false);
pdlg.show(); pdlg.show();
@ -774,9 +793,6 @@ void main_window::HandlePackageInstallation(QStringList file_paths)
pdlg.setLabelText(tr("Installing package (%0/%1), please wait...\n\n%2").arg(i + 1).arg(count).arg(app_info)); pdlg.setLabelText(tr("Installing package (%0/%1), please wait...\n\n%2").arg(i + 1).arg(count).arg(app_info));
pdlg.show(); pdlg.show();
Emu.SetForceBoot(true);
Emu.Stop();
const QFileInfo file_info(package.path); const QFileInfo file_info(package.path);
const std::string path = sstr(package.path); const std::string path = sstr(package.path);
const std::string file_name = sstr(file_info.fileName()); const std::string file_name = sstr(file_info.fileName());
@ -934,8 +950,7 @@ void main_window::ExtractTar()
return; return;
} }
Emu.SetForceBoot(true); Emu.GracefulShutdown(false);
Emu.Stop();
const QString path_last_tar = m_gui_settings->GetValue(gui::fd_ext_tar).toString(); const QString path_last_tar = m_gui_settings->GetValue(gui::fd_ext_tar).toString();
QStringList files = QFileDialog::getOpenFileNames(this, tr("Select TAR To extract"), path_last_tar, tr("All tar files (*.tar *.TAR *.tar.aa.* *.TAR.AA.*);;All files (*.*)")); QStringList files = QFileDialog::getOpenFileNames(this, tr("Select TAR To extract"), path_last_tar, tr("All tar files (*.tar *.TAR *.tar.aa.* *.TAR.AA.*);;All files (*.*)"));
@ -1011,8 +1026,7 @@ void main_window::HandlePupInstallation(const QString& file_path, const QString&
return; return;
} }
Emu.SetForceBoot(true); Emu.GracefulShutdown(false);
Emu.Stop();
m_gui_settings->SetValue(gui::fd_install_pup, QFileInfo(file_path).path()); m_gui_settings->SetValue(gui::fd_install_pup, QFileInfo(file_path).path());
@ -1257,7 +1271,7 @@ void main_window::HandlePupInstallation(const QString& file_path, const QString&
} }
// This is ugly, but PS3 headers shall not be included there. // This is ugly, but PS3 headers shall not be included there.
extern void sysutil_send_system_cmd(u64 status, u64 param); extern u32 sysutil_send_system_cmd(u64 status, u64 param);
void main_window::DecryptSPRXLibraries() void main_window::DecryptSPRXLibraries()
{ {
@ -2026,6 +2040,8 @@ void main_window::CreateConnects()
if (!paths.isEmpty()) if (!paths.isEmpty())
{ {
Emu.GracefulShutdown(false);
for (const QString& path : paths) for (const QString& path : paths)
{ {
AddGamesFromDir(path); AddGamesFromDir(path);
@ -2087,7 +2103,7 @@ void main_window::CreateConnects()
connect(ui->sysStopAct, &QAction::triggered, this, []() connect(ui->sysStopAct, &QAction::triggered, this, []()
{ {
gui_log.notice("User triggered stop action in menu bar"); gui_log.notice("User triggered stop action in menu bar");
Emu.Stop(); Emu.GracefulShutdown(false, true);
}); });
connect(ui->sysRebootAct, &QAction::triggered, this, []() connect(ui->sysRebootAct, &QAction::triggered, this, []()
{ {
@ -2415,7 +2431,7 @@ void main_window::CreateConnects()
connect(ui->toolbar_stop, &QAction::triggered, this, []() connect(ui->toolbar_stop, &QAction::triggered, this, []()
{ {
gui_log.notice("User triggered stop action in toolbar"); gui_log.notice("User triggered stop action in toolbar");
Emu.Stop(); Emu.GracefulShutdown(false);
}); });
connect(ui->toolbar_start, &QAction::triggered, this, &main_window::OnPlayOrPause); connect(ui->toolbar_start, &QAction::triggered, this, &main_window::OnPlayOrPause);
@ -2762,8 +2778,7 @@ void main_window::CreateFirmwareCache()
return; return;
} }
Emu.SetForceBoot(true); Emu.GracefulShutdown(false);
Emu.Stop();
Emu.SetForceBoot(true); Emu.SetForceBoot(true);
if (const game_boot_result error = Emu.BootGame(g_cfg_vfs.get_dev_flash() + "sys", "", true); if (const game_boot_result error = Emu.BootGame(g_cfg_vfs.get_dev_flash() + "sys", "", true);
@ -2811,8 +2826,9 @@ void main_window::closeEvent(QCloseEvent* closeEvent)
// Cleanly stop and quit the emulator. // Cleanly stop and quit the emulator.
if (!Emu.IsStopped()) if (!Emu.IsStopped())
{ {
Emu.Stop(); Emu.GracefulShutdown(false);
} }
Emu.Quit(true); Emu.Quit(true);
} }
@ -3007,10 +3023,13 @@ void main_window::dropEvent(QDropEvent* event)
{ {
return; return;
} }
for (const auto& path : drop_paths) for (const auto& path : drop_paths)
{ {
Emu.GracefulShutdown(false);
AddGamesFromDir(path); AddGamesFromDir(path);
} }
m_game_list_frame->Refresh(true); m_game_list_frame->Refresh(true);
break; break;
} }
@ -3021,8 +3040,7 @@ void main_window::dropEvent(QDropEvent* event)
return; return;
} }
Emu.SetForceBoot(true); Emu.GracefulShutdown(false);
Emu.Stop();
if (const auto error = Emu.BootGame(sstr(drop_paths.first()), "", true); error != game_boot_result::no_errors) if (const auto error = Emu.BootGame(sstr(drop_paths.first()), "", true); error != game_boot_result::no_errors)
{ {

View file

@ -655,8 +655,7 @@ bool update_manager::handle_rpcs3(const QByteArray& data, bool auto_accept)
QMessageBox::information(m_parent, tr("Auto-updater"), tr("Update successful!\nRPCS3 will now restart.")); QMessageBox::information(m_parent, tr("Auto-updater"), tr("Update successful!\nRPCS3 will now restart."));
} }
Emu.SetForceBoot(true); Emu.GracefulShutdown(false);
Emu.Stop();
Emu.CleanUp(); Emu.CleanUp();
#ifdef _WIN32 #ifdef _WIN32

View file

@ -361,7 +361,7 @@ void user_manager_dialog::OnUserLogin()
} }
gui_log.notice("Stopping current emulation in order to change the current user."); gui_log.notice("Stopping current emulation in order to change the current user.");
Emu.Stop(); Emu.GracefulShutdown(false);
} }
const u32 key = GetUserKey(); const u32 key = GetUserKey();