1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2024-11-22 10:42:36 +01:00

sys_game_watchdog minor fixups

This commit is contained in:
Eladash 2022-10-17 21:40:44 +03:00 committed by Megamouse
parent 035d410a89
commit 7ea0a6d642
2 changed files with 107 additions and 35 deletions

View File

@ -5,53 +5,107 @@
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/system_config.h" #include "Emu/system_config.h"
#include <thread> #include "Emu/IdManager.h"
#include "Utilities/Thread.h"
#include "sys_game.h" #include "sys_game.h"
LOG_CHANNEL(sys_game); LOG_CHANNEL(sys_game);
atomic_t<bool> watchdog_stopped = true; struct watchdog_t
atomic_t<u64> watchdog_last_clear;
u64 get_timestamp()
{ {
return (get_system_time() - Emu.GetPauseTime()); struct alignas(8) control_t
} {
bool needs_restart = false;
bool active = false;
char pad[sizeof(u32) - sizeof(bool) * 2]{};
u32 timeout = 0;
};
atomic_t<control_t> control;
void operator()()
{
u64 start_time = get_system_time();
u64 old_time = start_time;
u64 current_time = old_time;
constexpr u64 sleep_time = 50'000;
while (thread_ctrl::state() != thread_state::aborting)
{
if (Emu.GetStatus(false) == system_state::paused)
{
start_time += current_time - old_time;
old_time = current_time;
thread_ctrl::wait_for(sleep_time);
current_time = get_system_time();
continue;
}
old_time = std::exchange(current_time, get_system_time());
const auto old = control.fetch_op([&](control_t& data)
{
if (data.needs_restart)
{
data.needs_restart = false;
return true;
}
return false;
}).first;
if (old.active && old.needs_restart)
{
start_time = current_time;
old_time = current_time;
continue;
}
if (old.active && current_time - start_time >= old.timeout)
{
sys_game.warning("Watchdog timeout! Restarting the game...");
Emu.CallFromMainThread([]()
{
Emu.Restart();
});
return;
}
thread_ctrl::wait_for(sleep_time);
}
}
static constexpr auto thread_name = "LV2 Watchdog Thread"sv;
};
error_code _sys_game_watchdog_start(u32 timeout) error_code _sys_game_watchdog_start(u32 timeout)
{ {
sys_game.trace("sys_game_watchdog_start(timeout=%d)", timeout); sys_game.trace("sys_game_watchdog_start(timeout=%d)", timeout);
if (!watchdog_stopped) // According to disassembly
timeout *= 1'000'000;
timeout &= -64;
if (!g_fxo->get<named_thread<watchdog_t>>().control.fetch_op([&](watchdog_t::control_t& data)
{
if (data.active)
{
return false;
}
data.needs_restart = true;
data.active = true;
data.timeout = timeout;
return true;
}).second)
{ {
return CELL_EABORT; return CELL_EABORT;
} }
auto watchdog = [=]()
{
while (!watchdog_stopped)
{
if (Emu.IsStopped() || get_timestamp() - watchdog_last_clear > timeout * 1000000)
{
watchdog_stopped = true;
if (!Emu.IsStopped())
{
sys_game.warning("Watchdog timeout! Restarting the game...");
Emu.CallFromMainThread([]()
{
Emu.Restart();
});
}
break;
}
std::this_thread::sleep_for(1s);
}
};
watchdog_stopped = false;
watchdog_last_clear = get_timestamp();
std::thread(watchdog).detach();
return CELL_OK; return CELL_OK;
} }
@ -59,7 +113,16 @@ error_code _sys_game_watchdog_stop()
{ {
sys_game.trace("sys_game_watchdog_stop()"); sys_game.trace("sys_game_watchdog_stop()");
watchdog_stopped = true; g_fxo->get<named_thread<watchdog_t>>().control.fetch_op([](watchdog_t::control_t& data)
{
if (!data.active)
{
return false;
}
data.active = false;
return true;
});
return CELL_OK; return CELL_OK;
} }
@ -68,7 +131,16 @@ error_code _sys_game_watchdog_clear()
{ {
sys_game.trace("sys_game_watchdog_clear()"); sys_game.trace("sys_game_watchdog_clear()");
watchdog_last_clear = get_timestamp(); g_fxo->get<named_thread<watchdog_t>>().control.fetch_op([](watchdog_t::control_t& data)
{
if (!data.active || data.needs_restart)
{
return false;
}
data.needs_restart = true;
return true;
});
return CELL_OK; return CELL_OK;
} }

View File

@ -314,7 +314,7 @@ public:
bool IsStopped() const { return m_state == system_state::stopped; } bool IsStopped() const { return m_state == system_state::stopped; }
bool IsReady() const { return m_state == system_state::ready; } bool IsReady() const { return m_state == system_state::ready; }
bool IsStarting() const { return m_state == system_state::starting; } bool IsStarting() const { return m_state == system_state::starting; }
auto GetStatus() const { system_state state = m_state; return state == system_state::frozen ? system_state::paused : state; } auto GetStatus(bool fixup = true) const { system_state state = m_state; return fixup && state == system_state::frozen ? system_state::paused : state; }
bool HasGui() const { return m_has_gui; } bool HasGui() const { return m_has_gui; }
void SetHasGui(bool has_gui) { m_has_gui = has_gui; } void SetHasGui(bool has_gui) { m_has_gui = has_gui; }