summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrey Kleshchev <andreykproductengine@lindenlab.com>2024-02-29 21:14:39 +0200
committerAndrey Kleshchev <117672381+akleshchev@users.noreply.github.com>2024-03-01 18:20:01 +0200
commitfe3be58938ec3a6241d011156cd6ff3607ed1602 (patch)
tree4127b0caf23473b03b31c3256079df4c2d8d503d
parent6d077c90a01121e1d11c7a4c8e3867cebf937e0d (diff)
SL-18721 Shutdown fixes #6
-rw-r--r--indra/llwindow/llwindowwin32.cpp183
1 files changed, 113 insertions, 70 deletions
diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index 8cc8f9c408..0d56d2f6f6 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -353,7 +353,7 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool
void run() override;
// closes queue, wakes thread, waits until thread closes
- void wakeAndClose();
+ void wakeAndDestroy();
void glReady()
{
@@ -366,6 +366,9 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool
// initialize D3D (if DXGI cannot be used)
void initD3D();
+ //clean up DXGI/D3D resources
+ void cleanupDX();
+
// call periodically to update available VRAM
void updateVRAMUsage();
@@ -990,43 +993,10 @@ void LLWindowWin32::close()
LL_DEBUGS("Window") << "Destroying Window" << LL_ENDL;
- mWindowThread->post([this, self = mWindowThread]()
- {
- if (IsWindow(self->mWindowHandleThrd))
- {
- if (self->mhDCThrd)
- {
- if (!ReleaseDC(self->mWindowHandleThrd, self->mhDCThrd))
- {
- LL_WARNS("Window") << "Release of ghDC failed!" << LL_ENDL;
- }
- }
-
- // Make sure we don't leave a blank toolbar button.
- ShowWindow(self->mWindowHandleThrd, SW_HIDE);
-
- // This causes WM_DESTROY to be sent *immediately*
- if (!destroy_window_handler(self->mWindowHandleThrd))
- {
- OSMessageBox(mCallbacks->translateString("MBDestroyWinFailed"),
- mCallbacks->translateString("MBShutdownErr"),
- OSMB_OK);
- }
- }
- else
- {
- // Something killed the window while we were busy destroying gl or handle somehow got broken
- LL_WARNS("Window") << "Failed to destroy Window, invalid handle!" << LL_ENDL;
- }
- self->mWindowHandleThrd = NULL;
- self->mhDCThrd = NULL;
- self->mGLReady = false;
- });
-
mhDC = NULL;
mWindowHandle = NULL;
- mWindowThread->wakeAndClose();
+ mWindowThread->wakeAndDestroy();
}
BOOL LLWindowWin32::isValid()
@@ -4771,6 +4741,28 @@ void LLWindowWin32::LLWindowWin32Thread::initD3D()
}
}
+void LLWindowWin32::LLWindowWin32Thread::cleanupDX()
+{
+ //clean up DXGI/D3D resources
+ if (mDXGIAdapter)
+ {
+ mDXGIAdapter->Release();
+ mDXGIAdapter = nullptr;
+ }
+
+ if (mD3DDevice)
+ {
+ mD3DDevice->Release();
+ mD3DDevice = nullptr;
+ }
+
+ if (mD3D)
+ {
+ mD3D->Release();
+ mD3D = nullptr;
+ }
+}
+
void LLWindowWin32::LLWindowWin32Thread::updateVRAMUsage()
{
LL_PROFILE_ZONE_SCOPED;
@@ -4918,58 +4910,109 @@ void LLWindowWin32::LLWindowWin32Thread::run()
#endif
}
- //clean up DXGI/D3D resources
- if (mDXGIAdapter)
+ cleanupDX();
+}
+
+void LLWindowWin32::LLWindowWin32Thread::wakeAndDestroy()
+{
+ if (mQueue->isClosed())
{
- mDXGIAdapter->Release();
- mDXGIAdapter = nullptr;
+ LL_WARNS() << "Tried to close Queue. Win32 thread Queue already closed." <<LL_ENDL;
}
- if (mD3DDevice)
+ // Make sure we don't leave a blank toolbar button.
+ // Also hiding window now prevents user from suspending it
+ // via some action (like dragging it around)
+ ShowWindow(mWindowHandleThrd, SW_HIDE);
+
+ // Schedule destruction
+ HWND old_handle = mWindowHandleThrd;
+ post([this]()
+ {
+ if (IsWindow(mWindowHandleThrd))
+ {
+ if (mhDCThrd)
+ {
+ if (!ReleaseDC(mWindowHandleThrd, mhDCThrd))
+ {
+ LL_WARNS("Window") << "Release of ghDC failed!" << LL_ENDL;
+ }
+ mhDCThrd = NULL;
+ }
+
+ // This causes WM_DESTROY to be sent *immediately*
+ if (!destroy_window_handler(mWindowHandleThrd))
+ {
+ LL_WARNS("Window") << "Failed to destroy Window! " << std::hex << GetLastError() << LL_ENDL;
+ }
+ }
+ else
+ {
+ // Something killed the window while we were busy destroying gl or handle somehow got broken
+ LL_WARNS("Window") << "Failed to destroy Window, invalid handle!" << LL_ENDL;
+ }
+ mWindowHandleThrd = NULL;
+ mhDCThrd = NULL;
+ mGLReady = false;
+ });
+
+ LL_DEBUGS("Window") << "Closing window's pool queue" << LL_ENDL;
+ mQueue->close();
+
+ // Post a nonsense user message to wake up the thread in
+ // case it is waiting for a getMessage()
+ if (old_handle)
{
- mD3DDevice->Release();
- mD3DDevice = nullptr;
+ WPARAM wparam{ 0xB0B0 };
+ LL_DEBUGS("Window") << "PostMessage(" << std::hex << old_handle
+ << ", " << WM_DUMMY_
+ << ", " << wparam << ")" << std::dec << LL_ENDL;
+ PostMessage(old_handle, WM_DUMMY_, wparam, 0x1337);
}
- if (mD3D)
+ // There are cases where window will refuse to close,
+ // can't wait forever on join, check state instead
+ LLTimer timeout;
+ timeout.setTimerExpirySec(2.0);
+ while (!getQueue().done() && !timeout.hasExpired() && mWindowHandleThrd)
{
- mD3D->Release();
- mD3D = nullptr;
+ ms_sleep(100);
}
-}
-
-void LLWindowWin32::LLWindowWin32Thread::wakeAndClose()
-{
- if (!mQueue->isClosed())
+ if (getQueue().done() || mWindowHandleThrd == NULL)
{
- LL_DEBUGS("Window") << "closing pool queue" << LL_ENDL;
- mQueue->close();
-
- // Post a nonsense user message to wake up the thred in
- // case it is waiting for a getMessage()
- //
- // Note that mWindowHandleThrd can change at any moment and isn't thread safe
- // but since we aren't writing it, should be safe to use even if value is obsolete
- // worst case dead handle gets reused and some new window ignores the message
- HWND old_handle = mWindowHandleThrd;
- if (old_handle)
+ // Window is closed, started closing or is cleaning up
+ // now wait for our single thread to die.
+ if (mWindowHandleThrd)
{
- WPARAM wparam{ 0xB0B0 };
- LL_DEBUGS("Window") << "PostMessage(" << std::hex << old_handle
- << ", " << WM_DUMMY_
- << ", " << wparam << ")" << std::dec << LL_ENDL;
- PostMessage(old_handle, WM_DUMMY_, wparam, 0x1337);
+ LL_INFOS("Window") << "Window is closing, waiting on pool's thread to join, time since post: " << timeout.getElapsedSeconds() << "s" << LL_ENDL;
+ }
+ else
+ {
+ LL_DEBUGS("Window") << "Waiting on pool's thread, time since post: " << timeout.getElapsedSeconds() << "s" << LL_ENDL;
}
-
- // now wait for our one thread to die.
for (auto& pair : mThreads)
{
- LL_DEBUGS("Window") << "waiting on pool's thread " << pair.first << LL_ENDL;
pair.second.join();
}
- LL_DEBUGS("Window") << "thread pool shutdown complete" << LL_ENDL;
}
+ else
+ {
+ // Something suspended window thread, can't afford to wait forever
+ // so kill thread instead
+ // Ex: This can happen if user starts dragging window arround (if it
+ // was visible) or a modal notification pops up
+ LL_WARNS("Window") << "Window is frozen, couldn't perform clean exit" << LL_ENDL;
+
+ for (auto& pair : mThreads)
+ {
+ // very unsafe
+ TerminateThread(pair.second.native_handle(), 0);
+ pair.second.detach();
+ cleanupDX();
+ }
+ }
+ LL_DEBUGS("Window") << "thread pool shutdown complete" << LL_ENDL;
}
void LLWindowWin32::post(const std::function<void()>& func)