Skip to content

Commit

Permalink
sys_game_watchdog minor fixups
Browse files Browse the repository at this point in the history
  • Loading branch information
elad335 committed Oct 17, 2022
1 parent 5c24009 commit 77198ff
Showing 1 changed file with 101 additions and 31 deletions.
132 changes: 101 additions & 31 deletions rpcs3/Emu/Cell/lv2/sys_game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,52 +5,104 @@
#include "Emu/System.h"
#include "Emu/system_config.h"

#include <thread>
#include "Emu/IdManager.h"
#include "Utilities/Thread.h"

#include "sys_game.h"

LOG_CHANNEL(sys_game);

atomic_t<bool> watchdog_stopped = true;
atomic_t<u64> watchdog_last_clear;
u64 get_timestamp()
struct watchdog_t
{
return (get_system_time() - Emu.GetPauseTime());
}
struct alignas(16) control_t
{
bool needs_restart = false;
bool active = false;
char pad[sizeof(u64) - sizeof(bool) * 2]{};
u64 timeout = umax;
};

error_code _sys_game_watchdog_start(u32 timeout)
{
sys_game.trace("sys_game_watchdog_start(timeout=%d)", timeout);
atomic_t<control_t> control{};

if (!watchdog_stopped)
void operator()()
{
return CELL_EABORT;
}
u64 start_time = get_system_time();
u64 old_time = start_time;
u64 current_time = old_time;

auto watchdog = [=]()
{
while (!watchdog_stopped)
constexpr u64 sleep_time = 50'000;

while (thread_ctrl::state() != thread_state::aborting)
{
if (Emu.IsStopped() || get_timestamp() - watchdog_last_clear > timeout * 1000000)
if (Emu.IsPaused())
{
watchdog_stopped = true;
if (!Emu.IsStopped())
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());

auto old = control.fetch_op([&](control_t& data)
{
if (data.needs_restart)
{
sys_game.warning("Watchdog timeout! Restarting the game...");
Emu.CallFromMainThread([]()
{
Emu.Restart();
});
data.needs_restart = false;
return true;
}
break;

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;
}
std::this_thread::sleep_for(1s);

thread_ctrl::wait_for(sleep_time);
}
};
}
};

error_code _sys_game_watchdog_start(u32 timeout)
{
sys_game.trace("sys_game_watchdog_start(timeout=%d)", timeout);

// According to disassembly
timeout *= 1'000'000;
timeout &= -64;

watchdog_stopped = false;
watchdog_last_clear = get_timestamp();
std::thread(watchdog).detach();
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_OK;
}
Expand All @@ -59,7 +111,16 @@ error_code _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;
}
Expand All @@ -68,7 +129,16 @@ error_code _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;
}
Expand Down

0 comments on commit 77198ff

Please sign in to comment.