Showing the changes to interface/src/Application.cpp (1 of 4 files). Show all
Unified · Split
| @@ -235,6 +235,42 @@ const QHash<QString, Application::AcceptURLMethod> Application::_acceptedExtensi · 234 unmodified lines | |||
| 235 | { AVA_JSON_EXTENSION, &Application::askToWearAvatarAttachmentUrl } | 235 | { AVA_JSON_EXTENSION, &Application::askToWearAvatarAttachmentUrl } |
| 236 | }; | 236 | }; |
| 237 | 237 | ||
| 238 | class DeadlockWatchdogThread : public QThread { | ||
| 239 | public: | ||
| 240 | static const unsigned long HEARTBEAT_CHECK_INTERVAL_SECS = 1; | ||
| 241 | static const unsigned long HEARTBEAT_UPDATE_INTERVAL_SECS = 1; | ||
| 242 | static const unsigned long MAX_HEARTBEAT_AGE_USECS = 10 * USECS_PER_SECOND; | ||
| 243 | |||
| 244 | // Set the heartbeat on launch | ||
| 245 | DeadlockWatchdogThread() { | ||
| 246 | QTimer* heartbeatTimer = new QTimer(); | ||
| 247 | connect(heartbeatTimer, &QTimer::timeout, [this] { | ||
| 248 | _heartbeat = usecTimestampNow(); | ||
| 249 | }); | ||
| 250 | heartbeatTimer->start(HEARTBEAT_UPDATE_INTERVAL_SECS * MSECS_PER_SECOND); | ||
| 251 | } | ||
| 252 | |||
| 253 | void deadlockDetectionCrash() { | ||
| 254 | uint32_t* crashTrigger = nullptr; | ||
| 255 | *crashTrigger = 0xDEAD10CC; | ||
| 256 | } | ||
| 257 | |||
| 258 | void run() override { | ||
| 259 | while (!qApp->isAboutToQuit()) { | ||
| 260 | QThread::sleep(HEARTBEAT_UPDATE_INTERVAL_SECS); | ||
| 261 | auto now = usecTimestampNow(); | ||
| 262 | auto lastHeartbeatAge = now - _heartbeat; | ||
| 263 | if (lastHeartbeatAge > MAX_HEARTBEAT_AGE_USECS) { | ||
| 264 | deadlockDetectionCrash(); | ||
| 265 | } | ||
| 266 | } | ||
| 267 | } | ||
| 268 | |||
| 269 | static std::atomic<uint64_t> _heartbeat; | ||
| 270 | }; | ||
| 271 | |||
| 272 | std::atomic<uint64_t> DeadlockWatchdogThread::_heartbeat; | ||
| 273 | |||
| 238 | #ifdef Q_OS_WIN | 274 | #ifdef Q_OS_WIN |
| 239 | class MyNativeEventFilter : public QAbstractNativeEventFilter { | 275 | class MyNativeEventFilter : public QAbstractNativeEventFilter { |
| 240 | public: | 276 | public: |
| @@ -457,6 +493,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : · 216 unmodified lines | |||
| 457 | 493 | ||
| 458 | auto nodeList = DependencyManager::get<NodeList>(); | 494 | auto nodeList = DependencyManager::get<NodeList>(); |
| 459 | 495 | ||
| 496 | // Set up a watchdog thread to intentionally crash the application on deadlocks | ||
| 497 | (new DeadlockWatchdogThread())->start(); | ||
| 498 | |||
| 460 | qCDebug(interfaceapp) << "[VERSION] Build sequence:" << qPrintable(applicationVersion()); | 499 | qCDebug(interfaceapp) << "[VERSION] Build sequence:" << qPrintable(applicationVersion()); |
| 461 | 500 | ||
| 462 | _bookmarks = new Bookmarks(); // Before setting up the menu | 501 | _bookmarks = new Bookmarks(); // Before setting up the menu |
| @@ -4960,6 +4999,15 @@ void Application::crashApplication() { · 4497 unmodified lines | |||
| 4960 | Q_UNUSED(value); | 4999 | Q_UNUSED(value); |
| 4961 | } | 5000 | } |
| 4962 | 5001 | ||
| 5002 | void Application::deadlockApplication() { | ||
| 5003 | qCDebug(interfaceapp) << "Intentionally deadlocked Interface"; | ||
| 5004 | // Using a loop that will *technically* eventually exit (in ~600 billion years) | ||
| 5005 | // to avoid compiler warnings about a loop that will never exit | ||
| 5006 | for (uint64_t i = 1; i != 0; ++i) { | ||
| 5007 | QThread::sleep(1); | ||
| 5008 | } | ||
| 5009 | } | ||
| 5010 | |||
| 4963 | void Application::setActiveDisplayPlugin(const QString& pluginName) { | 5011 | void Application::setActiveDisplayPlugin(const QString& pluginName) { |
| 4964 | auto menu = Menu::getInstance(); | 5012 | auto menu = Menu::getInstance(); |
| 4965 | foreach(DisplayPluginPointer displayPlugin, PluginManager::getInstance()->getDisplayPlugins()) { | 5013 | foreach(DisplayPluginPointer displayPlugin, PluginManager::getInstance()->getDisplayPlugins()) { |