From 2e5b105dffc41695d0a64c5b55eef7c28da49246 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 7 Feb 2024 22:50:28 +0200 Subject: [PATCH 01/17] SL-18721 Shutdown fixes #4 --- indra/llcommon/threadpool.h | 2 +- indra/llwindow/llwindowwin32.cpp | 42 ++++++++++++++++++++++++++++---- 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/indra/llcommon/threadpool.h b/indra/llcommon/threadpool.h index fa16c6fe71..b8be7bb81a 100644 --- a/indra/llcommon/threadpool.h +++ b/indra/llcommon/threadpool.h @@ -87,6 +87,7 @@ namespace LL protected: std::unique_ptr mQueue; + std::vector> mThreads; bool mAutomaticShutdown; private: @@ -94,7 +95,6 @@ namespace LL std::string mName; size_t mThreadCount; - std::vector> mThreads; }; /** diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 4b72ade469..8cc8f9c408 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -352,6 +352,9 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool void run() override; + // closes queue, wakes thread, waits until thread closes + void wakeAndClose(); + void glReady() { mGLReady = true; @@ -1022,12 +1025,8 @@ void LLWindowWin32::close() 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(); + mWindowThread->wakeAndClose(); } BOOL LLWindowWin32::isValid() @@ -4940,6 +4939,39 @@ void LLWindowWin32::LLWindowWin32Thread::run() } +void LLWindowWin32::LLWindowWin32Thread::wakeAndClose() +{ + if (!mQueue->isClosed()) + { + 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) + { + 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); + } + + // 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; + } +} + void LLWindowWin32::post(const std::function& func) { mFunctionQueue.pushFront(func); From a2552a555669490dc2ca173a48989d1b30e62c56 Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Thu, 8 Feb 2024 21:03:59 +0100 Subject: [PATCH 02/17] Build fix for Visual Studio patch --- indra/llcommon/llbase64.cpp | 4 ++-- indra/llcommon/llrand.cpp | 2 +- indra/llcommon/llsd.h | 4 ++-- indra/llcommon/llsdserialize.cpp | 2 +- indra/llcommon/llsdserialize_xml.cpp | 4 ++-- indra/llcommon/llsys.cpp | 2 +- indra/llcommon/lltrace.cpp | 2 +- indra/llcommon/lltraceaccumulators.cpp | 2 +- indra/llcorehttp/bufferarray.cpp | 2 +- indra/newview/llmaterialeditor.cpp | 8 ++++---- 10 files changed, 16 insertions(+), 16 deletions(-) diff --git a/indra/llcommon/llbase64.cpp b/indra/llcommon/llbase64.cpp index bb85fe32a3..433b54f6f8 100644 --- a/indra/llcommon/llbase64.cpp +++ b/indra/llcommon/llbase64.cpp @@ -42,7 +42,7 @@ std::string LLBase64::encode(const U8* input, size_t input_size) && input_size > 0) { // Yes, it returns int. - int b64_buffer_length = apr_base64_encode_len(narrow(input_size)); + int b64_buffer_length = apr_base64_encode_len(narrow(input_size)); char* b64_buffer = new char[b64_buffer_length]; // This is faster than apr_base64_encode() if you know @@ -52,7 +52,7 @@ std::string LLBase64::encode(const U8* input, size_t input_size) b64_buffer_length = apr_base64_encode_binary( b64_buffer, input, - narrow(input_size)); + narrow(input_size)); output.assign(b64_buffer); delete[] b64_buffer; } diff --git a/indra/llcommon/llrand.cpp b/indra/llcommon/llrand.cpp index e4065e23bf..0192111574 100644 --- a/indra/llcommon/llrand.cpp +++ b/indra/llcommon/llrand.cpp @@ -85,7 +85,7 @@ inline F32 ll_internal_random() // Per Monty, it's important to clamp using the correct fmodf() rather // than expanding to F64 for fmod() and then truncating back to F32. Prior // to this change, we were getting sporadic ll_frand() == 1.0 results. - F32 rv{ narrow(gRandomGenerator()) }; + F32 rv{ narrow(gRandomGenerator()) }; if(!((rv >= 0.0f) && (rv < 1.0f))) return fmodf(rv, 1.0f); return rv; } diff --git a/indra/llcommon/llsd.h b/indra/llcommon/llsd.h index cdb9a7ed8a..8ed254919c 100644 --- a/indra/llcommon/llsd.h +++ b/indra/llcommon/llsd.h @@ -197,12 +197,12 @@ public: typename std::enable_if::value && ! std::is_same::value, bool>::type = true> - LLSD(VALUE v): LLSD(Integer(narrow(v))) {} + LLSD(VALUE v): LLSD(Integer(narrow(v))) {} // support construction from F32 et al. template ::value, bool>::type = true> - LLSD(VALUE v): LLSD(Real(narrow(v))) {} + LLSD(VALUE v): LLSD(Real(narrow(v))) {} //@} /** @name Scalar Assignment */ diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp index a475be6293..76171f2dfd 100644 --- a/indra/llcommon/llsdserialize.cpp +++ b/indra/llcommon/llsdserialize.cpp @@ -2174,7 +2174,7 @@ std::string zip_llsd(LLSD& data) U8 out[CHUNK]; - strm.avail_in = narrow(source.size()); + strm.avail_in = narrow(source.size()); strm.next_in = (U8*) source.data(); U8* output = NULL; diff --git a/indra/llcommon/llsdserialize_xml.cpp b/indra/llcommon/llsdserialize_xml.cpp index 38b11eb32b..1511983596 100644 --- a/indra/llcommon/llsdserialize_xml.cpp +++ b/indra/llcommon/llsdserialize_xml.cpp @@ -196,12 +196,12 @@ S32 LLSDXMLFormatter::format_impl(const LLSD& data, std::ostream& ostr, // *FIX: memory inefficient. // *TODO: convert to use LLBase64 ostr << pre << ""; - int b64_buffer_length = apr_base64_encode_len(narrow(buffer.size())); + int b64_buffer_length = apr_base64_encode_len(narrow(buffer.size())); char* b64_buffer = new char[b64_buffer_length]; b64_buffer_length = apr_base64_encode_binary( b64_buffer, &buffer[0], - narrow(buffer.size())); + narrow(buffer.size())); ostr.write(b64_buffer, b64_buffer_length - 1); delete[] b64_buffer; ostr << "" << post; diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp index 938685bae6..2bf12fb0eb 100644 --- a/indra/llcommon/llsys.cpp +++ b/indra/llcommon/llsys.cpp @@ -917,7 +917,7 @@ void LLMemoryInfo::stream(std::ostream& s) const // Now stream stats BOOST_FOREACH(const MapEntry& pair, inMap(mStatsMap)) { - s << pfx << std::setw(narrow(key_width+1)) << (pair.first + ':') << ' '; + s << pfx << std::setw(narrow(key_width+1)) << (pair.first + ':') << ' '; LLSD value(pair.second); if (value.isInteger()) s << std::setw(12) << value.asInteger(); diff --git a/indra/llcommon/lltrace.cpp b/indra/llcommon/lltrace.cpp index bce186054f..87457ad907 100644 --- a/indra/llcommon/lltrace.cpp +++ b/indra/llcommon/lltrace.cpp @@ -63,7 +63,7 @@ void TimeBlockTreeNode::setParent( BlockTimerStatHandle* parent ) llassert_always(parent != mBlock); llassert_always(parent != NULL); - TimeBlockTreeNode* parent_tree_node = get_thread_recorder()->getTimeBlockTreeNode(narrow(parent->getIndex())); + TimeBlockTreeNode* parent_tree_node = get_thread_recorder()->getTimeBlockTreeNode(narrow(parent->getIndex())); if (!parent_tree_node) return; if (mParent) diff --git a/indra/llcommon/lltraceaccumulators.cpp b/indra/llcommon/lltraceaccumulators.cpp index 5fafb53832..b5b32cba38 100644 --- a/indra/llcommon/lltraceaccumulators.cpp +++ b/indra/llcommon/lltraceaccumulators.cpp @@ -77,7 +77,7 @@ void AccumulatorBufferGroup::makeCurrent() // update stacktimer parent pointers for (size_t i = 0, end_i = mStackTimers.size(); i < end_i; i++) { - TimeBlockTreeNode* tree_node = thread_recorder->getTimeBlockTreeNode(narrow(i)); + TimeBlockTreeNode* tree_node = thread_recorder->getTimeBlockTreeNode(narrow(i)); if (tree_node) { timer_accumulator_buffer[i].mParent = tree_node->mParent; diff --git a/indra/llcorehttp/bufferarray.cpp b/indra/llcorehttp/bufferarray.cpp index 8d2e7c6a63..c780c06b4e 100644 --- a/indra/llcorehttp/bufferarray.cpp +++ b/indra/llcorehttp/bufferarray.cpp @@ -288,7 +288,7 @@ int BufferArray::findBlock(size_t pos, size_t * ret_offset) if (pos >= mLen) return -1; // Doesn't exist - const int block_limit(narrow(mBlocks.size())); + const int block_limit(narrow(mBlocks.size())); for (int i(0); i < block_limit; ++i) { if (pos < mBlocks[i]->mUsed) diff --git a/indra/newview/llmaterialeditor.cpp b/indra/newview/llmaterialeditor.cpp index 292ddb765f..1f5974c74d 100644 --- a/indra/newview/llmaterialeditor.cpp +++ b/indra/newview/llmaterialeditor.cpp @@ -2228,7 +2228,7 @@ bool LLMaterialEditor::canModifyObjectsMaterial() LLSelectedTEGetMatData func(true); LLPermissions permissions; LLViewerInventoryItem* item_out; - return can_use_objects_material(func, std::vector({PERM_MODIFY}), ItemSource::OBJECT, permissions, item_out); + return can_use_objects_material(func, std::vector({PERM_MODIFY}), ItemSource::OBJECT, permissions, item_out); } bool LLMaterialEditor::canSaveObjectsMaterial() @@ -2236,7 +2236,7 @@ bool LLMaterialEditor::canSaveObjectsMaterial() LLSelectedTEGetMatData func(true); LLPermissions permissions; LLViewerInventoryItem* item_out; - return can_use_objects_material(func, std::vector({PERM_COPY, PERM_MODIFY}), ItemSource::AGENT, permissions, item_out); + return can_use_objects_material(func, std::vector({PERM_COPY, PERM_MODIFY}), ItemSource::AGENT, permissions, item_out); } bool LLMaterialEditor::canClipboardObjectsMaterial() @@ -2262,7 +2262,7 @@ bool LLMaterialEditor::canClipboardObjectsMaterial() LLSelectedTEGetMatData func(true); LLPermissions permissions; LLViewerInventoryItem* item_out; - return can_use_objects_material(func, std::vector({PERM_COPY, PERM_MODIFY, PERM_TRANSFER}), ItemSource::OBJECT, permissions, item_out); + return can_use_objects_material(func, std::vector({PERM_COPY, PERM_MODIFY, PERM_TRANSFER}), ItemSource::OBJECT, permissions, item_out); } void LLMaterialEditor::saveObjectsMaterialAs() @@ -2270,7 +2270,7 @@ void LLMaterialEditor::saveObjectsMaterialAs() LLSelectedTEGetMatData func(true); LLPermissions permissions; LLViewerInventoryItem* item = nullptr; - bool allowed = can_use_objects_material(func, std::vector({PERM_COPY, PERM_MODIFY}), ItemSource::AGENT, permissions, item); + bool allowed = can_use_objects_material(func, std::vector({PERM_COPY, PERM_MODIFY}), ItemSource::AGENT, permissions, item); if (!allowed) { LL_WARNS("MaterialEditor") << "Failed to save GLTF material from object" << LL_ENDL; From 5bd9c86314bf8ae57899654320fe212416435bc8 Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Thu, 8 Feb 2024 21:24:22 +0100 Subject: [PATCH 03/17] #746 BugSplat Crash: LLAccordionCtrlTab::showAndFocusHeader(873) --- indra/newview/lloutfitgallery.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/indra/newview/lloutfitgallery.cpp b/indra/newview/lloutfitgallery.cpp index e621c32911..65ec38a41d 100644 --- a/indra/newview/lloutfitgallery.cpp +++ b/indra/newview/lloutfitgallery.cpp @@ -1094,8 +1094,11 @@ bool LLOutfitGalleryItem::openOutfitsContent() { outfit_list->setSelectedOutfitByUUID(mUUID); LLAccordionCtrlTab* tab = accordion->getSelectedTab(); - tab->showAndFocusHeader(); - return true; + if (tab) + { + tab->showAndFocusHeader(); + return true; + } } } } From ff543b744ee0b0fd4dd90b46419ae50a570572ab Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 15 Feb 2024 11:21:31 -0500 Subject: [PATCH 04/17] Engage new viewer-build-util/which-branch with relnotes output. Put whatever release notes we retrieve into the generated release page. --- .github/workflows/build.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 19a6a0ef6f..73df01b8cf 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -25,6 +25,7 @@ jobs: viewer_channel: ${{ steps.build.outputs.viewer_channel }} viewer_version: ${{ steps.build.outputs.viewer_version }} viewer_branch: ${{ steps.which-branch.outputs.branch }} + relnotes: ${{ steps.which-branch.outputs.relnotes }} imagename: ${{ steps.build.outputs.imagename }} env: AUTOBUILD_ADDRSIZE: 64 @@ -102,7 +103,7 @@ jobs: - name: Determine source branch id: which-branch - uses: secondlife/viewer-build-util/which-branch@v1 + uses: secondlife/viewer-build-util/which-branch@relnotes with: token: ${{ github.token }} @@ -377,6 +378,7 @@ jobs: ${{ needs.build.outputs.viewer_channel }} ${{ needs.build.outputs.viewer_version }} ${{ needs.build.outputs.viewer_branch }} + ${{ needs.build.outputs.relnotes }} prerelease: true generate_release_notes: true append_body: true From 5e697cc04c0dd876e2484dbe49e32ddd7a711b3d Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 21 Feb 2024 00:31:08 +0200 Subject: [PATCH 05/17] SL-20469 Crash at dead mRootVolp in getAttachedAvatar() --- indra/newview/llcontrolavatar.cpp | 6 ++++-- indra/newview/llviewerobject.cpp | 6 ++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/indra/newview/llcontrolavatar.cpp b/indra/newview/llcontrolavatar.cpp index 50b9af668b..d764f64c79 100644 --- a/indra/newview/llcontrolavatar.cpp +++ b/indra/newview/llcontrolavatar.cpp @@ -99,7 +99,6 @@ LLVOAvatar *LLControlAvatar::getAttachedAvatar() void LLControlAvatar::getNewConstraintFixups(LLVector3& new_pos_fixup, F32& new_scale_fixup) const { - F32 max_legal_offset = MAX_LEGAL_OFFSET; if (gSavedSettings.getControl("AnimatedObjectsMaxLegalOffset")) { @@ -362,6 +361,9 @@ LLControlAvatar *LLControlAvatar::createControlAvatar(LLVOVolume *obj) void LLControlAvatar::markForDeath() { mMarkedForDeath = true; + // object unlinked cav and might be dead already + // might need to clean mControlAVBridge here as well + mRootVolp = NULL; } void LLControlAvatar::idleUpdate(LLAgent &agent, const F64 &time) @@ -440,7 +442,7 @@ void LLControlAvatar::updateDebugText() F32 streaming_cost = 0.f; std::string cam_dist_string = ""; S32 cam_dist_count = 0; - F32 lod_radius = mRootVolp->mLODRadius; + F32 lod_radius = mRootVolp ? mRootVolp->mLODRadius : 0.f; for (std::vector::iterator it = volumes.begin(); it != volumes.end(); ++it) diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index d46339e2fd..fc055a7303 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -392,6 +392,12 @@ LLViewerObject::~LLViewerObject() sNumZombieObjects--; llassert(mChildList.size() == 0); llassert(mControlAvatar.isNull()); // Should have been cleaned by now + if (mControlAvatar.notNull()) + { + mControlAvatar->markForDeath(); + mControlAvatar = NULL; + LL_WARNS() << "Dead object owned a live control avatar" << LL_ENDL; + } clearInventoryListeners(); } From da0f5ea0b4366ccc2b065103a7bc37552b1fe8de Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 22 Feb 2024 01:09:23 +0200 Subject: [PATCH 06/17] Viewer#863 Crash reading xml --- indra/llcommon/llsdserialize_xml.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/indra/llcommon/llsdserialize_xml.cpp b/indra/llcommon/llsdserialize_xml.cpp index 1511983596..db61f4ae41 100644 --- a/indra/llcommon/llsdserialize_xml.cpp +++ b/indra/llcommon/llsdserialize_xml.cpp @@ -404,11 +404,18 @@ S32 LLSDXMLParser::Impl::parse(std::istream& input, LLSD& data) if (buffer) { ((char*) buffer)[count ? count - 1 : 0] = '\0'; + if (mEmitErrors) + { + LL_INFOS() << "LLSDXMLParser::Impl::parse: XML_STATUS_ERROR parsing:" << (char*)buffer << LL_ENDL; + } } - if (mEmitErrors) - { - LL_INFOS() << "LLSDXMLParser::Impl::parse: XML_STATUS_ERROR parsing:" << (char*) buffer << LL_ENDL; - } + else + { + if (mEmitErrors) + { + LL_INFOS() << "LLSDXMLParser::Impl::parse: XML_STATUS_ERROR, null buffer" << LL_ENDL; + } + } data = LLSD(); return LLSDParser::PARSE_FAILURE; } From ae7b318e7f21d0d372d48a635ff1e2ea59c4acf6 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 22 Feb 2024 21:48:46 +0200 Subject: [PATCH 07/17] viewer#875 Crash at uri normalization Note that crash happened when setting LLProgressView::setMessage --- indra/llcommon/lluriparser.cpp | 18 ++++++++++++------ indra/llui/llurlentry.cpp | 18 ++++++++++++------ indra/llui/llurlregistry.cpp | 6 ++++-- 3 files changed, 28 insertions(+), 14 deletions(-) diff --git a/indra/llcommon/lluriparser.cpp b/indra/llcommon/lluriparser.cpp index e4f229dd16..f79a98a56d 100644 --- a/indra/llcommon/lluriparser.cpp +++ b/indra/llcommon/lluriparser.cpp @@ -164,8 +164,10 @@ void LLUriParser::extractParts() #if LL_DARWIN typedef void(*sighandler_t)(int); jmp_buf return_to_normalize; +static int sLastSignal = 0; void uri_signal_handler(int signal) { + sLastSignal = signal; // Apparently signal handler throwing an exception doesn't work. // This is ugly and unsafe due to not unwinding content of uriparser library, // but unless we have a way to catch this as NSexception, jump appears to be the only option. @@ -179,8 +181,10 @@ S32 LLUriParser::normalize() if (!mRes) { #if LL_DARWIN - sighandler_t last_handler; - last_handler = signal(SIGILL, &uri_signal_handler); // illegal instruction + sighandler_t last_sigill_handler, last_sigbus_handler; + last_sigill_handler = signal(SIGILL, &uri_signal_handler); // illegal instruction + last_sigbus_handler = signal(SIGBUS, &uri_signal_handler); + if (setjmp(return_to_normalize)) { // Issue: external library crashed via signal @@ -194,8 +198,9 @@ S32 LLUriParser::normalize() // if this can be handled by NSexception, it needs to be remade llassert(0); - LL_WARNS() << "Uriparser crashed with SIGILL, while processing: " << mNormalizedUri << LL_ENDL; - signal(SIGILL, last_handler); + LL_WARNS() << "Uriparser crashed with " << sLastSignal << " , while processing: " << mNormalizedUri << LL_ENDL; + signal(SIGILL, last_sigill_handler); + signal(SIGBUS, last_sigbus_handler); return 1; } #endif @@ -203,7 +208,8 @@ S32 LLUriParser::normalize() mRes = uriNormalizeSyntaxExA(&mUri, URI_NORMALIZE_SCHEME | URI_NORMALIZE_HOST); #if LL_DARWIN - signal(SIGILL, last_handler); + signal(SIGILL, last_sigill_handler); + signal(SIGBUS, last_sigbus_handler); #endif if (!mRes) @@ -226,7 +232,7 @@ S32 LLUriParser::normalize() } } - if(mTmpScheme) + if(mTmpScheme && mNormalizedUri.size() > 7) { mNormalizedUri = mNormalizedUri.substr(7); mTmpScheme = false; diff --git a/indra/llui/llurlentry.cpp b/indra/llui/llurlentry.cpp index 77e9edf5e5..05d821f5d8 100644 --- a/indra/llui/llurlentry.cpp +++ b/indra/llui/llurlentry.cpp @@ -234,14 +234,20 @@ bool LLUrlEntryBase::isWikiLinkCorrect(const std::string &labeled_url) const std::string LLUrlEntryBase::urlToLabelWithGreyQuery(const std::string &url) const { + if (url.empty()) + { + return url; + } LLUriParser up(escapeUrl(url)); - up.normalize(); + if (up.normalize() == 0) + { + std::string label; + up.extractParts(); + up.glueFirst(label); - std::string label; - up.extractParts(); - up.glueFirst(label); - - return unescapeUrl(label); + return unescapeUrl(label); + } + return std::string(); } std::string LLUrlEntryBase::urlToGreyQuery(const std::string &url) const diff --git a/indra/llui/llurlregistry.cpp b/indra/llui/llurlregistry.cpp index 3bd7321777..f1df7699e2 100644 --- a/indra/llui/llurlregistry.cpp +++ b/indra/llui/llurlregistry.cpp @@ -221,8 +221,10 @@ bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LL if (match_entry == mUrlEntryTrusted) { LLUriParser up(url); - up.normalize(); - url = up.normalizedUri(); + if (up.normalize() == 0) + { + url = up.normalizedUri(); + } } match.setValues(match_start, match_end, From a908b4cfa98716d4a838fc1e5a6789faa15d16cf Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Mon, 26 Feb 2024 11:23:47 -0500 Subject: [PATCH 08/17] Try to generate release notes for this specific branch. Also try to cross-reference release page and build page. --- .github/workflows/build.yaml | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 1bc74fe084..c78c8c656b 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -367,25 +367,30 @@ jobs: mv newview/viewer_version.txt macOS-viewer_version.txt # forked from softprops/action-gh-release - - uses: secondlife-3p/action-gh-release@v1 + - name: Create GitHub release + id: release + uses: secondlife-3p/action-gh-release@v1 with: - # name the release page for the build number so we can find it - # easily (analogous to looking up a codeticket build page) - name: "v${{ github.run_id }}" + # name the release page for the branch + name: "${{ needs.build.outputs.viewer_branch }}" # SL-20546: want the channel and version to be visible on the # release page body: | + Build ${{ github.repositoryUrl }}/actions/runs/${{ github.run_id }} ${{ needs.build.outputs.viewer_channel }} ${{ needs.build.outputs.viewer_version }} - ${{ needs.build.outputs.viewer_branch }} ${{ needs.build.outputs.relnotes }} prerelease: true generate_release_notes: true + target_commitish: ${{ github.ref }} append_body: true - # the only reason we generate a GH release is to post build products fail_on_unmatched_files: true files: | *.dmg *.exe *-autobuild-package.xml *-viewer_version.txt + + - name: post release URL + run: | + echo "::notice::Release ${{ steps.release.outputs.url }}" From c6a6db8488a8b3e7ea6534fbf5e2fe2b17864421 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Mon, 26 Feb 2024 12:20:31 -0500 Subject: [PATCH 09/17] Try basing the GH release on github.ref_name instead of github.ref. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Using github.ref as action-gh-release's target_commitish produces: ⚠️ GitHub release failed with status: 422 [{"resource":"Release","code":"invalid","field":"target_commitish"}] --- .github/workflows/build.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index c78c8c656b..622ceb4afe 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -382,7 +382,7 @@ jobs: ${{ needs.build.outputs.relnotes }} prerelease: true generate_release_notes: true - target_commitish: ${{ github.ref }} + target_commitish: ${{ github.ref_name }} append_body: true fail_on_unmatched_files: true files: | From 4edd78f2e54b3cd2e0b0a4b9300dfc669231dd98 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Mon, 26 Feb 2024 13:26:29 -0500 Subject: [PATCH 10/17] Try basing release notes on github.sha rather than github.ref_name. --- .github/workflows/build.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 622ceb4afe..6f4325b9dd 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -382,7 +382,7 @@ jobs: ${{ needs.build.outputs.relnotes }} prerelease: true generate_release_notes: true - target_commitish: ${{ github.ref_name }} + target_commitish: ${{ github.sha }} append_body: true fail_on_unmatched_files: true files: | From 88ebb92f05dade00cc8fc519cc062a458ecd48f2 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Mon, 26 Feb 2024 15:51:31 -0500 Subject: [PATCH 11/17] Leverage action-gh-release's new previous_tag input. This should (!) allow us to generate full release notes relative to the previous viewer release, instead of letting action-gh-release guess incorrectly. Also try again to add to the release page a back-link to the specific build. --- .github/workflows/build.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 6f4325b9dd..c903f1b8ce 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -369,20 +369,21 @@ jobs: # forked from softprops/action-gh-release - name: Create GitHub release id: release - uses: secondlife-3p/action-gh-release@v1 + uses: secondlife-3p/action-gh-release@feat/add-generateReleaseNotes with: # name the release page for the branch name: "${{ needs.build.outputs.viewer_branch }}" # SL-20546: want the channel and version to be visible on the # release page body: | - Build ${{ github.repositoryUrl }}/actions/runs/${{ github.run_id }} + Build ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} ${{ needs.build.outputs.viewer_channel }} ${{ needs.build.outputs.viewer_version }} ${{ needs.build.outputs.relnotes }} prerelease: true generate_release_notes: true target_commitish: ${{ github.sha }} + previous_tag: 7.1.2-release append_body: true fail_on_unmatched_files: true files: | From 27b298d8bc720ff315c8e74cc5bff9ff9ead0552 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Mon, 26 Feb 2024 17:05:56 -0500 Subject: [PATCH 12/17] Base generated release notes on new floating tag 'release' instead of on the current tag 7.1.2-release. --- .github/workflows/build.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index c903f1b8ce..28310e54e2 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -383,7 +383,7 @@ jobs: prerelease: true generate_release_notes: true target_commitish: ${{ github.sha }} - previous_tag: 7.1.2-release + previous_tag: release append_body: true fail_on_unmatched_files: true files: | From 563c35e1b4e5e0a1cd34dc92da917500f8a3d172 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 27 Feb 2024 01:20:56 +0200 Subject: [PATCH 13/17] Issue#894 Crash at load3 in cacheOptimize --- indra/llmath/llvolume.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index 6d36daa92a..e694732da2 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -5592,9 +5592,9 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents) U32 stream_count = data.w.empty() ? 4 : 5; - U32 vert_count = meshopt_generateVertexRemapMulti(&remap[0], nullptr, data.p.size(), data.p.size(), mos, stream_count); + size_t vert_count = meshopt_generateVertexRemapMulti(&remap[0], nullptr, data.p.size(), data.p.size(), mos, stream_count); - if (vert_count < 65535) + if (vert_count < 65535 && vert_count != 0) { std::vector indices; indices.resize(mNumIndices); @@ -5613,6 +5613,13 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents) { U32 src_idx = i; U32 dst_idx = remap[i]; + if (dst_idx >= mNumVertices) + { + dst_idx = mNumVertices - 1; + // Shouldn't happen, figure out what gets returned in remap and why. + llassert(false); + LL_DEBUGS_ONCE("LLVOLUME") << "Invalid destination index, substituting" << LL_ENDL; + } mIndices[i] = dst_idx; mPositions[dst_idx].load3(data.p[src_idx].mV); @@ -5646,6 +5653,10 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents) } else { + if (vert_count == 0) + { + LL_WARNS_ONCE("LLVOLUME") << "meshopt_generateVertexRemapMulti failed to process a model or model was invalid" << LL_ENDL; + } // blew past the max vertex size limit, use legacy tangent generation which never adds verts createTangents(); } From 44ea9490797ce0e984aadbf438c7a2aceef5ddf0 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 27 Feb 2024 23:00:37 +0200 Subject: [PATCH 14/17] Issue#900 Crash at LLInventoryAddItemByAssetObserver --- indra/newview/llinventoryobserver.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/indra/newview/llinventoryobserver.cpp b/indra/newview/llinventoryobserver.cpp index fe067b621a..e1eaa18206 100644 --- a/indra/newview/llinventoryobserver.cpp +++ b/indra/newview/llinventoryobserver.cpp @@ -566,8 +566,12 @@ void LLInventoryAddItemByAssetObserver::changed(U32 mask) for (uuid_set_t::iterator it = added.begin(); it != added.end(); ++it) { LLInventoryItem *item = gInventory.getItem(*it); + if (!item) + { + continue; + } const LLUUID& asset_uuid = item->getAssetUUID(); - if (item && item->getUUID().notNull() && asset_uuid.notNull()) + if (item->getUUID().notNull() && asset_uuid.notNull()) { if (isAssetWatched(asset_uuid)) { From 18ec799992e0e2571ed3d3a61454be682a81aa16 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 27 Feb 2024 23:02:00 +0200 Subject: [PATCH 15/17] SL-18721 Shutdown fixes #5 --- indra/llcommon/threadpool.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/indra/llcommon/threadpool.cpp b/indra/llcommon/threadpool.cpp index a063a01b82..c48989358e 100644 --- a/indra/llcommon/threadpool.cpp +++ b/indra/llcommon/threadpool.cpp @@ -120,8 +120,11 @@ void LL::ThreadPoolBase::close() mQueue->close(); for (auto& pair: mThreads) { - LL_DEBUGS("ThreadPool") << mName << " waiting on thread " << pair.first << LL_ENDL; - pair.second.join(); + if (pair.second.joinable()) + { + LL_DEBUGS("ThreadPool") << mName << " waiting on thread " << pair.first << LL_ENDL; + pair.second.join(); + } } LL_DEBUGS("ThreadPool") << mName << " shutdown complete" << LL_ENDL; } From b42e01d7acf5d4c55612c3a7df0e1ff6ee5ed951 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 28 Feb 2024 08:45:12 -0500 Subject: [PATCH 16/17] Reference updated action-gh-release@v1 instead of the branch that got pulled. --- .github/workflows/build.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 28310e54e2..321ba281cf 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -369,7 +369,7 @@ jobs: # forked from softprops/action-gh-release - name: Create GitHub release id: release - uses: secondlife-3p/action-gh-release@feat/add-generateReleaseNotes + uses: secondlife-3p/action-gh-release@v1 with: # name the release page for the branch name: "${{ needs.build.outputs.viewer_branch }}" From fe3be58938ec3a6241d011156cd6ff3607ed1602 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 29 Feb 2024 21:14:39 +0200 Subject: [PATCH 17/17] SL-18721 Shutdown fixes #6 --- indra/llwindow/llwindowwin32.cpp | 193 +++++++++++++++++++------------ 1 file changed, 118 insertions(+), 75 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) - { - mDXGIAdapter->Release(); - mDXGIAdapter = nullptr; - } - - if (mD3DDevice) - { - mD3DDevice->Release(); - mD3DDevice = nullptr; - } - - if (mD3D) - { - mD3D->Release(); - mD3D = nullptr; - } - + cleanupDX(); } -void LLWindowWin32::LLWindowWin32Thread::wakeAndClose() +void LLWindowWin32::LLWindowWin32Thread::wakeAndDestroy() { - if (!mQueue->isClosed()) + if (mQueue->isClosed()) { - LL_DEBUGS("Window") << "closing pool queue" << LL_ENDL; - mQueue->close(); + LL_WARNS() << "Tried to close Queue. Win32 thread Queue already closed." <close(); + + // Post a nonsense user message to wake up the thread in + // case it is waiting for a getMessage() + if (old_handle) + { + 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); + } + + // 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) + { + ms_sleep(100); + } + + if (getQueue().done() || mWindowHandleThrd == NULL) + { + // 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& func)