diff options
author | Andrey Kleshchev <andreykproductengine@lindenlab.com> | 2024-01-20 02:26:51 +0200 |
---|---|---|
committer | Andrey Kleshchev <117672381+akleshchev@users.noreply.github.com> | 2024-01-22 18:47:43 +0200 |
commit | 4a34a1196627c7e9998edde725d5e839f3ef61b9 (patch) | |
tree | cbca0677ac1d4bb27e6d608f09fde45396a1d4cc | |
parent | fee2dc981cb15c54cacd63f778f106ff93a85796 (diff) |
SL-18721 Shutdown fixes
1. After window closes viewer still takes some time to shut down, so
added splash screen to not confuse users (and to see if something gets
stuck)
2. Having two identical mWindowHandle caused confusion for me, so I
split them. It looks like there might have been issues with thread being
stuck because thread's handle wasn't cleaned up.
3. Made region clean mCacheMap immediately instead of spending time
making copies on shutdown
-rw-r--r-- | indra/llcommon/threadpool.cpp | 17 | ||||
-rw-r--r-- | indra/llcommon/threadpool.h | 10 | ||||
-rw-r--r-- | indra/llwindow/llwindowwin32.cpp | 61 | ||||
-rw-r--r-- | indra/newview/llappviewer.cpp | 8 | ||||
-rwxr-xr-x | indra/newview/llviewerregion.cpp | 15 |
5 files changed, 71 insertions, 40 deletions
diff --git a/indra/llcommon/threadpool.cpp b/indra/llcommon/threadpool.cpp index 3a9a5a2062..a063a01b82 100644 --- a/indra/llcommon/threadpool.cpp +++ b/indra/llcommon/threadpool.cpp @@ -60,12 +60,15 @@ struct sleepy_robin: public boost::fibers::algo::round_robin /***************************************************************************** * ThreadPoolBase *****************************************************************************/ -LL::ThreadPoolBase::ThreadPoolBase(const std::string& name, size_t threads, - WorkQueueBase* queue): +LL::ThreadPoolBase::ThreadPoolBase(const std::string& name, + size_t threads, + WorkQueueBase* queue, + bool auto_shutdown): super(name), mName("ThreadPool:" + name), mThreadCount(getConfiguredWidth(name, threads)), - mQueue(queue) + mQueue(queue), + mAutomaticShutdown(auto_shutdown) {} void LL::ThreadPoolBase::start() @@ -79,6 +82,14 @@ void LL::ThreadPoolBase::start() run(tname); }); } + + if (!mAutomaticShutdown) + { + // Some threads, like main window's might need to run a bit longer + // to wait for a proper shutdown message + return; + } + // Listen on "LLApp", and when the app is shutting down, close the queue // and join the workers. LLEventPumps::instance().obtain("LLApp").listen( diff --git a/indra/llcommon/threadpool.h b/indra/llcommon/threadpool.h index 60f4a0ce1b..fa16c6fe71 100644 --- a/indra/llcommon/threadpool.h +++ b/indra/llcommon/threadpool.h @@ -40,7 +40,7 @@ namespace LL * overrides this parameter. */ ThreadPoolBase(const std::string& name, size_t threads, - WorkQueueBase* queue); + WorkQueueBase* queue, bool auto_shutdown = true); virtual ~ThreadPoolBase(); /** @@ -87,6 +87,7 @@ namespace LL protected: std::unique_ptr<WorkQueueBase> mQueue; + bool mAutomaticShutdown; private: void run(const std::string& name); @@ -117,8 +118,11 @@ namespace LL * Constraining the queue can cause a submitter to block. Do not * constrain any ThreadPool accepting work from the main thread. */ - ThreadPoolUsing(const std::string& name, size_t threads=1, size_t capacity=1024*1024): - ThreadPoolBase(name, threads, new queue_t(name, capacity)) + ThreadPoolUsing(const std::string& name, + size_t threads=1, + size_t capacity=1024*1024, + bool auto_shutdown = true): + ThreadPoolBase(name, threads, new queue_t(name, capacity), auto_shutdown) {} ~ThreadPoolUsing() override {} diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 057d7a700e..0c1ed85477 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -412,8 +412,8 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool using FuncType = std::function<void()>; // call GetMessage() and pull enqueue messages for later processing void gatherInput(); - HWND mWindowHandle = NULL; - HDC mhDC = 0; + HWND mWindowHandleThrd = NULL; + HDC mhDCThrd = 0; // *HACK: Attempt to prevent startup crashes by deferring memory accounting // until after some graphics setup. See SL-20177. -Cosmic,2023-09-18 @@ -987,23 +987,23 @@ void LLWindowWin32::close() LL_DEBUGS("Window") << "Destroying Window" << LL_ENDL; - mWindowThread->post([=]() + mWindowThread->post([this, self = mWindowThread]() { - if (IsWindow(mWindowHandle)) + if (IsWindow(self->mWindowHandleThrd)) { - if (mhDC) + if (self->mhDCThrd) { - if (!ReleaseDC(mWindowHandle, mhDC)) + 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(mWindowHandle, SW_HIDE); + ShowWindow(self->mWindowHandleThrd, SW_HIDE); // This causes WM_DESTROY to be sent *immediately* - if (!destroy_window_handler(mWindowHandle)) + if (!destroy_window_handler(self->mWindowHandleThrd)) { OSMessageBox(mCallbacks->translateString("MBDestroyWinFailed"), mCallbacks->translateString("MBShutdownErr"), @@ -1015,17 +1015,18 @@ void LLWindowWin32::close() // 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; }); - // Window thread might be waiting for a getMessage(), give it - // a push to enshure it will process destroy_window_handler - kickWindowThread(); - // Even though the above lambda might not yet have run, we've already - // bound mWindowHandle into it by value, which should suffice for the - // operations we're asking. That's the last time WE should touch it. mhDC = NULL; mWindowHandle = NULL; + + // Window thread might be waiting for a getMessage(), give it + // a push to enshure it will process destroy_window_handler + kickWindowThread(); + mWindowThread->close(); } @@ -1777,8 +1778,8 @@ void LLWindowWin32::recreateWindow(RECT window_rect, DWORD dw_ex_style, DWORD dw () { LL_DEBUGS("Window") << "recreateWindow(): window_work entry" << LL_ENDL; - self->mWindowHandle = 0; - self->mhDC = 0; + self->mWindowHandleThrd = 0; + self->mhDCThrd = 0; if (oldWindowHandle) { @@ -1813,20 +1814,20 @@ void LLWindowWin32::recreateWindow(RECT window_rect, DWORD dw_ex_style, DWORD dw { // Failed to create window: clear the variables. This // assignment is valid because we're running on mWindowThread. - self->mWindowHandle = NULL; - self->mhDC = 0; + self->mWindowHandleThrd = NULL; + self->mhDCThrd = 0; } else { // Update mWindowThread's own mWindowHandle and mhDC. - self->mWindowHandle = handle; - self->mhDC = GetDC(handle); + self->mWindowHandleThrd = handle; + self->mhDCThrd = GetDC(handle); } updateWindowRect(); // It's important to wake up the future either way. - promise.set_value(std::make_pair(self->mWindowHandle, self->mhDC)); + promise.set_value(std::make_pair(self->mWindowHandleThrd, self->mhDCThrd)); LL_DEBUGS("Window") << "recreateWindow(): window_work done" << LL_ENDL; }; // But how we pass window_work to the window thread depends on whether we @@ -4589,7 +4590,7 @@ U32 LLWindowWin32::getAvailableVRAMMegabytes() #endif // LL_WINDOWS inline LLWindowWin32::LLWindowWin32Thread::LLWindowWin32Thread() - : LL::ThreadPool("Window Thread", 1, MAX_QUEUE_SIZE) + : LL::ThreadPool("Window Thread", 1, MAX_QUEUE_SIZE, false) { LL::ThreadPool::start(); } @@ -4745,7 +4746,7 @@ void LLWindowWin32::LLWindowWin32Thread::initD3D() { if (!mGLReady) { return; } - if (mDXGIAdapter == NULL && mD3DDevice == NULL && mWindowHandle != 0) + if (mDXGIAdapter == NULL && mD3DDevice == NULL && mWindowHandleThrd != 0) { mD3D = Direct3DCreate9(D3D_SDK_VERSION); @@ -4755,7 +4756,7 @@ void LLWindowWin32::LLWindowWin32Thread::initD3D() d3dpp.Windowed = TRUE; d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; - HRESULT res = mD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, mWindowHandle, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &mD3DDevice); + HRESULT res = mD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, mWindowHandleThrd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &mD3DDevice); if (FAILED(res)) { @@ -4861,7 +4862,7 @@ void LLWindowWin32::LLWindowWin32Thread::run() // lazily call initD3D inside this loop to catch when mGLReady has been set to true initDX(); - if (mWindowHandle != 0) + if (mWindowHandleThrd != 0) { // lazily call initD3D inside this loop to catch when mWindowHandle has been set, and mGLReady has been set to true // *TODO: Shutdown if this fails when mWindowHandle exists @@ -4869,16 +4870,16 @@ void LLWindowWin32::LLWindowWin32Thread::run() MSG msg; BOOL status; - if (mhDC == 0) + if (mhDCThrd == 0) { LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("w32t - PeekMessage"); - logger.onChange("PeekMessage(", std::hex, mWindowHandle, ")"); - status = PeekMessage(&msg, mWindowHandle, 0, 0, PM_REMOVE); + logger.onChange("PeekMessage(", std::hex, mWindowHandleThrd, ")"); + status = PeekMessage(&msg, mWindowHandleThrd, 0, 0, PM_REMOVE); } else { LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("w32t - GetMessage"); - logger.always("GetMessage(", std::hex, mWindowHandle, ")"); + logger.always("GetMessage(", std::hex, mWindowHandleThrd, ")"); status = GetMessage(&msg, NULL, 0, 0); } if (status > 0) diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 30fb0be46c..f094170ff5 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -1892,6 +1892,9 @@ bool LLAppViewer::cleanup() LL_INFOS() << "ViewerWindow deleted" << LL_ENDL; } + LLSplashScreen::show(); + LLSplashScreen::update(LLTrans::getString("ShuttingDown")); + LL_INFOS() << "Cleaning up Keyboard & Joystick" << LL_ENDL; // viewer UI relies on keyboard so keep it aound until viewer UI isa gone @@ -2170,6 +2173,8 @@ bool LLAppViewer::cleanup() // deleteSingleton() methods. LLSingletonBase::deleteAll(); + LLSplashScreen::hide(); + LL_INFOS() << "Goodbye!" << LL_ENDL; removeDumpDir(); @@ -5059,6 +5064,9 @@ void LLAppViewer::idleShutdown() && gLogoutTimer.getElapsedTimeF32() < SHUTDOWN_UPLOAD_SAVE_TIME && !logoutRequestSent()) { + gViewerWindow->setShowProgress(TRUE); + gViewerWindow->setProgressPercent(100.f); + gViewerWindow->setProgressString(LLTrans::getString("LoggingOut")); return; } diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index 6c0e25ae39..ed5b809003 100755 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -829,10 +829,17 @@ void LLViewerRegion::saveObjectCache() mCacheDirty = FALSE; } - // Map of LLVOCacheEntry takes time to release, store map for cleanup on idle - sRegionCacheCleanup.insert(mImpl->mCacheMap.begin(), mImpl->mCacheMap.end()); - mImpl->mCacheMap.clear(); - // TODO - probably need to do the same for overrides cache + if (LLAppViewer::instance()->isQuitting()) + { + mImpl->mCacheMap.clear(); + } + else + { + // Map of LLVOCacheEntry takes time to release, store map for cleanup on idle + sRegionCacheCleanup.insert(mImpl->mCacheMap.begin(), mImpl->mCacheMap.end()); + mImpl->mCacheMap.clear(); + // TODO - probably need to do the same for overrides cache + } } void LLViewerRegion::sendMessage() |