diff --git a/rpcs3/Emu/Cell/Modules/cellSysutil.cpp b/rpcs3/Emu/Cell/Modules/cellSysutil.cpp index b6da4105f1..8fa9b6762e 100644 --- a/rpcs3/Emu/Cell/Modules/cellSysutil.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSysutil.cpp @@ -49,6 +49,7 @@ struct sysutil_cb_manager lf_queue> registered; atomic_t draw_cb_started{}; + atomic_t read_counter{0}; }; extern void sysutil_register_cb(std::function&& cb) @@ -100,6 +101,16 @@ extern s32 sysutil_send_system_cmd(u64 status, u64 param) return count; } +extern u64 get_sysutil_cb_manager_read_count() +{ + if (auto cbm = g_fxo->try_get()) + { + return cbm->read_counter; + } + + return 0; +} + template <> void fmt_class_string::format(std::string& out, u64 arg) { @@ -428,8 +439,12 @@ error_code cellSysutilCheckCallback(ppu_thread& ppu) auto& cbm = g_fxo->get(); + bool read = false; + for (auto&& func : cbm.registered.pop_all()) { + read = true; + if (s32 res = func(ppu)) { // Currently impossible @@ -442,6 +457,11 @@ error_code cellSysutilCheckCallback(ppu_thread& ppu) } } + if (read) + { + cbm.read_counter++; + } + return CELL_OK; } diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index f0a13d9d06..f2a3d97d20 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -1769,6 +1769,8 @@ void Emulator::Resume() } s32 sysutil_send_system_cmd(u64 status, u64 param); +u64 get_sysutil_cb_manager_read_count(); + void process_qt_events(); void Emulator::GracefulShutdown(bool allow_autoexit, bool async_op) @@ -1785,6 +1787,8 @@ void Emulator::GracefulShutdown(bool allow_autoexit, bool async_op) Resume(); } + const u64 read_counter = get_sysutil_cb_manager_read_count(); + 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 @@ -1792,21 +1796,29 @@ void Emulator::GracefulShutdown(bool allow_autoexit, bool async_op) return; } - auto perform_kill = [allow_autoexit, this, info = ProcureCurrentEmulationCourseInformation()]() + auto perform_kill = [read_counter, allow_autoexit, this, info = ProcureCurrentEmulationCourseInformation()]() { - for (u32 i = 0; i < 100; i++) + bool read_sysutil_signal = false; + + for (u32 i = 100; i < 140; 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 (!read_sysutil_signal && read_counter != get_sysutil_cb_manager_read_count()) + { + i -= 100; // Grant 5 seconds (if signal is not read force kill after two second) + read_sysutil_signal = true; + } + if (static_cast(info) != m_stop_ctr) { return; } } - // An inevitable attempt to terminate the *current* emulation course will be issued after 5s + // An inevitable attempt to terminate the *current* emulation course will be issued after 7s CallFromMainThread([allow_autoexit, this]() { Kill(allow_autoexit);