From 107ea4d84950e13be6b7291f506419b1839a0dda Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> Date: Fri, 19 Dec 2025 13:18:41 +0200 Subject: #5084 Cover window's thread with watchdog --- indra/llwindow/llwindowwin32.cpp | 65 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) (limited to 'indra/llwindow/llwindowwin32.cpp') diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index f826a60ddd..9d05d7e5a4 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -49,6 +49,7 @@ #include "llthreadsafequeue.h" #include "stringize.h" #include "llframetimer.h" +#include "llwatchdog.h" // System includes #include @@ -364,7 +365,8 @@ static LLMonitorInfo sMonitorInfo; // the containing class a friend. struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool { - static const int MAX_QUEUE_SIZE = 2048; + static constexpr int MAX_QUEUE_SIZE = 2048; + static constexpr F32 WINDOW_TIMEOUT_SEC = 90.f; LLThreadSafeQueue mMessageQueue; @@ -426,6 +428,50 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool PostMessage(windowHandle, WM_POST_FUNCTION_, wparam, LPARAM(ptr)); } + // Call from main thread. + void initTimeout() + { + // post into thread's queue to avoid threading issues + post([this]() + { + if (!mWindowTimeout) + { + mWindowTimeout = std::make_unique("mainloop"); + // supposed to be executed within run(), + // so no point checking if thread is alive + resumeTimeout("TimeoutInit"); + } + }); + } +private: + // These timeout related functions are strictly for the thread. + void resumeTimeout(std::string_view state) + { + if (mWindowTimeout) + { + mWindowTimeout->setTimeout(WINDOW_TIMEOUT_SEC); + mWindowTimeout->start(state); + } + } + + void pauseTimeout() + { + if (mWindowTimeout) + { + mWindowTimeout->stop(); + } + } + + void pingTimeout(std::string_view state) + { + if (mWindowTimeout) + { + mWindowTimeout->setTimeout(WINDOW_TIMEOUT_SEC); + mWindowTimeout->ping(state); + } + } + +public: using FuncType = std::function; // call GetMessage() and pull enqueue messages for later processing HWND mWindowHandleThrd = NULL; @@ -436,6 +482,8 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool bool mGLReady = false; bool mGotGLBuffer = false; LLAtomicBool mDeleteOnExit = false; +private: + std::unique_ptr mWindowTimeout; }; @@ -4595,6 +4643,11 @@ bool LLWindowWin32::getInputDevices(U32 device_type_filter, return false; } +void LLWindowWin32::initWatchdog() +{ + mWindowThread->initTimeout(); +} + F32 LLWindowWin32::getSystemUISize() { F32 scale_value = 1.f; @@ -4732,6 +4785,8 @@ void LLWindowWin32::LLWindowWin32Thread::checkDXMem() return; } + pauseTimeout(); + IDXGIFactory4* p_factory = nullptr; HRESULT res = CreateDXGIFactory1(__uuidof(IDXGIFactory4), (void**)&p_factory); @@ -4835,6 +4890,8 @@ void LLWindowWin32::LLWindowWin32Thread::checkDXMem() } mGotGLBuffer = true; + + resumeTimeout("checkDXMem"); } void LLWindowWin32::LLWindowWin32Thread::run() @@ -4850,6 +4907,9 @@ void LLWindowWin32::LLWindowWin32Thread::run() timeBeginPeriod(llclamp((U32) 1, tc.wPeriodMin, tc.wPeriodMax)); } + // Normally won't exist yet, but in case of re-init, make sure it's cleaned up + resumeTimeout("WindowThread"); + while (! getQueue().done()) { LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32; @@ -4859,6 +4919,7 @@ void LLWindowWin32::LLWindowWin32Thread::run() if (mWindowHandleThrd != 0) { + pingTimeout("messages"); MSG msg; BOOL status; if (mhDCThrd == 0) @@ -4886,6 +4947,7 @@ void LLWindowWin32::LLWindowWin32Thread::run() { LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("w32t - Function Queue"); + pingTimeout("queue"); logger.onChange("runPending()"); //process any pending functions getQueue().runPending(); @@ -4900,6 +4962,7 @@ void LLWindowWin32::LLWindowWin32Thread::run() #endif } + pauseTimeout(); destroyWindow(); if (mDeleteOnExit) -- cgit v1.3 From 60651640a3114dd2c6a8c0f880234921506ab207 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> Date: Fri, 13 Feb 2026 02:10:45 +0200 Subject: #5084 Adjust Window's watchdog to only run after login like mainloop does --- indra/llwindow/llwindowwin32.cpp | 2 +- indra/newview/llappviewer.cpp | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'indra/llwindow/llwindowwin32.cpp') diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 9d05d7e5a4..2bd9dd053c 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -436,7 +436,7 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool { if (!mWindowTimeout) { - mWindowTimeout = std::make_unique("mainloop"); + mWindowTimeout = std::make_unique("WindowThread"); // supposed to be executed within run(), // so no point checking if thread is alive resumeTimeout("TimeoutInit"); diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 35edbf089e..93a0cd9d43 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -3200,7 +3200,6 @@ bool LLAppViewer::initWindow() app->createErrorMarker(LAST_EXEC_FROZE); } }); - gViewerWindow->getWindow()->initWatchdog(); } LLNotificationsUI::LLNotificationManager::getInstance(); @@ -5924,6 +5923,11 @@ void LLAppViewer::handleLoginComplete() { gLoggedInTime.start(); initMainloopTimeout("Mainloop Init"); + LLWindow* viewer_window = gViewerWindow->getWindow(); + if (viewer_window) // in case of a headless client + { + viewer_window->initWatchdog(); + } // Store some data to DebugInfo in case of a freeze. gDebugInfo["ClientInfo"]["Name"] = LLVersionInfo::instance().getChannel(); -- cgit v1.3