Skip to content

Commit fe3be58

Browse files
committed
SL-18721 Shutdown fixes #6
1 parent 6d077c9 commit fe3be58

File tree

1 file changed

+113
-70
lines changed

1 file changed

+113
-70
lines changed

indra/llwindow/llwindowwin32.cpp

Lines changed: 113 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,7 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool
353353
void run() override;
354354

355355
// closes queue, wakes thread, waits until thread closes
356-
void wakeAndClose();
356+
void wakeAndDestroy();
357357

358358
void glReady()
359359
{
@@ -366,6 +366,9 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool
366366
// initialize D3D (if DXGI cannot be used)
367367
void initD3D();
368368

369+
//clean up DXGI/D3D resources
370+
void cleanupDX();
371+
369372
// call periodically to update available VRAM
370373
void updateVRAMUsage();
371374

@@ -990,43 +993,10 @@ void LLWindowWin32::close()
990993

991994
LL_DEBUGS("Window") << "Destroying Window" << LL_ENDL;
992995

993-
mWindowThread->post([this, self = mWindowThread]()
994-
{
995-
if (IsWindow(self->mWindowHandleThrd))
996-
{
997-
if (self->mhDCThrd)
998-
{
999-
if (!ReleaseDC(self->mWindowHandleThrd, self->mhDCThrd))
1000-
{
1001-
LL_WARNS("Window") << "Release of ghDC failed!" << LL_ENDL;
1002-
}
1003-
}
1004-
1005-
// Make sure we don't leave a blank toolbar button.
1006-
ShowWindow(self->mWindowHandleThrd, SW_HIDE);
1007-
1008-
// This causes WM_DESTROY to be sent *immediately*
1009-
if (!destroy_window_handler(self->mWindowHandleThrd))
1010-
{
1011-
OSMessageBox(mCallbacks->translateString("MBDestroyWinFailed"),
1012-
mCallbacks->translateString("MBShutdownErr"),
1013-
OSMB_OK);
1014-
}
1015-
}
1016-
else
1017-
{
1018-
// Something killed the window while we were busy destroying gl or handle somehow got broken
1019-
LL_WARNS("Window") << "Failed to destroy Window, invalid handle!" << LL_ENDL;
1020-
}
1021-
self->mWindowHandleThrd = NULL;
1022-
self->mhDCThrd = NULL;
1023-
self->mGLReady = false;
1024-
});
1025-
1026996
mhDC = NULL;
1027997
mWindowHandle = NULL;
1028998

1029-
mWindowThread->wakeAndClose();
999+
mWindowThread->wakeAndDestroy();
10301000
}
10311001

10321002
BOOL LLWindowWin32::isValid()
@@ -4771,6 +4741,28 @@ void LLWindowWin32::LLWindowWin32Thread::initD3D()
47714741
}
47724742
}
47734743

4744+
void LLWindowWin32::LLWindowWin32Thread::cleanupDX()
4745+
{
4746+
//clean up DXGI/D3D resources
4747+
if (mDXGIAdapter)
4748+
{
4749+
mDXGIAdapter->Release();
4750+
mDXGIAdapter = nullptr;
4751+
}
4752+
4753+
if (mD3DDevice)
4754+
{
4755+
mD3DDevice->Release();
4756+
mD3DDevice = nullptr;
4757+
}
4758+
4759+
if (mD3D)
4760+
{
4761+
mD3D->Release();
4762+
mD3D = nullptr;
4763+
}
4764+
}
4765+
47744766
void LLWindowWin32::LLWindowWin32Thread::updateVRAMUsage()
47754767
{
47764768
LL_PROFILE_ZONE_SCOPED;
@@ -4918,58 +4910,109 @@ void LLWindowWin32::LLWindowWin32Thread::run()
49184910
#endif
49194911
}
49204912

