History

Add a watchdog thread to trigger a crash on detecting a deadlock

Brad Davis committed 10 years ago

Commit 95f5d821 parent d1401794 files · +52 −0Browse files

Showing the changes to interface/src/Application.cpp (1 of 4 files). Show all

Unified · Split

interface/src/Application.cpp+48−0
@@ -235,6 +235,42 @@ const QHash<QString, Application::AcceptURLMethod> Application::_acceptedExtensi · 234 unmodified lines
235235 { AVA_JSON_EXTENSION, &Application::askToWearAvatarAttachmentUrl }
236236 };
237237
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+
238274 #ifdef Q_OS_WIN
239275 class MyNativeEventFilter : public QAbstractNativeEventFilter {
240276 public:
@@ -457,6 +493,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : · 216 unmodified lines
457493
458494 auto nodeList = DependencyManager::get<NodeList>();
459495
496+ // Set up a watchdog thread to intentionally crash the application on deadlocks
497+ (new DeadlockWatchdogThread())->start();
498+
460499 qCDebug(interfaceapp) << "[VERSION] Build sequence:" << qPrintable(applicationVersion());
461500
462501 _bookmarks = new Bookmarks(); // Before setting up the menu
@@ -4960,6 +4999,15 @@ void Application::crashApplication() { · 4497 unmodified lines
49604999 Q_UNUSED(value);
49615000 }
49625001
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+
49635011 void Application::setActiveDisplayPlugin(const QString& pluginName) {
49645012 auto menu = Menu::getInstance();
49655013 foreach(DisplayPluginPointer displayPlugin, PluginManager::getInstance()->getDisplayPlugins()) {