summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrey Kleshchev <117672381+akleshchev@users.noreply.github.com>2026-06-19 23:32:32 +0300
committerAndrey Kleshchev <117672381+akleshchev@users.noreply.github.com>2026-06-22 19:14:20 +0300
commit6d9293fe7393be0f17836c7e5512e8a2d8bb53f4 (patch)
tree217b6e8a67e09c70f1114becf91eaa6f60a6c567
parent9f05efc7618fb5c2ea0d6cb3ac1a21ba38184987 (diff)
#5084 Include watchdog's state in crash report
to help diagnose crashes
-rw-r--r--indra/llcommon/llwatchdog.cpp5
-rw-r--r--indra/llcommon/llwatchdog.h2
-rw-r--r--indra/newview/llappviewer.cpp26
-rw-r--r--indra/newview/llappviewer.h1
-rw-r--r--indra/newview/llappviewerwin32.cpp8
5 files changed, 42 insertions, 0 deletions
diff --git a/indra/llcommon/llwatchdog.cpp b/indra/llcommon/llwatchdog.cpp
index 66b565c763..fd0702733c 100644
--- a/indra/llcommon/llwatchdog.cpp
+++ b/indra/llcommon/llwatchdog.cpp
@@ -116,6 +116,11 @@ bool LLWatchdogTimeout::isAlive() const
return (mTimer.getStarted() && !mTimer.hasExpired());
}
+bool LLWatchdogTimeout::hasExpired() const
+{
+ return mTimer.hasExpired();
+}
+
void LLWatchdogTimeout::reset()
{
mTimer.setTimerExpirySec(mTimeout);
diff --git a/indra/llcommon/llwatchdog.h b/indra/llcommon/llwatchdog.h
index f138fbccb0..b286dd179d 100644
--- a/indra/llcommon/llwatchdog.h
+++ b/indra/llcommon/llwatchdog.h
@@ -47,6 +47,7 @@ public:
// This may mean that resources used by
// isAlive and other method may need synchronization.
virtual bool isAlive() const = 0;
+ virtual bool hasExpired() const = 0;
virtual void reset() = 0;
virtual void start();
virtual void stop();
@@ -66,6 +67,7 @@ public:
virtual ~LLWatchdogTimeout();
bool isAlive() const override;
+ bool hasExpired() const override;
void reset() override;
void start() override { start(""); }
void stop() override;
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 263c1f2054..58e3aea9b7 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -6321,6 +6321,32 @@ F32 LLAppViewer::getMainloopTimeoutSec() const
}
}
+std::string LLAppViewer::getMainloopWatchdogState() const
+{
+ if (!mMainloopTimeout)
+ {
+ return std::string();
+ }
+ std::string state = mMainloopTimeout->getState();
+
+ if (mMainloopTimeout->hasExpired())
+ {
+ return "Expired at " + state;
+ }
+
+ // Check if the watchdog is currently active (timer started)
+ if (!mMainloopTimeout->isAlive())
+ {
+ // Timer is not running, meaning watchdog is paused/stopped
+ if (state.empty())
+ {
+ return "Paused";
+ }
+ return "Paused at " + state;
+ }
+ return state;
+}
+
void LLAppViewer::handleLoginComplete()
{
gLoggedInTime.start();
diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h
index 6ecafae036..1b1a89d756 100644
--- a/indra/newview/llappviewer.h
+++ b/indra/newview/llappviewer.h
@@ -212,6 +212,7 @@ public:
void pingMainloopTimeout(std::string_view state);
F32 getMainloopTimeoutSec() const;
+ std::string getMainloopWatchdogState() const;
// Handle the 'login completed' event.
// *NOTE:Mani Fix this for login abstraction!!
diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp
index 25aeb2a26e..416efa9354 100644
--- a/indra/newview/llappviewerwin32.cpp
+++ b/indra/newview/llappviewerwin32.cpp
@@ -193,6 +193,14 @@ namespace
}
LLAppViewer* app = LLAppViewer::instance();
+
+ // Include mainloop watchdog state if available
+ std::string watchdog_state = app->getMainloopWatchdogState();
+ if (!watchdog_state.empty())
+ {
+ sBugSplatSender->setAttribute(WCSTR(L"WatchdogState"), WCSTR(watchdog_state));
+ }
+
if (!app->isSecondInstance() && !app->errorMarkerExists())
{
// If marker doesn't exist, create a marker with 'other' or 'logout' code for next launch