mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 12:28:02 +02:00
Add a watchdog thread to trigger a crash on detecting a deadlock
This commit is contained in:
parent
d1401796d8
commit
95f5d82d37
4 changed files with 52 additions and 0 deletions
|
@ -235,6 +235,42 @@ const QHash<QString, Application::AcceptURLMethod> Application::_acceptedExtensi
|
||||||
{ AVA_JSON_EXTENSION, &Application::askToWearAvatarAttachmentUrl }
|
{ AVA_JSON_EXTENSION, &Application::askToWearAvatarAttachmentUrl }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class DeadlockWatchdogThread : public QThread {
|
||||||
|
public:
|
||||||
|
static const unsigned long HEARTBEAT_CHECK_INTERVAL_SECS = 1;
|
||||||
|
static const unsigned long HEARTBEAT_UPDATE_INTERVAL_SECS = 1;
|
||||||
|
static const unsigned long MAX_HEARTBEAT_AGE_USECS = 10 * USECS_PER_SECOND;
|
||||||
|
|
||||||
|
// Set the heartbeat on launch
|
||||||
|
DeadlockWatchdogThread() {
|
||||||
|
QTimer* heartbeatTimer = new QTimer();
|
||||||
|
connect(heartbeatTimer, &QTimer::timeout, [this] {
|
||||||
|
_heartbeat = usecTimestampNow();
|
||||||
|
});
|
||||||
|
heartbeatTimer->start(HEARTBEAT_UPDATE_INTERVAL_SECS * MSECS_PER_SECOND);
|
||||||
|
}
|
||||||
|
|
||||||
|
void deadlockDetectionCrash() {
|
||||||
|
uint32_t* crashTrigger = nullptr;
|
||||||
|
*crashTrigger = 0xDEAD10CC;
|
||||||
|
}
|
||||||
|
|
||||||
|
void run() override {
|
||||||
|
while (!qApp->isAboutToQuit()) {
|
||||||
|
QThread::sleep(HEARTBEAT_UPDATE_INTERVAL_SECS);
|
||||||
|
auto now = usecTimestampNow();
|
||||||
|
auto lastHeartbeatAge = now - _heartbeat;
|
||||||
|
if (lastHeartbeatAge > MAX_HEARTBEAT_AGE_USECS) {
|
||||||
|
deadlockDetectionCrash();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::atomic<uint64_t> _heartbeat;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::atomic<uint64_t> DeadlockWatchdogThread::_heartbeat;
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
class MyNativeEventFilter : public QAbstractNativeEventFilter {
|
class MyNativeEventFilter : public QAbstractNativeEventFilter {
|
||||||
public:
|
public:
|
||||||
|
@ -457,6 +493,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
||||||
|
|
||||||
auto nodeList = DependencyManager::get<NodeList>();
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
|
|
||||||
|
// Set up a watchdog thread to intentionally crash the application on deadlocks
|
||||||
|
(new DeadlockWatchdogThread())->start();
|
||||||
|
|
||||||
qCDebug(interfaceapp) << "[VERSION] Build sequence:" << qPrintable(applicationVersion());
|
qCDebug(interfaceapp) << "[VERSION] Build sequence:" << qPrintable(applicationVersion());
|
||||||
|
|
||||||
_bookmarks = new Bookmarks(); // Before setting up the menu
|
_bookmarks = new Bookmarks(); // Before setting up the menu
|
||||||
|
@ -4960,6 +4999,15 @@ void Application::crashApplication() {
|
||||||
Q_UNUSED(value);
|
Q_UNUSED(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Application::deadlockApplication() {
|
||||||
|
qCDebug(interfaceapp) << "Intentionally deadlocked Interface";
|
||||||
|
// Using a loop that will *technically* eventually exit (in ~600 billion years)
|
||||||
|
// to avoid compiler warnings about a loop that will never exit
|
||||||
|
for (uint64_t i = 1; i != 0; ++i) {
|
||||||
|
QThread::sleep(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Application::setActiveDisplayPlugin(const QString& pluginName) {
|
void Application::setActiveDisplayPlugin(const QString& pluginName) {
|
||||||
auto menu = Menu::getInstance();
|
auto menu = Menu::getInstance();
|
||||||
foreach(DisplayPluginPointer displayPlugin, PluginManager::getInstance()->getDisplayPlugins()) {
|
foreach(DisplayPluginPointer displayPlugin, PluginManager::getInstance()->getDisplayPlugins()) {
|
||||||
|
|
|
@ -276,6 +276,7 @@ public slots:
|
||||||
void reloadResourceCaches();
|
void reloadResourceCaches();
|
||||||
|
|
||||||
void crashApplication();
|
void crashApplication();
|
||||||
|
void deadlockApplication();
|
||||||
|
|
||||||
void rotationModeChanged();
|
void rotationModeChanged();
|
||||||
|
|
||||||
|
|
|
@ -590,6 +590,8 @@ Menu::Menu() {
|
||||||
addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::DisplayCrashOptions, 0, true);
|
addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::DisplayCrashOptions, 0, true);
|
||||||
// Developer > Crash Application
|
// Developer > Crash Application
|
||||||
addActionToQMenuAndActionHash(developerMenu, MenuOption::CrashInterface, 0, qApp, SLOT(crashApplication()));
|
addActionToQMenuAndActionHash(developerMenu, MenuOption::CrashInterface, 0, qApp, SLOT(crashApplication()));
|
||||||
|
// Developer > Deadlock Application
|
||||||
|
addActionToQMenuAndActionHash(developerMenu, MenuOption::DeadlockInterface, 0, qApp, SLOT(deadlockApplication()));
|
||||||
|
|
||||||
// Developer > Log...
|
// Developer > Log...
|
||||||
addActionToQMenuAndActionHash(developerMenu, MenuOption::Log, Qt::CTRL | Qt::SHIFT | Qt::Key_L,
|
addActionToQMenuAndActionHash(developerMenu, MenuOption::Log, Qt::CTRL | Qt::SHIFT | Qt::Key_L,
|
||||||
|
|
|
@ -66,6 +66,7 @@ namespace MenuOption {
|
||||||
const QString CopyPath = "Copy Path to Clipboard";
|
const QString CopyPath = "Copy Path to Clipboard";
|
||||||
const QString CoupleEyelids = "Couple Eyelids";
|
const QString CoupleEyelids = "Couple Eyelids";
|
||||||
const QString CrashInterface = "Crash Interface";
|
const QString CrashInterface = "Crash Interface";
|
||||||
|
const QString DeadlockInterface = "Deadlock Interface";
|
||||||
const QString DecreaseAvatarSize = "Decrease Avatar Size";
|
const QString DecreaseAvatarSize = "Decrease Avatar Size";
|
||||||
const QString DeleteBookmark = "Delete Bookmark...";
|
const QString DeleteBookmark = "Delete Bookmark...";
|
||||||
const QString DisableActivityLogger = "Disable Activity Logger";
|
const QString DisableActivityLogger = "Disable Activity Logger";
|
||||||
|
|
Loading…
Reference in a new issue