mirror of https://github.com/AxioDL/metaforce.git
Add CInfiniteLoopDetector to detect infinite loops in release builds
This commit is contained in:
parent
740114af9e
commit
d93cf46bc3
|
@ -0,0 +1,37 @@
|
||||||
|
#include "Runtime/CInfiniteLoopDetector.hpp"
|
||||||
|
#include <logvisor/logvisor.hpp>
|
||||||
|
|
||||||
|
namespace metaforce {
|
||||||
|
namespace {
|
||||||
|
logvisor::Module Log("CInfiniteLoopDetector");
|
||||||
|
std::chrono::system_clock::time_point g_WatchDog = std::chrono::system_clock::now();
|
||||||
|
std::mutex g_mutex;
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
CInfiniteLoopDetector::CInfiniteLoopDetector(int duration)
|
||||||
|
: m_duration(duration), m_futureObj(m_stopRequested.get_future()) {}
|
||||||
|
|
||||||
|
bool CInfiniteLoopDetector::stopRequested() const {
|
||||||
|
return m_futureObj.wait_for(std::chrono::milliseconds(0)) != std::future_status::timeout;
|
||||||
|
}
|
||||||
|
void CInfiniteLoopDetector::run() {
|
||||||
|
std::chrono::system_clock::time_point start = std::chrono::system_clock::now();
|
||||||
|
while (!stopRequested()) {
|
||||||
|
if (std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - start) >
|
||||||
|
std::chrono::milliseconds(m_duration)) {
|
||||||
|
std::lock_guard<std::mutex> guard(g_mutex);
|
||||||
|
if (std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - g_WatchDog) >
|
||||||
|
std::chrono::milliseconds(m_duration)) {
|
||||||
|
Log.report(logvisor::Fatal, FMT_STRING("INFINITE LOOP DETECTED!"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CInfiniteLoopDetector::UpdateWatchDog(std::chrono::system_clock::time_point time) {
|
||||||
|
std::lock_guard<std::mutex> guard(g_mutex);
|
||||||
|
g_WatchDog = time;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CInfiniteLoopDetector::stop() { m_stopRequested.set_value(); }
|
||||||
|
} // namespace metaforce
|
|
@ -0,0 +1,20 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <mutex>
|
||||||
|
#include <future>
|
||||||
|
|
||||||
|
namespace metaforce {
|
||||||
|
class CInfiniteLoopDetector {
|
||||||
|
int m_duration = 0;
|
||||||
|
std::mutex m_mutex;
|
||||||
|
std::promise<void> m_stopRequested;
|
||||||
|
std::future<void> m_futureObj;
|
||||||
|
bool stopRequested() const;
|
||||||
|
public:
|
||||||
|
explicit CInfiniteLoopDetector(int duration=1000);
|
||||||
|
void run();
|
||||||
|
void stop();
|
||||||
|
static void UpdateWatchDog(std::chrono::system_clock::time_point WatchDog);
|
||||||
|
};
|
||||||
|
}
|
|
@ -2,6 +2,7 @@
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include "Runtime/CInfiniteLoopDetector.hpp"
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
#ifndef WIN32_LEAN_AND_MEAN
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
|
@ -308,6 +309,10 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
bool onAppIdle(float realDt) noexcept override {
|
bool onAppIdle(float realDt) noexcept override {
|
||||||
|
#ifdef NDEBUG
|
||||||
|
/* Ping the watchdog to let it know we're still alive */
|
||||||
|
CInfiniteLoopDetector::UpdateWatchDog(std::chrono::system_clock::now());
|
||||||
|
#endif
|
||||||
if (auto* input = g_InputGenerator) {
|
if (auto* input = g_InputGenerator) {
|
||||||
if (!m_deferredControllers.empty()) {
|
if (!m_deferredControllers.empty()) {
|
||||||
for (const auto which : m_deferredControllers) {
|
for (const auto which : m_deferredControllers) {
|
||||||
|
@ -605,7 +610,18 @@ int main(int argc, char** argv) {
|
||||||
.width = icon.width,
|
.width = icon.width,
|
||||||
.height = icon.height,
|
.height = icon.height,
|
||||||
};
|
};
|
||||||
|
#ifdef NDEBUG
|
||||||
|
/* Before we start running the app, lets get a thread going to detect any infinite loops */
|
||||||
|
metaforce::CInfiniteLoopDetector infiniteLoopDetector;
|
||||||
|
std::thread infiniteLoopDetectorThread(&metaforce::CInfiniteLoopDetector::run, &infiniteLoopDetector);
|
||||||
|
infiniteLoopDetectorThread.detach();
|
||||||
aurora::app_run(std::move(app), std::move(data), argc, argv);
|
aurora::app_run(std::move(app), std::move(data), argc, argv);
|
||||||
|
infiniteLoopDetector.stop();
|
||||||
|
#else
|
||||||
|
/* Debuggers can interrupt the loop detector and make it unable to perform its job correctly, so lets not detect
|
||||||
|
* infinite loops in a debug build */
|
||||||
|
aurora::app_run(std::move(app), std::move(data), argc, argv);
|
||||||
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -61,6 +61,7 @@ set(RUNTIME_SOURCES_B
|
||||||
${PARTICLE_SOURCES}
|
${PARTICLE_SOURCES}
|
||||||
${WORLD_SOURCES}
|
${WORLD_SOURCES}
|
||||||
${WEAPON_SOURCES}
|
${WEAPON_SOURCES}
|
||||||
|
CInfiniteLoopDetector.hpp CInfiniteLoopDetector.cpp
|
||||||
ConsoleVariables/FileStoreManager.hpp ConsoleVariables/FileStoreManager.cpp
|
ConsoleVariables/FileStoreManager.hpp ConsoleVariables/FileStoreManager.cpp
|
||||||
ConsoleVariables/CVar.hpp ConsoleVariables/CVar.cpp
|
ConsoleVariables/CVar.hpp ConsoleVariables/CVar.cpp
|
||||||
ConsoleVariables/CVarManager.hpp ConsoleVariables/CVarManager.cpp
|
ConsoleVariables/CVarManager.hpp ConsoleVariables/CVarManager.cpp
|
||||||
|
|
|
@ -138,9 +138,15 @@ static bool poll_events() noexcept {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SDL_CONTROLLERAXISMOTION: {
|
case SDL_CONTROLLERAXISMOTION: {
|
||||||
|
if (event.caxis.value > 8000 || event.caxis.value < -8000) {
|
||||||
g_AppDelegate->onControllerAxis(
|
g_AppDelegate->onControllerAxis(
|
||||||
event.caxis.which, input::translate_controller_axis(static_cast<SDL_GameControllerAxis>(event.caxis.axis)),
|
event.caxis.which, input::translate_controller_axis(static_cast<SDL_GameControllerAxis>(event.caxis.axis)),
|
||||||
event.caxis.value);
|
event.caxis.value);
|
||||||
|
} else {
|
||||||
|
g_AppDelegate->onControllerAxis(
|
||||||
|
event.caxis.which, input::translate_controller_axis(static_cast<SDL_GameControllerAxis>(event.caxis.axis)),
|
||||||
|
0);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SDL_KEYDOWN: {
|
case SDL_KEYDOWN: {
|
||||||
|
|
Loading…
Reference in New Issue