From ff9321e971511262ca35640fee27b20c2523521b Mon Sep 17 00:00:00 2001 From: Ilya Fedin Date: Mon, 21 Aug 2023 03:21:30 +0400 Subject: [PATCH] Main thread deadlock detector for debug mode --- Telegram/CMakeLists.txt | 1 + Telegram/SourceFiles/core/deadlock_detector.h | 83 +++++++++++++++++++ Telegram/SourceFiles/core/sandbox.cpp | 12 +++ Telegram/SourceFiles/core/sandbox.h | 2 + 4 files changed, 98 insertions(+) create mode 100644 Telegram/SourceFiles/core/deadlock_detector.h diff --git a/Telegram/CMakeLists.txt b/Telegram/CMakeLists.txt index 6f9dbff7d..d555578f7 100644 --- a/Telegram/CMakeLists.txt +++ b/Telegram/CMakeLists.txt @@ -413,6 +413,7 @@ PRIVATE core/crash_report_window.h core/crash_reports.cpp core/crash_reports.h + core/deadlock_detector.h core/file_utilities.cpp core/file_utilities.h core/launcher.cpp diff --git a/Telegram/SourceFiles/core/deadlock_detector.h b/Telegram/SourceFiles/core/deadlock_detector.h new file mode 100644 index 000000000..fb538cf62 --- /dev/null +++ b/Telegram/SourceFiles/core/deadlock_detector.h @@ -0,0 +1,83 @@ +/* +This file is part of Telegram Desktop, +the official desktop application for the Telegram messaging service. + +For license and copyright information please follow this link: +https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL +*/ +#pragma once + +namespace Core::DeadlockDetector { + +class PingPongEvent : public QEvent { +public: + static auto Type() { + static const auto Result = QEvent::Type(QEvent::registerEventType()); + return Result; + } + + PingPongEvent(not_null sender) + : QEvent(Type()) + , _sender(sender) { + } + + [[nodiscard]] not_null sender() const { + return _sender; + } + +private: + not_null _sender; + +}; + +class Pinger : public QObject { +public: + Pinger(not_null receiver) + : _receiver(receiver) + , _abortTimer([] { Unexpected("Deadlock found!"); }) { + const auto callback = [=] { + QCoreApplication::postEvent(_receiver, new PingPongEvent(this)); + _abortTimer.callOnce(30000); + }; + _pingTimer.setCallback(callback); + _pingTimer.callEach(60000); + callback(); + } + +protected: + bool event(QEvent *e) override { + if (e->type() == PingPongEvent::Type() + && static_cast(e)->sender() == _receiver) { + _abortTimer.cancel(); + } + return QObject::event(e); + } + +private: + not_null _receiver; + base::Timer _pingTimer; + base::Timer _abortTimer; + +}; + +class PingThread : public QThread { +public: + PingThread(not_null parent) + : QThread(parent) { + start(); + } + + ~PingThread() { + quit(); + wait(); + } + +protected: + void run() override { + Pinger pinger(parent()); + QThread::run(); + } + +}; + +} // namespace Core::DeadlockDetector diff --git a/Telegram/SourceFiles/core/sandbox.cpp b/Telegram/SourceFiles/core/sandbox.cpp index 1a6c949cf..45d2bef81 100644 --- a/Telegram/SourceFiles/core/sandbox.cpp +++ b/Telegram/SourceFiles/core/sandbox.cpp @@ -20,6 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "core/launcher.h" #include "core/local_url_handlers.h" #include "core/update_checker.h" +#include "core/deadlock_detector.h" #include "base/timer.h" #include "base/concurrent_timer.h" #include "base/invoke_queued.h" @@ -198,6 +199,13 @@ void Sandbox::launchApplication() { } setupScreenScale(); +#ifndef _DEBUG + if (Logs::DebugEnabled()) { + using DeadlockDetector::PingThread; + _deadlockDetector = std::make_unique(this); + } +#endif // !_DEBUG + _application = std::make_unique(); // Ideally this should go to constructor. @@ -267,6 +275,10 @@ bool Sandbox::event(QEvent *e) { return false; } else if (e->type() == QEvent::Close) { Quit(); + } else if (e->type() == DeadlockDetector::PingPongEvent::Type()) { + postEvent( + static_cast(e)->sender(), + new DeadlockDetector::PingPongEvent(this)); } return QApplication::event(e); } diff --git a/Telegram/SourceFiles/core/sandbox.h b/Telegram/SourceFiles/core/sandbox.h index d8f47cd5a..4c15c2828 100644 --- a/Telegram/SourceFiles/core/sandbox.h +++ b/Telegram/SourceFiles/core/sandbox.h @@ -131,6 +131,8 @@ private: rpl::event_stream<> _widgetUpdateRequests; + std::unique_ptr _deadlockDetector; + }; } // namespace Core