4921-
//clean up DXGI/D3D resources
4922-
if (mDXGIAdapter)
4913+
cleanupDX();
4914+
}
4915+
4916+
void LLWindowWin32::LLWindowWin32Thread::wakeAndDestroy()
4917+
{
4918+
if (mQueue->isClosed())
49234919
{
4924-
mDXGIAdapter->Release();
4925-
mDXGIAdapter = nullptr;
4920+
LL_WARNS() << "Tried to close Queue. Win32 thread Queue already closed." <<LL_ENDL;
49264921
}
49274922

4928-
if (mD3DDevice)
4923+
// Make sure we don't leave a blank toolbar button.
4924+
// Also hiding window now prevents user from suspending it
4925+
// via some action (like dragging it around)
4926+
ShowWindow(mWindowHandleThrd, SW_HIDE);
4927+
4928+
// Schedule destruction
4929+
HWND old_handle = mWindowHandleThrd;
4930+
post([this]()
4931+
{
4932+
if (IsWindow(mWindowHandleThrd))
4933+
{
4934+
if (mhDCThrd)
4935+
{
4936+
if (!ReleaseDC(mWindowHandleThrd, mhDCThrd))
4937+
{
4938+
LL_WARNS("Window") << "Release of ghDC failed!" << LL_ENDL;
4939+
}
4940+
mhDCThrd = NULL;
4941+
}
4942+
4943+
// This causes WM_DESTROY to be sent *immediately*
4944+
if (!destroy_window_handler(mWindowHandleThrd))
4945+
{
4946+
LL_WARNS("Window") << "Failed to destroy Window! " << std::hex << GetLastError() << LL_ENDL;
4947+
}
4948+
}
4949+
else
4950+
{
4951+
// Something killed the window while we were busy destroying gl or handle somehow got broken
4952+
LL_WARNS("Window") << "Failed to destroy Window, invalid handle!" << LL_ENDL;
4953+
}
4954+
mWindowHandleThrd = NULL;
4955+
mhDCThrd = NULL;
4956+
mGLReady = false;
4957+
});
4958+
4959+
LL_DEBUGS("Window") << "Closing window's pool queue" << LL_ENDL;
4960+
mQueue->close();
4961+
4962+
// Post a nonsense user message to wake up the thread in
4963+
// case it is waiting for a getMessage()
4964+
if (old_handle)
49294965
{
4930-
mD3DDevice->Release();
4931-
mD3DDevice = nullptr;
4966+
WPARAM wparam{ 0xB0B0 };
4967+
LL_DEBUGS("Window") << "PostMessage(" << std::hex << old_handle
4968+
<< ", " << WM_DUMMY_
4969+
<< ", " << wparam << ")" << std::dec << LL_ENDL;
4970+
PostMessage(old_handle, WM_DUMMY_, wparam, 0x1337);
49324971
}
49334972

4934-
if (mD3D)
4973+
// There are cases where window will refuse to close,
4974+
// can't wait forever on join, check state instead
4975+
LLTimer timeout;
4976+
timeout.setTimerExpirySec(2.0);
4977+
while (!getQueue().done() && !timeout.hasExpired() && mWindowHandleThrd)
49354978
{
4936-
mD3D->Release();
4937-
mD3D = nullptr;
4979+
ms_sleep(100);
49384980
}
49394981

4940-
}
4941-
4942-
void LLWindowWin32::LLWindowWin32Thread::wakeAndClose()
4943-
{
4944-
if (!mQueue->isClosed())
4982+
if (getQueue().done() || mWindowHandleThrd == NULL)
49454983
{
4946-
LL_DEBUGS("Window") << "closing pool queue" << LL_ENDL;
4947-
mQueue->close();
4948-
4949-
// Post a nonsense user message to wake up the thred in
4950-
// case it is waiting for a getMessage()
4951-
//
4952-
// Note that mWindowHandleThrd can change at any moment and isn't thread safe
4953-
// but since we aren't writing it, should be safe to use even if value is obsolete
4954-
// worst case dead handle gets reused and some new window ignores the message
4955-
HWND old_handle = mWindowHandleThrd;
4956-
if (old_handle)
4984+
// Window is closed, started closing or is cleaning up
4985+
// now wait for our single thread to die.
4986+
if (mWindowHandleThrd)
49574987
{
4958-
WPARAM wparam{ 0xB0B0 };
4959-
LL_DEBUGS("Window") << "PostMessage(" << std::hex << old_handle
4960-
<< ", " << WM_DUMMY_
4961-
<< ", " << wparam << ")" << std::dec << LL_ENDL;
4962-
PostMessage(old_handle, WM_DUMMY_, wparam, 0x1337);
4988+
LL_INFOS("Window") << "Window is closing, waiting on pool's thread to join, time since post: " << timeout.getElapsedSeconds() << "s" << LL_ENDL;
4989+
}
4990+
else
4991+
{
4992+
LL_DEBUGS("Window") << "Waiting on pool's thread, time since post: " << timeout.getElapsedSeconds() << "s" << LL_ENDL;
49634993
}
4964-
4965-
// now wait for our one thread to die.
49664994
for (auto& pair : mThreads)
49674995
{
4968-
LL_DEBUGS("Window") << "waiting on pool's thread " << pair.first << LL_ENDL;
49694996
pair.second.join();
49704997
}
4971-
LL_DEBUGS("Window") << "thread pool shutdown complete" << LL_ENDL;
49724998
}
4999+
else
5000+
{
5001+
// Something suspended window thread, can't afford to wait forever
5002+
// so kill thread instead
5003+
// Ex: This can happen if user starts dragging window arround (if it
5004+
// was visible) or a modal notification pops up
5005+
LL_WARNS("Window") << "Window is frozen, couldn't perform clean exit" << LL_ENDL;
5006+
5007+
for (auto& pair : mThreads)
5008+
{
5009+
// very unsafe
5010+
TerminateThread(pair.second.native_handle(), 0);
5011+
pair.second.detach();
5012+
cleanupDX();
5013+
}
5014+
}
5015+
LL_DEBUGS("Window") << "thread pool shutdown complete" << LL_ENDL;
49735016
}
49745017

49755018
void LLWindowWin32::post(const std::function<void()>& func)

0 commit comments

Comments
 (0)