From 9d5b897600a8f9405ec37a141b9417f34a11c557 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Mon, 2 Dec 2019 14:39:24 -0500 Subject: DRTVWR-494: Defend LLInstanceTracker against multi-thread usage. The previous implementation went to some effort to crash if anyone attempted to create or destroy an LLInstanceTracker subclass instance during traversal. That restriction is manageable within a single thread, but becomes unworkable if it's possible that a given subclass might be used on more than one thread. Remove LLInstanceTracker::instance_iter, beginInstances(), endInstances(), also key_iter, beginKeys() and endKeys(). Instead, introduce key_snapshot() and instance_snapshot(), the only means of iterating over LLInstanceTracker instances. (These are intended to resemble functions, but in fact the current implementation simply presents the classes.) Iterating over a captured snapshot defends against container modifications during traversal. The term 'snapshot' reminds the coder that a new instance created during traversal will not be considered. To defend against instance deletion during traversal, a snapshot stores std::weak_ptrs which it lazily dereferences, skipping on the fly any that have expired. Dereferencing instance_snapshot::iterator gets you a reference rather than a pointer. Because some use cases want to delete all existing instances, add an instance_snapshot::deleteAll() method that extracts the pointer. Those cases used to require explicitly copying instance pointers into a separate container; instance_snapshot() now takes care of that. It remains the caller's responsibility to ensure that all instances of that LLInstanceTracker subclass were allocated on the heap. Replace unkeyed static LLInstanceTracker::getInstance(T*) -- which returned nullptr if that instance had been destroyed -- with new getWeak() method returning std::weak_ptr. Caller must detect expiration of that weak_ptr. Adjust tests accordingly. Use of std::weak_ptr to detect expired instances requires engaging std::shared_ptr in the constructor. We now store shared_ptrs in the static containers (std::map for keyed, std::set for unkeyed). Make LLInstanceTrackerBase a template parameterized on the type of the static data it manages. For that reason, hoist static data class declarations out of the class definitions to an LLInstanceTrackerStuff namespace. Remove the static atomic sIterationNestDepth and its methods incrementDepth(), decrementDepth() and getDepth(), since they were used only to forbid creation and destruction during traversal. Add a std::mutex to static data. Introduce an internal LockStatic class that locks the mutex while providing a pointer to static data, making that the only way to access the static data. The LLINSTANCETRACKER_DTOR_NOEXCEPT macro goes away because we no longer expect ~LLInstanceTracker() to throw an exception in test programs. That affects LLTrace::StatBase as well as LLInstanceTracker itself. Adapt consumers to the new LLInstanceTracker API. --- indra/newview/llappviewer.cpp | 26 ++++-------------- indra/newview/llchathistory.cpp | 4 +-- indra/newview/llimprocessing.cpp | 4 +-- indra/newview/llscenemonitor.cpp | 44 +++++++++++++------------------ indra/newview/lltoast.cpp | 23 ++-------------- indra/newview/llviewercontrollistener.cpp | 12 +++------ 6 files changed, 31 insertions(+), 82 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index b232a8c3bb..a76ac58724 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -1681,24 +1681,9 @@ bool LLAppViewer::cleanup() gDirUtilp->deleteFilesInDir(logdir, "*-*-*-*-*.dmp"); } - { - // Kill off LLLeap objects. We can find them all because LLLeap is derived - // from LLInstanceTracker. But collect instances first: LLInstanceTracker - // specifically forbids adding/deleting instances while iterating. - std::vector leaps; - leaps.reserve(LLLeap::instanceCount()); - for (LLLeap::instance_iter li(LLLeap::beginInstances()), lend(LLLeap::endInstances()); - li != lend; ++li) - { - leaps.push_back(&*li); - } - // Okay, now trash them all. We don't have to NULL or erase the entry - // in 'leaps' because the whole vector is going away momentarily. - BOOST_FOREACH(LLLeap* leap, leaps) - { - delete leap; - } - } // destroy 'leaps' + // Kill off LLLeap objects. We can find them all because LLLeap is derived + // from LLInstanceTracker. + LLLeap::instance_snapshot().deleteAll(); //flag all elements as needing to be destroyed immediately // to ensure shutdown order @@ -2858,12 +2843,11 @@ bool LLAppViewer::initConfiguration() // Let anyone else who cares know that we've populated our settings // variables. - for (LLControlGroup::key_iter ki(LLControlGroup::beginKeys()), kend(LLControlGroup::endKeys()); - ki != kend; ++ki) + for (const auto& key : LLControlGroup::key_snapshot()) { // For each named instance of LLControlGroup, send an event saying // we've initialized an LLControlGroup instance by that name. - LLEventPumps::instance().obtain("LLControlGroup").post(LLSDMap("init", *ki)); + LLEventPumps::instance().obtain("LLControlGroup").post(LLSDMap("init", key)); } return true; // Config was successful. diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp index 1099d4bc09..4131af828e 100644 --- a/indra/newview/llchathistory.cpp +++ b/indra/newview/llchathistory.cpp @@ -1344,10 +1344,8 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL // We don't want multiple friendship offers to appear, this code checks if there are previous offers // by iterating though all panels. // Note: it might be better to simply add a "pending offer" flag somewhere - for (LLToastNotifyPanel::instance_iter ti(LLToastNotifyPanel::beginInstances()) - , tend(LLToastNotifyPanel::endInstances()); ti != tend; ++ti) + for (auto& panel : LLToastNotifyPanel::instance_snapshot()) { - LLToastNotifyPanel& panel = *ti; LLIMToastNotifyPanel * imtoastp = dynamic_cast(&panel); const std::string& notification_name = panel.getNotificationName(); if (notification_name == "OfferFriendship" diff --git a/indra/newview/llimprocessing.cpp b/indra/newview/llimprocessing.cpp index c3375a3779..c1dcc61010 100644 --- a/indra/newview/llimprocessing.cpp +++ b/indra/newview/llimprocessing.cpp @@ -1404,10 +1404,8 @@ void LLIMProcessing::processNewMessage(LLUUID from_id, payload["sender"] = sender.getIPandPort(); bool add_notification = true; - for (LLToastNotifyPanel::instance_iter ti(LLToastNotifyPanel::beginInstances()) - , tend(LLToastNotifyPanel::endInstances()); ti != tend; ++ti) + for (auto& panel : LLToastNotifyPanel::instance_snapshot()) { - LLToastNotifyPanel& panel = *ti; const std::string& notification_name = panel.getNotificationName(); if (notification_name == "OfferFriendship" && panel.isControlPanelEnabled()) { diff --git a/indra/newview/llscenemonitor.cpp b/indra/newview/llscenemonitor.cpp index 5ab0013055..2c0c38dc75 100644 --- a/indra/newview/llscenemonitor.cpp +++ b/indra/newview/llscenemonitor.cpp @@ -559,16 +559,14 @@ void LLSceneMonitor::dumpToFile(std::string file_name) typedef StatType trace_count; - for (trace_count::instance_iter it = trace_count::beginInstances(), end_it = trace_count::endInstances(); - it != end_it; - ++it) + for (auto& it : trace_count::instance_snapshot()) { std::ostringstream row; row << std::setprecision(10); - row << it->getName(); + row << it.getName(); - const char* unit_label = it->getUnitLabel(); + const char* unit_label = it.getUnitLabel(); if(unit_label[0]) { row << "(" << unit_label << ")"; @@ -579,8 +577,8 @@ void LLSceneMonitor::dumpToFile(std::string file_name) for (S32 frame = 1; frame <= frame_count; frame++) { Recording& recording = scene_load_recording.getPrevRecording(frame_count - frame); - samples += recording.getSampleCount(*it); - row << ", " << recording.getSum(*it); + samples += recording.getSampleCount(it); + row << ", " << recording.getSum(it); } row << '\n'; @@ -593,15 +591,13 @@ void LLSceneMonitor::dumpToFile(std::string file_name) typedef StatType trace_event; - for (trace_event::instance_iter it = trace_event::beginInstances(), end_it = trace_event::endInstances(); - it != end_it; - ++it) + for (auto& it : trace_event::instance_snapshot()) { std::ostringstream row; row << std::setprecision(10); - row << it->getName(); + row << it.getName(); - const char* unit_label = it->getUnitLabel(); + const char* unit_label = it.getUnitLabel(); if(unit_label[0]) { row << "(" << unit_label << ")"; @@ -612,8 +608,8 @@ void LLSceneMonitor::dumpToFile(std::string file_name) for (S32 frame = 1; frame <= frame_count; frame++) { Recording& recording = scene_load_recording.getPrevRecording(frame_count - frame); - samples += recording.getSampleCount(*it); - F64 mean = recording.getMean(*it); + samples += recording.getSampleCount(it); + F64 mean = recording.getMean(it); if (llisnan(mean)) { row << ", n/a"; @@ -634,15 +630,13 @@ void LLSceneMonitor::dumpToFile(std::string file_name) typedef StatType trace_sample; - for (trace_sample::instance_iter it = trace_sample::beginInstances(), end_it = trace_sample::endInstances(); - it != end_it; - ++it) + for (auto& it : trace_sample::instance_snapshot()) { std::ostringstream row; row << std::setprecision(10); - row << it->getName(); + row << it.getName(); - const char* unit_label = it->getUnitLabel(); + const char* unit_label = it.getUnitLabel(); if(unit_label[0]) { row << "(" << unit_label << ")"; @@ -653,8 +647,8 @@ void LLSceneMonitor::dumpToFile(std::string file_name) for (S32 frame = 1; frame <= frame_count; frame++) { Recording& recording = scene_load_recording.getPrevRecording(frame_count - frame); - samples += recording.getSampleCount(*it); - F64 mean = recording.getMean(*it); + samples += recording.getSampleCount(it); + F64 mean = recording.getMean(it); if (llisnan(mean)) { row << ", n/a"; @@ -674,15 +668,13 @@ void LLSceneMonitor::dumpToFile(std::string file_name) } typedef StatType trace_mem; - for (trace_mem::instance_iter it = trace_mem::beginInstances(), end_it = trace_mem::endInstances(); - it != end_it; - ++it) + for (auto& it : trace_mem::instance_snapshot()) { - os << it->getName() << "(KiB)"; + os << it.getName() << "(KiB)"; for (S32 frame = 1; frame <= frame_count; frame++) { - os << ", " << scene_load_recording.getPrevRecording(frame_count - frame).getMax(*it).valueInUnits(); + os << ", " << scene_load_recording.getPrevRecording(frame_count - frame).getMax(it).valueInUnits(); } os << '\n'; diff --git a/indra/newview/lltoast.cpp b/indra/newview/lltoast.cpp index 870e0d94f0..bf56a10d4d 100644 --- a/indra/newview/lltoast.cpp +++ b/indra/newview/lltoast.cpp @@ -612,11 +612,8 @@ S32 LLToast::notifyParent(const LLSD& info) //static void LLToast::updateClass() { - for (LLInstanceTracker::instance_iter iter = LLInstanceTracker::beginInstances(); - iter != LLInstanceTracker::endInstances(); ) + for (auto& toast : LLInstanceTracker::instance_snapshot()) { - LLToast& toast = *iter++; - toast.updateHoveredState(); } } @@ -624,22 +621,6 @@ void LLToast::updateClass() // static void LLToast::cleanupToasts() { - LLToast * toastp = NULL; - - while (LLInstanceTracker::instanceCount() > 0) - { - { // Need to scope iter to allow deletion - LLInstanceTracker::instance_iter iter = LLInstanceTracker::beginInstances(); - toastp = &(*iter); - } - - //LL_INFOS() << "Cleaning up toast id " << toastp->getNotificationID() << LL_ENDL; - - // LLToast destructor will remove it from the LLInstanceTracker. - if (!toastp) - break; // Don't get stuck in the loop if a null pointer somehow got on the list - - delete toastp; - } + LLInstanceTracker::instance_snapshot().deleteAll(); } diff --git a/indra/newview/llviewercontrollistener.cpp b/indra/newview/llviewercontrollistener.cpp index d2484b2b23..3443bb644a 100644 --- a/indra/newview/llviewercontrollistener.cpp +++ b/indra/newview/llviewercontrollistener.cpp @@ -50,11 +50,9 @@ LLViewerControlListener::LLViewerControlListener() std::ostringstream groupnames; groupnames << "[\"group\"] is one of "; const char* delim = ""; - for (LLControlGroup::key_iter cgki(LLControlGroup::beginKeys()), - cgkend(LLControlGroup::endKeys()); - cgki != cgkend; ++cgki) + for (const auto& key : LLControlGroup::key_snapshot()) { - groupnames << delim << '"' << *cgki << '"'; + groupnames << delim << '"' << key << '"'; delim = ", "; } groupnames << '\n'; @@ -181,11 +179,9 @@ void LLViewerControlListener::groups(LLSD const & request) { // No Info, we're not looking up either a group or a control name. Response response(LLSD(), request); - for (LLControlGroup::key_iter cgki(LLControlGroup::beginKeys()), - cgkend(LLControlGroup::endKeys()); - cgki != cgkend; ++cgki) + for (const auto& key : LLControlGroup::key_snapshot()) { - response["groups"].append(*cgki); + response["groups"].append(key); } } -- cgit v1.2.3 From 47ec6ab3be5df5ee3f80a642d9c2ef7f4dac0d8a Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 30 May 2019 08:23:32 -0400 Subject: SL-11216: Remove LLSingletonBase::cleanupAll(). Remove call from LLAppViewer::cleanup(). Instead, make each LLSingleton::deleteSingleton() call cleanupSingleton() just before destroying the instance. Since deleteSingleton() is not a destructor, it's fine to call cleanupSingleton() from there; and since deleteAll() calls deleteSingleton() on every remaining instance, the former cleanupAll() functionality has been subsumed into deleteAll(). Since cleanupSingleton() is now called at exactly one point in the instance's lifetime, we no longer need a bool indicating whether it has been called. The previous protocol of calling cleanupAll() before deleteAll() implemented a two-phase cleanup strategy for the application. That is no longer needed. Moreover, the cleanupAll() / deleteAll() sequence created a time window during which individual LLSingleton instances weren't usable (to the extent that their cleanupSingleton() methods released essential resources) but still existed -- so a getInstance() call would return the crippled instance rather than recreating it. Remove cleanupAll() calls from tests; adjust to new order of expected side effects: instead of A::cleanupSingleton(), B::cleanupSingleton(), ~A(), ~B(), now we get A::cleanupSingleton(), ~A(), B::cleanupSingleton(), ~B(). --- indra/newview/llappviewer.cpp | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index a76ac58724..ed80e7c0ce 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -2093,25 +2093,19 @@ bool LLAppViewer::cleanup() removeMarkerFiles(); - // It's not at first obvious where, in this long sequence, generic cleanup - // calls OUGHT to go. So let's say this: as we migrate cleanup from + // It's not at first obvious where, in this long sequence, a generic cleanup + // call OUGHT to go. So let's say this: as we migrate cleanup from // explicit hand-placed calls into the generic mechanism, eventually - // all cleanup will get subsumed into the generic calls. So the calls you + // all cleanup will get subsumed into the generic call. So the calls you // still see above are calls that MUST happen before the generic cleanup // kicks in. - // This calls every remaining LLSingleton's cleanupSingleton() method. - // This method should perform any cleanup that might take significant - // realtime, or might throw an exception. - LLSingletonBase::cleanupAll(); - // The logging subsystem depends on an LLSingleton. Any logging after // LLSingletonBase::deleteAll() won't be recorded. LL_INFOS() << "Goodbye!" << LL_ENDL; - // This calls every remaining LLSingleton's deleteSingleton() method. - // No class destructor should perform any cleanup that might take - // significant realtime, or throw an exception. + // This calls every remaining LLSingleton's cleanupSingleton() and + // deleteSingleton() methods. LLSingletonBase::deleteAll(); removeDumpDir(); -- cgit v1.2.3 From 5a260e0cc3beec45da1d29578855524977206022 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 30 May 2019 10:39:37 -0400 Subject: SL-11216: Convert LLVersionInfo to an LLSingleton. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This changeset is meant to exemplify how to convert a "namespace" class whose methods are static -- and whose data are module-static -- to an LLSingleton. LLVersionInfo has no initClass() or cleanupClass() methods, but the general idea is the same. * Derive the class from LLSingleton: class LLSomeSingleton: public LLSingleton { ... }; * Add LLSINGLETON(LLSomeSingleton); in the private section of the class. This usage implies a separate LLSomeSingleton::LLSomeSingleton() definition, as described in indra/llcommon/llsingleton.h. * Move module-scope data in the .cpp file to non-static class members. Change any sVariableName to mVariableName to avoid being outright misleading. * Make static class methods non-static. Remove '//static' comments from method definitions as needed. * For LLVersionInfo specifically, the 'const std::string&' return type was replaced with 'std::string'. Returning a reference to a static or a member, const or otherwise, is an anti-pattern: the interface constrains the implementation, prohibiting possibly later returning a temporary (an expression). * For LLVersionInfo specifically, 'const S32' return type was replaced with simple 'S32'. 'const' is just noise in that usage. * Simple member initialization (e.g. the original initializer expressions for static variables) can be done with member{ value } initializers (no examples here though). * Delete initClass() method. * LLSingleton's forté is of course lazy initialization. It might work to simply delete any calls to initClass(). But if there are side effects that must happen at that moment, replace LLSomeSingleton::initClass() with (void)LLSomeSingleton::instance(); * Most initClass() initialization can be done in the constructor, as would normally be the case. * Initialization that might cause a circular LLSingleton reference should be moved to initSingleton(). Override 'void initSingleton();' should be private. * For LLVersionInfo specifically, certain initialization that used to be lazily performed was made unconditional, due to its low cost. * For LLVersionInfo specifically, certain initialization involved calling methods that have become non-static. This was moved to initSingleton() because, in a constructor body, 'this' does not yet point to the enclosing class. * Delete cleanupClass() method. * There is already a generic LLSingletonBase::deleteAll() call in LLAppViewer::cleanup(). It might work to let this new LLSingleton be cleaned up with all the rest. But if there are side effects that must happen at that moment, replace LLSomeSingleton::cleanupClass() with LLSomeSingleton::deleteSingleton(). That said, much of the benefit of converting to LLSingleton is deleteAll()'s guarantee that cross-LLSingleton dependencies will be properly honored: we're trying to migrate the code base away from the present fragile manual cleanup sequence. * Most cleanupClass() cleanup can be done in the destructor, as would normally be the case. * Cleanup that might throw an exception should be moved to cleanupSingleton(). Override 'void cleanupSingleton();' should be private. * Within LLSomeSingleton methods, remove any existing LLSomeSingleton::methodName() qualification: simple methodName() is better. * In the rest of the code base, convert most LLSomeSingleton::methodName() references to LLSomeSingleton::instance().methodName(). (Prefer instance() to getInstance() because a reference does not admit the possibility of NULL.) * Of course, LLSomeSingleton::ENUM_VALUE can remain unchanged. In general, for many successive references to an LLSingleton instance, it can be useful to capture the instance() as in: auto& versionInfo{LLVersionInfo::instance()}; // ... versionInfo.getVersion() ... We did not do that here only to simplify the code review. The STRINGIZE(expression) macro encapsulates: std::ostringstream out; out << expression; return out.str(); We used that in a couple places. For LLVersionInfo specifically, lllogininstance_test.cpp used to dummy out a couple specific static methods. It's harder to dummy out LLSingleton::instance() references, so we add the real class to that test. --- indra/newview/CMakeLists.txt | 1 + indra/newview/llappviewer.cpp | 50 ++++++++-------- indra/newview/llcurrencyuimanager.cpp | 20 +++---- indra/newview/llfloaterreporter.cpp | 4 +- indra/newview/lllogininstance.cpp | 4 +- indra/newview/llpanellogin.cpp | 12 ++-- indra/newview/llstartup.cpp | 10 ++-- indra/newview/lltexturestats.cpp | 4 +- indra/newview/lltranslate.cpp | 20 +++---- indra/newview/llversioninfo.cpp | 89 +++++++++++----------------- indra/newview/llversioninfo.h | 47 ++++++++++----- indra/newview/llviewermedia.cpp | 4 +- indra/newview/llviewerstats.cpp | 2 +- indra/newview/llviewerwindow.cpp | 2 +- indra/newview/llvoicevivox.cpp | 2 +- indra/newview/llweb.cpp | 12 ++-- indra/newview/tests/lllogininstance_test.cpp | 2 - indra/newview/tests/llversioninfo_test.cpp | 24 ++++---- 18 files changed, 152 insertions(+), 157 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 800696825f..dc0d737540 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -2434,6 +2434,7 @@ if (LL_TESTS) set_source_files_properties( lllogininstance.cpp PROPERTIES + LL_TEST_ADDITIONAL_SOURCE_FILES llversioninfo.cpp LL_TEST_ADDITIONAL_LIBRARIES "${BOOST_SYSTEM_LIBRARY}" ) diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index ed80e7c0ce..795d14740a 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -1120,7 +1120,7 @@ bool LLAppViewer::init() // Save the current version to the prefs file gSavedSettings.setString("LastRunVersion", - LLVersionInfo::getChannelAndVersion()); + LLVersionInfo::instance().getChannelAndVersion()); gSimLastTime = gRenderStartTime.getElapsedTimeF32(); gSimFrames = (F32)gFrameCount; @@ -1156,7 +1156,7 @@ bool LLAppViewer::init() // UpdaterServiceSettings updater.args.add(stringize(gSavedSettings.getU32("UpdaterServiceSetting"))); // channel - updater.args.add(LLVersionInfo::getChannel()); + updater.args.add(LLVersionInfo::instance().getChannel()); // testok updater.args.add(stringize(gSavedSettings.getBOOL("UpdaterWillingToTest"))); // ForceAddressSize @@ -2616,7 +2616,7 @@ bool LLAppViewer::initConfiguration() std::string CmdLineChannel(gSavedSettings.getString("CmdLineChannel")); if(! CmdLineChannel.empty()) { - LLVersionInfo::resetChannel(CmdLineChannel); + LLVersionInfo::instance().resetChannel(CmdLineChannel); } // If we have specified crash on startup, set the global so we'll trigger the crash at the right time @@ -3062,15 +3062,15 @@ LLSD LLAppViewer::getViewerInfo() const // LLFloaterAbout. LLSD info; LLSD version; - version.append(LLVersionInfo::getMajor()); - version.append(LLVersionInfo::getMinor()); - version.append(LLVersionInfo::getPatch()); - version.append(LLVersionInfo::getBuild()); + version.append(LLVersionInfo::instance().getMajor()); + version.append(LLVersionInfo::instance().getMinor()); + version.append(LLVersionInfo::instance().getPatch()); + version.append(LLVersionInfo::instance().getBuild()); info["VIEWER_VERSION"] = version; - info["VIEWER_VERSION_STR"] = LLVersionInfo::getVersion(); - info["CHANNEL"] = LLVersionInfo::getChannel(); + info["VIEWER_VERSION_STR"] = LLVersionInfo::instance().getVersion(); + info["CHANNEL"] = LLVersionInfo::instance().getChannel(); info["ADDRESS_SIZE"] = ADDRESS_SIZE; - std::string build_config = LLVersionInfo::getBuildConfig(); + std::string build_config = LLVersionInfo::instance().getBuildConfig(); if (build_config != "Release") { info["BUILD_CONFIG"] = build_config; @@ -3081,7 +3081,7 @@ LLSD LLAppViewer::getViewerInfo() const std::string url = LLTrans::getString("RELEASE_NOTES_BASE_URL"); if (! LLStringUtil::endsWith(url, "/")) url += "/"; - url += LLURI::escape(LLVersionInfo::getVersion()) + ".html"; + url += LLURI::escape(LLVersionInfo::instance().getVersion()) + ".html"; info["VIEWER_RELEASE_NOTES_URL"] = url; @@ -3372,12 +3372,12 @@ void LLAppViewer::writeSystemInfo() gDebugInfo["SLLog"] = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLife.old"); //LLError::logFileName(); #endif - gDebugInfo["ClientInfo"]["Name"] = LLVersionInfo::getChannel(); - gDebugInfo["ClientInfo"]["MajorVersion"] = LLVersionInfo::getMajor(); - gDebugInfo["ClientInfo"]["MinorVersion"] = LLVersionInfo::getMinor(); - gDebugInfo["ClientInfo"]["PatchVersion"] = LLVersionInfo::getPatch(); - gDebugInfo["ClientInfo"]["BuildVersion"] = LLVersionInfo::getBuild(); - gDebugInfo["ClientInfo"]["AddressSize"] = LLVersionInfo::getAddressSize(); + gDebugInfo["ClientInfo"]["Name"] = LLVersionInfo::instance().getChannel(); + gDebugInfo["ClientInfo"]["MajorVersion"] = LLVersionInfo::instance().getMajor(); + gDebugInfo["ClientInfo"]["MinorVersion"] = LLVersionInfo::instance().getMinor(); + gDebugInfo["ClientInfo"]["PatchVersion"] = LLVersionInfo::instance().getPatch(); + gDebugInfo["ClientInfo"]["BuildVersion"] = LLVersionInfo::instance().getBuild(); + gDebugInfo["ClientInfo"]["AddressSize"] = LLVersionInfo::instance().getAddressSize(); gDebugInfo["CAFilename"] = gDirUtilp->getCAFile(); @@ -3420,7 +3420,7 @@ void LLAppViewer::writeSystemInfo() // Dump some debugging info LL_INFOS("SystemInfo") << "Application: " << LLTrans::getString("APP_NAME") << LL_ENDL; - LL_INFOS("SystemInfo") << "Version: " << LLVersionInfo::getChannelAndVersion() << LL_ENDL; + LL_INFOS("SystemInfo") << "Version: " << LLVersionInfo::instance().getChannelAndVersion() << LL_ENDL; // Dump the local time and time zone time_t now; @@ -3642,7 +3642,7 @@ void LLAppViewer::handleViewerCrash() // static void LLAppViewer::recordMarkerVersion(LLAPRFile& marker_file) { - std::string marker_version(LLVersionInfo::getChannelAndVersion()); + std::string marker_version(LLVersionInfo::instance().getChannelAndVersion()); if ( marker_version.length() > MAX_MARKER_LENGTH ) { LL_WARNS_ONCE("MarkerFile") << "Version length ("<< marker_version.length()<< ")" @@ -3659,7 +3659,7 @@ bool LLAppViewer::markerIsSameVersion(const std::string& marker_name) const { bool sameVersion = false; - std::string my_version(LLVersionInfo::getChannelAndVersion()); + std::string my_version(LLVersionInfo::instance().getChannelAndVersion()); char marker_version[MAX_MARKER_LENGTH]; S32 marker_version_length; @@ -5517,12 +5517,12 @@ void LLAppViewer::handleLoginComplete() initMainloopTimeout("Mainloop Init"); // Store some data to DebugInfo in case of a freeze. - gDebugInfo["ClientInfo"]["Name"] = LLVersionInfo::getChannel(); + gDebugInfo["ClientInfo"]["Name"] = LLVersionInfo::instance().getChannel(); - gDebugInfo["ClientInfo"]["MajorVersion"] = LLVersionInfo::getMajor(); - gDebugInfo["ClientInfo"]["MinorVersion"] = LLVersionInfo::getMinor(); - gDebugInfo["ClientInfo"]["PatchVersion"] = LLVersionInfo::getPatch(); - gDebugInfo["ClientInfo"]["BuildVersion"] = LLVersionInfo::getBuild(); + gDebugInfo["ClientInfo"]["MajorVersion"] = LLVersionInfo::instance().getMajor(); + gDebugInfo["ClientInfo"]["MinorVersion"] = LLVersionInfo::instance().getMinor(); + gDebugInfo["ClientInfo"]["PatchVersion"] = LLVersionInfo::instance().getPatch(); + gDebugInfo["ClientInfo"]["BuildVersion"] = LLVersionInfo::instance().getBuild(); LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); if ( parcel && parcel->getMusicURL()[0]) diff --git a/indra/newview/llcurrencyuimanager.cpp b/indra/newview/llcurrencyuimanager.cpp index b4a1457f47..df94e337da 100644 --- a/indra/newview/llcurrencyuimanager.cpp +++ b/indra/newview/llcurrencyuimanager.cpp @@ -166,11 +166,11 @@ void LLCurrencyUIManager::Impl::updateCurrencyInfo() gAgent.getSecureSessionID().asString()); keywordArgs.appendString("language", LLUI::getLanguage()); keywordArgs.appendInt("currencyBuy", mUserCurrencyBuy); - keywordArgs.appendString("viewerChannel", LLVersionInfo::getChannel()); - keywordArgs.appendInt("viewerMajorVersion", LLVersionInfo::getMajor()); - keywordArgs.appendInt("viewerMinorVersion", LLVersionInfo::getMinor()); - keywordArgs.appendInt("viewerPatchVersion", LLVersionInfo::getPatch()); - keywordArgs.appendInt("viewerBuildVersion", LLVersionInfo::getBuild()); + keywordArgs.appendString("viewerChannel", LLVersionInfo::instance().getChannel()); + keywordArgs.appendInt("viewerMajorVersion", LLVersionInfo::instance().getMajor()); + keywordArgs.appendInt("viewerMinorVersion", LLVersionInfo::instance().getMinor()); + keywordArgs.appendInt("viewerPatchVersion", LLVersionInfo::instance().getPatch()); + keywordArgs.appendInt("viewerBuildVersion", LLVersionInfo::instance().getBuild()); LLXMLRPCValue params = LLXMLRPCValue::createArray(); params.append(keywordArgs); @@ -241,11 +241,11 @@ void LLCurrencyUIManager::Impl::startCurrencyBuy(const std::string& password) { keywordArgs.appendString("password", password); } - keywordArgs.appendString("viewerChannel", LLVersionInfo::getChannel()); - keywordArgs.appendInt("viewerMajorVersion", LLVersionInfo::getMajor()); - keywordArgs.appendInt("viewerMinorVersion", LLVersionInfo::getMinor()); - keywordArgs.appendInt("viewerPatchVersion", LLVersionInfo::getPatch()); - keywordArgs.appendInt("viewerBuildVersion", LLVersionInfo::getBuild()); + keywordArgs.appendString("viewerChannel", LLVersionInfo::instance().getChannel()); + keywordArgs.appendInt("viewerMajorVersion", LLVersionInfo::instance().getMajor()); + keywordArgs.appendInt("viewerMinorVersion", LLVersionInfo::instance().getMinor()); + keywordArgs.appendInt("viewerPatchVersion", LLVersionInfo::instance().getPatch()); + keywordArgs.appendInt("viewerBuildVersion", LLVersionInfo::instance().getBuild()); LLXMLRPCValue params = LLXMLRPCValue::createArray(); params.append(keywordArgs); diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp index 4cc43254a5..64b7880938 100644 --- a/indra/newview/llfloaterreporter.cpp +++ b/indra/newview/llfloaterreporter.cpp @@ -765,7 +765,7 @@ LLSD LLFloaterReporter::gatherReport() std::ostringstream details; - details << "V" << LLVersionInfo::getVersion() << std::endl << std::endl; // client version moved to body of email for abuse reports + details << "V" << LLVersionInfo::instance().getVersion() << std::endl << std::endl; // client version moved to body of email for abuse reports std::string object_name = getChild("object_name")->getValue().asString(); if (!object_name.empty() && !mOwnerName.empty()) @@ -783,7 +783,7 @@ LLSD LLFloaterReporter::gatherReport() std::string version_string; version_string = llformat( "%s %s %s %s %s", - LLVersionInfo::getShortVersion().c_str(), + LLVersionInfo::instance().getShortVersion().c_str(), platform, gSysCPU.getFamily().c_str(), gGLManager.mGLRenderer.c_str(), diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp index 8a69acb8dc..a3c78cc5a5 100644 --- a/indra/newview/lllogininstance.cpp +++ b/indra/newview/lllogininstance.cpp @@ -215,8 +215,8 @@ void LLLoginInstance::constructAuthParams(LLPointer user_credentia request_params["last_exec_event"] = mLastExecEvent; request_params["last_exec_duration"] = mLastExecDuration; request_params["mac"] = (char*)hashed_unique_id_string; - request_params["version"] = LLVersionInfo::getVersion(); - request_params["channel"] = LLVersionInfo::getChannel(); + request_params["version"] = LLVersionInfo::instance().getVersion(); + request_params["channel"] = LLVersionInfo::instance().getChannel(); request_params["platform"] = mPlatform; request_params["address_size"] = ADDRESS_SIZE; request_params["platform_version"] = mPlatformVersion; diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index 224cec9650..70757882d8 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -338,10 +338,10 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, LLButton* def_btn = getChild("connect_btn"); setDefaultBtn(def_btn); - std::string channel = LLVersionInfo::getChannel(); + std::string channel = LLVersionInfo::instance().getChannel(); std::string version = llformat("%s (%d)", - LLVersionInfo::getShortVersion().c_str(), - LLVersionInfo::getBuild()); + LLVersionInfo::instance().getShortVersion().c_str(), + LLVersionInfo::instance().getBuild()); LLTextBox* forgot_password_text = getChild("forgot_password_text"); forgot_password_text->setClickedCallback(onClickForgotPassword, NULL); @@ -943,9 +943,9 @@ void LLPanelLogin::loadLoginPage() // Channel and Version params["version"] = llformat("%s (%d)", - LLVersionInfo::getShortVersion().c_str(), - LLVersionInfo::getBuild()); - params["channel"] = LLVersionInfo::getChannel(); + LLVersionInfo::instance().getShortVersion().c_str(), + LLVersionInfo::instance().getBuild()); + params["channel"] = LLVersionInfo::instance().getChannel(); // Grid params["grid"] = LLGridManager::getInstance()->getGridId(); diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index be6e9e520a..de046440c5 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -512,9 +512,9 @@ bool idle_startup() if(!start_messaging_system( message_template_path, port, - LLVersionInfo::getMajor(), - LLVersionInfo::getMinor(), - LLVersionInfo::getPatch(), + LLVersionInfo::instance().getMajor(), + LLVersionInfo::instance().getMinor(), + LLVersionInfo::instance().getPatch(), FALSE, std::string(), responder, @@ -2309,8 +2309,8 @@ void login_callback(S32 option, void *userdata) void show_release_notes_if_required() { static bool release_notes_shown = false; - if (!release_notes_shown && (LLVersionInfo::getChannelAndVersion() != gLastRunVersion) - && LLVersionInfo::getViewerMaturity() != LLVersionInfo::TEST_VIEWER // don't show Release Notes for the test builds + if (!release_notes_shown && (LLVersionInfo::instance().getChannelAndVersion() != gLastRunVersion) + && LLVersionInfo::instance().getViewerMaturity() != LLVersionInfo::TEST_VIEWER // don't show Release Notes for the test builds && gSavedSettings.getBOOL("UpdaterShowReleaseNotes") && !gSavedSettings.getBOOL("FirstLoginThisInstall")) { diff --git a/indra/newview/lltexturestats.cpp b/indra/newview/lltexturestats.cpp index b55b4d9ca4..8f4b7d000c 100644 --- a/indra/newview/lltexturestats.cpp +++ b/indra/newview/lltexturestats.cpp @@ -46,8 +46,8 @@ void send_texture_stats_to_sim(const LLSD &texture_stats) LLUUID agent_id = gAgent.getID(); texture_stats_report["agent_id"] = agent_id; texture_stats_report["region_id"] = gAgent.getRegion()->getRegionID(); - texture_stats_report["viewer_channel"] = LLVersionInfo::getChannel(); - texture_stats_report["viewer_version"] = LLVersionInfo::getVersion(); + texture_stats_report["viewer_channel"] = LLVersionInfo::instance().getChannel(); + texture_stats_report["viewer_version"] = LLVersionInfo::instance().getVersion(); texture_stats_report["stats_data"] = texture_stats; std::string texture_cap_url = gAgent.getRegion()->getCapability("TextureStats"); diff --git a/indra/newview/lltranslate.cpp b/indra/newview/lltranslate.cpp index e424983cf8..fa3b44f702 100644 --- a/indra/newview/lltranslate.cpp +++ b/indra/newview/lltranslate.cpp @@ -134,11 +134,11 @@ void LLTranslationAPIHandler::verifyKeyCoro(LLTranslate::EService service, std:: std::string user_agent = llformat("%s %d.%d.%d (%d)", - LLVersionInfo::getChannel().c_str(), - LLVersionInfo::getMajor(), - LLVersionInfo::getMinor(), - LLVersionInfo::getPatch(), - LLVersionInfo::getBuild()); + LLVersionInfo::instance().getChannel().c_str(), + LLVersionInfo::instance().getMajor(), + LLVersionInfo::instance().getMinor(), + LLVersionInfo::instance().getPatch(), + LLVersionInfo::instance().getBuild()); httpHeaders->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_TEXT_PLAIN); httpHeaders->append(HTTP_OUT_HEADER_USER_AGENT, user_agent); @@ -177,11 +177,11 @@ void LLTranslationAPIHandler::translateMessageCoro(LanguagePair_t fromTo, std::s std::string user_agent = llformat("%s %d.%d.%d (%d)", - LLVersionInfo::getChannel().c_str(), - LLVersionInfo::getMajor(), - LLVersionInfo::getMinor(), - LLVersionInfo::getPatch(), - LLVersionInfo::getBuild()); + LLVersionInfo::instance().getChannel().c_str(), + LLVersionInfo::instance().getMajor(), + LLVersionInfo::instance().getMinor(), + LLVersionInfo::instance().getPatch(), + LLVersionInfo::instance().getBuild()); httpHeaders->append(HTTP_OUT_HEADER_ACCEPT, HTTP_CONTENT_TEXT_PLAIN); httpHeaders->append(HTTP_OUT_HEADER_USER_AGENT, user_agent); diff --git a/indra/newview/llversioninfo.cpp b/indra/newview/llversioninfo.cpp index 4e07223784..f4b1f2566d 100644 --- a/indra/newview/llversioninfo.cpp +++ b/indra/newview/llversioninfo.cpp @@ -29,6 +29,7 @@ #include #include #include "llversioninfo.h" +#include "stringize.h" #include #if ! defined(LL_VIEWER_CHANNEL) \ @@ -43,100 +44,81 @@ // Set the version numbers in indra/VIEWER_VERSION // -//static +LLVersionInfo::LLVersionInfo(): + // LL_VIEWER_CHANNEL is a macro defined on the compiler command line. The + // macro expands to the string name of the channel, but without quotes. We + // need to turn it into a quoted string. LL_TO_STRING() does that. + mWorkingChannelName(LL_TO_STRING(LL_VIEWER_CHANNEL)), + build_configuration(LLBUILD_CONFIG), // set in indra/cmake/BuildVersion.cmake + short_version(STRINGIZE(LL_VIEWER_VERSION_MAJOR << "." + << LL_VIEWER_VERSION_MINOR << "." + << LL_VIEWER_VERSION_PATCH)) +{ +} + +void LLVersionInfo::initSingleton() +{ + // We override initSingleton() not because we have dependencies on other + // LLSingletons, but because certain initializations call other member + // functions. We should refrain from calling methods until this object is + // fully constructed; such calls don't really belong in the constructor. + + // cache the version string + version = STRINGIZE(getShortVersion() << "." << getBuild()); +} + S32 LLVersionInfo::getMajor() { return LL_VIEWER_VERSION_MAJOR; } -//static S32 LLVersionInfo::getMinor() { return LL_VIEWER_VERSION_MINOR; } -//static S32 LLVersionInfo::getPatch() { return LL_VIEWER_VERSION_PATCH; } -//static S32 LLVersionInfo::getBuild() { return LL_VIEWER_VERSION_BUILD; } -//static -const std::string &LLVersionInfo::getVersion() +std::string LLVersionInfo::getVersion() { - static std::string version(""); - if (version.empty()) - { - std::ostringstream stream; - stream << LLVersionInfo::getShortVersion() << "." << LLVersionInfo::getBuild(); - // cache the version string - version = stream.str(); - } return version; } -//static -const std::string &LLVersionInfo::getShortVersion() +std::string LLVersionInfo::getShortVersion() { - static std::string short_version(""); - if(short_version.empty()) - { - // cache the version string - std::ostringstream stream; - stream << LL_VIEWER_VERSION_MAJOR << "." - << LL_VIEWER_VERSION_MINOR << "." - << LL_VIEWER_VERSION_PATCH; - short_version = stream.str(); - } return short_version; } -namespace -{ - // LL_VIEWER_CHANNEL is a macro defined on the compiler command line. The - // macro expands to the string name of the channel, but without quotes. We - // need to turn it into a quoted string. LL_TO_STRING() does that. - /// Storage of the channel name the viewer is using. - // The channel name is set by hardcoded constant, - // or by calling LLVersionInfo::resetChannel() - std::string sWorkingChannelName(LL_TO_STRING(LL_VIEWER_CHANNEL)); - - // Storage for the "version and channel" string. - // This will get reset too. - std::string sVersionChannel(""); -} - -//static -const std::string &LLVersionInfo::getChannelAndVersion() +std::string LLVersionInfo::getChannelAndVersion() { - if (sVersionChannel.empty()) + if (mVersionChannel.empty()) { // cache the version string - sVersionChannel = LLVersionInfo::getChannel() + " " + LLVersionInfo::getVersion(); + mVersionChannel = getChannel() + " " + getVersion(); } - return sVersionChannel; + return mVersionChannel; } -//static -const std::string &LLVersionInfo::getChannel() +std::string LLVersionInfo::getChannel() { - return sWorkingChannelName; + return mWorkingChannelName; } void LLVersionInfo::resetChannel(const std::string& channel) { - sWorkingChannelName = channel; - sVersionChannel.clear(); // Reset version and channel string til next use. + mWorkingChannelName = channel; + mVersionChannel.clear(); // Reset version and channel string til next use. } -//static LLVersionInfo::ViewerMaturity LLVersionInfo::getViewerMaturity() { ViewerMaturity maturity; @@ -175,8 +157,7 @@ LLVersionInfo::ViewerMaturity LLVersionInfo::getViewerMaturity() } -const std::string &LLVersionInfo::getBuildConfig() +std::string LLVersionInfo::getBuildConfig() { - static const std::string build_configuration(LLBUILD_CONFIG); // set in indra/cmake/BuildVersion.cmake return build_configuration; } diff --git a/indra/newview/llversioninfo.h b/indra/newview/llversioninfo.h index b8b4341385..7857468697 100644 --- a/indra/newview/llversioninfo.h +++ b/indra/newview/llversioninfo.h @@ -30,6 +30,7 @@ #include #include "stdtypes.h" +#include "llsingleton.h" /// /// This API provides version information for the viewer. This @@ -38,42 +39,44 @@ /// viewer code that wants to query the current version should /// use this API. /// -class LLVersionInfo +class LLVersionInfo: public LLSingleton { + LLSINGLETON(LLVersionInfo); + void initSingleton(); public: - /// return the major verion number as an integer - static S32 getMajor(); + /// return the major version number as an integer + S32 getMajor(); - /// return the minor verion number as an integer - static S32 getMinor(); + /// return the minor version number as an integer + S32 getMinor(); - /// return the patch verion number as an integer - static S32 getPatch(); + /// return the patch version number as an integer + S32 getPatch(); /// return the build number as an integer - static S32 getBuild(); + S32 getBuild(); /// return the full viewer version as a string like "2.0.0.200030" - static const std::string &getVersion(); + std::string getVersion(); /// return the viewer version as a string like "2.0.0" - static const std::string &getShortVersion(); + std::string getShortVersion(); /// return the viewer version and channel as a string /// like "Second Life Release 2.0.0.200030" - static const std::string &getChannelAndVersion(); + std::string getChannelAndVersion(); /// return the channel name, e.g. "Second Life" - static const std::string &getChannel(); + std::string getChannel(); /// return the CMake build type - static const std::string &getBuildConfig(); + std::string getBuildConfig(); /// reset the channel name used by the viewer. - static void resetChannel(const std::string& channel); + void resetChannel(const std::string& channel); /// return the bit width of an address - static const S32 getAddressSize() { return ADDRESS_SIZE; } + S32 getAddressSize() { return ADDRESS_SIZE; } typedef enum { @@ -82,7 +85,19 @@ public: BETA_VIEWER, RELEASE_VIEWER } ViewerMaturity; - static ViewerMaturity getViewerMaturity(); + ViewerMaturity getViewerMaturity(); + +private: + std::string version; + std::string short_version; + /// Storage of the channel name the viewer is using. + // The channel name is set by hardcoded constant, + // or by calling resetChannel() + std::string mWorkingChannelName; + // Storage for the "version and channel" string. + // This will get reset too. + std::string mVersionChannel; + std::string build_configuration; }; #endif diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 99b54f66d3..572e53c37f 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -412,7 +412,7 @@ std::string LLViewerMedia::getCurrentUserAgent() // Just in case we need to check browser differences in A/B test // builds. - std::string channel = LLVersionInfo::getChannel(); + std::string channel = LLVersionInfo::instance().getChannel(); // append our magic version number string to the browser user agent id // See the HTTP 1.0 and 1.1 specifications for allowed formats: @@ -422,7 +422,7 @@ std::string LLViewerMedia::getCurrentUserAgent() // http://www.mozilla.org/build/revised-user-agent-strings.html std::ostringstream codec; codec << "SecondLife/"; - codec << LLVersionInfo::getVersion(); + codec << LLVersionInfo::instance().getVersion(); codec << " (" << channel << "; " << skin_name << " skin)"; LL_INFOS() << codec.str() << LL_ENDL; diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp index 85d87a43af..0f58933005 100644 --- a/indra/newview/llviewerstats.cpp +++ b/indra/newview/llviewerstats.cpp @@ -473,7 +473,7 @@ void send_stats() // send fps only for time app spends in foreground agent["fps"] = (F32)gForegroundFrameCount / gForegroundTime.getElapsedTimeF32(); - agent["version"] = LLVersionInfo::getChannelAndVersion(); + agent["version"] = LLVersionInfo::instance().getChannelAndVersion(); std::string language = LLUI::getLanguage(); agent["language"] = language; diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index ff5dff1c9b..c045fd8aa6 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -2477,7 +2477,7 @@ void LLViewerWindow::setMenuBackgroundColor(bool god_mode, bool dev_grid) } else { - switch (LLVersionInfo::getViewerMaturity()) + switch (LLVersionInfo::instance().getViewerMaturity()) { case LLVersionInfo::TEST_VIEWER: new_bg_color = LLUIColorTable::instance().getColor( "MenuBarTestBgColor" ); diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index 739f7bd47c..358396632c 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -527,7 +527,7 @@ void LLVivoxVoiceClient::connectorCreate() << ".log" << "" << vivoxLogLevel << "" << "" - << "" << LLVersionInfo::getChannel().c_str() << " " << LLVersionInfo::getVersion().c_str() << "" + << "" << LLVersionInfo::instance().getChannel() << " " << LLVersionInfo::instance().getVersion() << "" //<< "" //Name can cause problems per vivox. << "12" << "\n\n\n"; diff --git a/indra/newview/llweb.cpp b/indra/newview/llweb.cpp index a34c5826ed..63257d6543 100644 --- a/indra/newview/llweb.cpp +++ b/indra/newview/llweb.cpp @@ -157,12 +157,12 @@ std::string LLWeb::expandURLSubstitutions(const std::string &url, const LLSD &default_subs) { LLSD substitution = default_subs; - substitution["VERSION"] = LLVersionInfo::getVersion(); - substitution["VERSION_MAJOR"] = LLVersionInfo::getMajor(); - substitution["VERSION_MINOR"] = LLVersionInfo::getMinor(); - substitution["VERSION_PATCH"] = LLVersionInfo::getPatch(); - substitution["VERSION_BUILD"] = LLVersionInfo::getBuild(); - substitution["CHANNEL"] = LLVersionInfo::getChannel(); + substitution["VERSION"] = LLVersionInfo::instance().getVersion(); + substitution["VERSION_MAJOR"] = LLVersionInfo::instance().getMajor(); + substitution["VERSION_MINOR"] = LLVersionInfo::instance().getMinor(); + substitution["VERSION_PATCH"] = LLVersionInfo::instance().getPatch(); + substitution["VERSION_BUILD"] = LLVersionInfo::instance().getBuild(); + substitution["CHANNEL"] = LLVersionInfo::instance().getChannel(); substitution["GRID"] = LLGridManager::getInstance()->getGridId(); substitution["GRID_LOWERCASE"] = utf8str_tolower(LLGridManager::getInstance()->getGridId()); substitution["OS"] = LLOSInfo::instance().getOSStringSimple(); diff --git a/indra/newview/tests/lllogininstance_test.cpp b/indra/newview/tests/lllogininstance_test.cpp index 2edad30493..57f2d31eab 100644 --- a/indra/newview/tests/lllogininstance_test.cpp +++ b/indra/newview/tests/lllogininstance_test.cpp @@ -202,8 +202,6 @@ void LLUIColorTable::saveUserSettings(void)const {} //----------------------------------------------------------------------------- #include "../llversioninfo.h" -const std::string &LLVersionInfo::getVersion() { return VIEWERLOGIN_VERSION; } -const std::string &LLVersionInfo::getChannel() { return VIEWERLOGIN_CHANNEL; } bool llHashedUniqueID(unsigned char* id) { diff --git a/indra/newview/tests/llversioninfo_test.cpp b/indra/newview/tests/llversioninfo_test.cpp index 58f0469552..51a6f8f113 100644 --- a/indra/newview/tests/llversioninfo_test.cpp +++ b/indra/newview/tests/llversioninfo_test.cpp @@ -83,39 +83,39 @@ namespace tut void versioninfo_object_t::test<1>() { std::cout << "What we parsed from CMake: " << LL_VIEWER_VERSION_BUILD << std::endl; - std::cout << "What we get from llversioninfo: " << LLVersionInfo::getBuild() << std::endl; + std::cout << "What we get from llversioninfo: " << LLVersionInfo::instance().getBuild() << std::endl; ensure_equals("Major version", - LLVersionInfo::getMajor(), + LLVersionInfo::instance().getMajor(), LL_VIEWER_VERSION_MAJOR); ensure_equals("Minor version", - LLVersionInfo::getMinor(), + LLVersionInfo::instance().getMinor(), LL_VIEWER_VERSION_MINOR); ensure_equals("Patch version", - LLVersionInfo::getPatch(), + LLVersionInfo::instance().getPatch(), LL_VIEWER_VERSION_PATCH); ensure_equals("Build version", - LLVersionInfo::getBuild(), + LLVersionInfo::instance().getBuild(), LL_VIEWER_VERSION_BUILD); ensure_equals("Channel version", - LLVersionInfo::getChannel(), + LLVersionInfo::instance().getChannel(), ll_viewer_channel); ensure_equals("Version String", - LLVersionInfo::getVersion(), + LLVersionInfo::instance().getVersion(), mVersion); ensure_equals("Short Version String", - LLVersionInfo::getShortVersion(), + LLVersionInfo::instance().getShortVersion(), mShortVersion); ensure_equals("Version and channel String", - LLVersionInfo::getChannelAndVersion(), + LLVersionInfo::instance().getChannelAndVersion(), mVersionAndChannel); - LLVersionInfo::resetChannel(mResetChannel); + LLVersionInfo::instance().resetChannel(mResetChannel); ensure_equals("Reset channel version", - LLVersionInfo::getChannel(), + LLVersionInfo::instance().getChannel(), mResetChannel); ensure_equals("Reset Version and channel String", - LLVersionInfo::getChannelAndVersion(), + LLVersionInfo::instance().getChannelAndVersion(), mResetVersionAndChannel); } } -- cgit v1.2.3 From 378e4fae94c9c16b0b9070d7c7d3f63cba8aee94 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 30 May 2019 16:35:45 -0400 Subject: SL-11216: Introduce LLVersionInfo::getReleaseNotes() method. The default string returned by getReleaseNotes() is empty. It must be set by posting the relevant release-notes URL string to a new LLEventMailDrop instance named "relnotes". Add unique_ptr and unique_ptr> to LLVersionInfo -- using unique_ptr to leave those classes opaque to header-file consumers. Introduce an out-of-line destructor to handle the unique_ptr idiom. Initialize the LLEventMailDrop with the desired name; initialize the LLStoreListener with that LLEventMailDrop and the data member returned by getReleaseNotes(). --- indra/newview/llversioninfo.cpp | 24 +++++++++++++++++++----- indra/newview/llversioninfo.h | 21 ++++++++++++++++++++- 2 files changed, 39 insertions(+), 6 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llversioninfo.cpp b/indra/newview/llversioninfo.cpp index f4b1f2566d..4720a989b0 100644 --- a/indra/newview/llversioninfo.cpp +++ b/indra/newview/llversioninfo.cpp @@ -26,8 +26,8 @@ */ #include "llviewerprecompiledheaders.h" -#include -#include +#include "llevents.h" +#include "lleventfilter.h" #include "llversioninfo.h" #include "stringize.h" #include @@ -45,14 +45,19 @@ // LLVersionInfo::LLVersionInfo(): + short_version(STRINGIZE(LL_VIEWER_VERSION_MAJOR << "." + << LL_VIEWER_VERSION_MINOR << "." + << LL_VIEWER_VERSION_PATCH)), // LL_VIEWER_CHANNEL is a macro defined on the compiler command line. The // macro expands to the string name of the channel, but without quotes. We // need to turn it into a quoted string. LL_TO_STRING() does that. mWorkingChannelName(LL_TO_STRING(LL_VIEWER_CHANNEL)), build_configuration(LLBUILD_CONFIG), // set in indra/cmake/BuildVersion.cmake - short_version(STRINGIZE(LL_VIEWER_VERSION_MAJOR << "." - << LL_VIEWER_VERSION_MINOR << "." - << LL_VIEWER_VERSION_PATCH)) + // instantiate an LLEventMailDrop with canonical name to listen for news + // from SLVersionChecker + mPump{new LLEventMailDrop("relnotes")}, + // immediately listen on mPump, store arriving URL into mReleaseNotes + mStore{new LLStoreListener(*mPump, mReleaseNotes)} { } @@ -67,6 +72,10 @@ void LLVersionInfo::initSingleton() version = STRINGIZE(getShortVersion() << "." << getBuild()); } +LLVersionInfo::~LLVersionInfo() +{ +} + S32 LLVersionInfo::getMajor() { return LL_VIEWER_VERSION_MAJOR; @@ -161,3 +170,8 @@ std::string LLVersionInfo::getBuildConfig() { return build_configuration; } + +std::string LLVersionInfo::getReleaseNotes() +{ + return mReleaseNotes; +} diff --git a/indra/newview/llversioninfo.h b/indra/newview/llversioninfo.h index 7857468697..02ff0c094a 100644 --- a/indra/newview/llversioninfo.h +++ b/indra/newview/llversioninfo.h @@ -28,9 +28,14 @@ #ifndef LL_LLVERSIONINFO_H #define LL_LLVERSIONINFO_H -#include #include "stdtypes.h" #include "llsingleton.h" +#include +#include + +class LLEventMailDrop; +template +class LLStoreListener; /// /// This API provides version information for the viewer. This @@ -44,6 +49,8 @@ class LLVersionInfo: public LLSingleton LLSINGLETON(LLVersionInfo); void initSingleton(); public: + ~LLVersionInfo(); + /// return the major version number as an integer S32 getMajor(); @@ -87,6 +94,10 @@ public: } ViewerMaturity; ViewerMaturity getViewerMaturity(); + /// get the release-notes URL, once it becomes available -- until then, + /// return empty string + std::string getReleaseNotes(); + private: std::string version; std::string short_version; @@ -98,6 +109,14 @@ private: // This will get reset too. std::string mVersionChannel; std::string build_configuration; + std::string mReleaseNotes; + // Store unique_ptrs to the next couple things so we don't have to explain + // to every consumer of this header file all the details of each. + // mPump is the LLEventMailDrop on which we listen for SLVersionChecker to + // post the release-notes URL from the Viewer Version Manager. + std::unique_ptr mPump; + // mStore is an adapter that stores the release-notes URL in mReleaseNotes. + std::unique_ptr> mStore; }; #endif -- cgit v1.2.3 From 7fbbd4b766a86c3b8d0d0ed3b9e2ebf3fd27a889 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Fri, 31 May 2019 16:42:07 -0400 Subject: SL-11216: Add a "getStateTable" op to "LLStartUp" listener. getStateTable returns a list of the EStartupState symbolic names, implicitly mapping each to its index (its enum numeric value). --- indra/newview/llstartup.h | 1 + indra/newview/llstartuplistener.cpp | 26 +++++++++++++++++++++++++- indra/newview/llstartuplistener.h | 1 + 3 files changed, 27 insertions(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/llstartup.h b/indra/newview/llstartup.h index d7d294e9f4..3ec3ff4133 100644 --- a/indra/newview/llstartup.h +++ b/indra/newview/llstartup.h @@ -128,6 +128,7 @@ public: static LLViewerStats::PhaseMap& getPhases() { return *sPhases; } private: + friend class LLStartupListener; static LLSLURL sStartSLURL; static std::string startupStateToString(EStartupState state); diff --git a/indra/newview/llstartuplistener.cpp b/indra/newview/llstartuplistener.cpp index d9a21f908e..5770b595d0 100644 --- a/indra/newview/llstartuplistener.cpp +++ b/indra/newview/llstartuplistener.cpp @@ -35,7 +35,7 @@ // external library headers // other Linden headers #include "llstartup.h" - +#include "stringize.h" LLStartupListener::LLStartupListener(/* LLStartUp* instance */): LLEventAPI("LLStartUp", "Access e.g. LLStartup::postStartupState()") /* , @@ -43,9 +43,33 @@ LLStartupListener::LLStartupListener(/* LLStartUp* instance */): { add("postStartupState", "Refresh \"StartupState\" listeners with current startup state", &LLStartupListener::postStartupState); + add("getStateTable", "Reply with array of EStartupState string names", + &LLStartupListener::getStateTable); } void LLStartupListener::postStartupState(const LLSD&) const { LLStartUp::postStartupState(); } + +void LLStartupListener::getStateTable(const LLSD& event) const +{ + Response response(LLSD(), event); + + // This relies on our knowledge that STATE_STARTED is the very last + // EStartupState value. If that ever stops being true, we're going to lie + // without realizing it. I can think of no reliable way to test whether + // the enum has been extended *beyond* STATE_STARTED. We could, of course, + // test whether stuff has been inserted before it, by testing its + // numerical value against the constant value as of the last time we + // looked; but that's pointless, as values inserted before STATE_STARTED + // will continue to work fine. The bad case is if new symbols get added + // *after* it. + LLSD table; + // note <= comparison: we want to *include* STATE_STARTED. + for (LLSD::Integer istate{0}; istate <= LLSD::Integer(STATE_STARTED); ++istate) + { + table.append(LLStartUp::startupStateToString(EStartupState(istate))); + } + response["table"] = table; +} diff --git a/indra/newview/llstartuplistener.h b/indra/newview/llstartuplistener.h index a35e11f6eb..0b4380a568 100644 --- a/indra/newview/llstartuplistener.h +++ b/indra/newview/llstartuplistener.h @@ -40,6 +40,7 @@ public: private: void postStartupState(const LLSD&) const; + void getStateTable(const LLSD&) const; //LLStartup* mStartup; }; -- cgit v1.2.3 From 15418f991a77416e765e985c39267bb6d4c51a6f Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Fri, 31 May 2019 16:44:58 -0400 Subject: SL-11216: getViewerInfo() calls LLVersionInfo::getReleaseNotes(). Make LLAppViewer retrieve release notes from LLVersionInfo, rather than synthesizing the release-notes URL itself based on the viewer version string. --- indra/newview/llappviewer.cpp | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 795d14740a..ef4500c01f 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -3061,16 +3061,12 @@ LLSD LLAppViewer::getViewerInfo() const // is available to a getInfo() caller as to the user opening // LLFloaterAbout. LLSD info; - LLSD version; - version.append(LLVersionInfo::instance().getMajor()); - version.append(LLVersionInfo::instance().getMinor()); - version.append(LLVersionInfo::instance().getPatch()); - version.append(LLVersionInfo::instance().getBuild()); - info["VIEWER_VERSION"] = version; - info["VIEWER_VERSION_STR"] = LLVersionInfo::instance().getVersion(); - info["CHANNEL"] = LLVersionInfo::instance().getChannel(); + auto& versionInfo{ LLVersionInfo::instance() }; + info["VIEWER_VERSION"] = LLSDArray(versionInfo.getMajor())(versionInfo.getMinor())(versionInfo.getPatch())(versionInfo.getBuild()); + info["VIEWER_VERSION_STR"] = versionInfo.getVersion(); + info["CHANNEL"] = versionInfo.getChannel(); info["ADDRESS_SIZE"] = ADDRESS_SIZE; - std::string build_config = LLVersionInfo::instance().getBuildConfig(); + std::string build_config = versionInfo.getBuildConfig(); if (build_config != "Release") { info["BUILD_CONFIG"] = build_config; @@ -3078,12 +3074,8 @@ LLSD LLAppViewer::getViewerInfo() const // return a URL to the release notes for this viewer, such as: // https://releasenotes.secondlife.com/viewer/2.1.0.123456.html - std::string url = LLTrans::getString("RELEASE_NOTES_BASE_URL"); - if (! LLStringUtil::endsWith(url, "/")) - url += "/"; - url += LLURI::escape(LLVersionInfo::instance().getVersion()) + ".html"; - - info["VIEWER_RELEASE_NOTES_URL"] = url; + std::string url = versionInfo.getReleaseNotes(); + info["VIEWER_RELEASE_NOTES_URL"] = url.empty()? LLTrans::getString("RetrievingData") : url; // Position LLViewerRegion* region = gAgent.getRegion(); -- cgit v1.2.3 From 31d9930a0ff7da5a6312a8f47037052cd2d06bdb Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Fri, 31 May 2019 16:47:20 -0400 Subject: SL-11216: To display release notes, listen on "relnotes" LLEventPump. Now, when the viewer decides it's appropriate to display release notes on the login screen, wait for SLVersionChecker to post the release-notes URL before opening the web floater. --- indra/newview/llstartup.cpp | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index de046440c5..7c19dfac75 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -2309,13 +2309,29 @@ void login_callback(S32 option, void *userdata) void show_release_notes_if_required() { static bool release_notes_shown = false; + // We happen to know that instantiating LLVersionInfo implicitly + // instantiates the LLEventMailDrop named "relnotes", which we (might) use + // below. If viewer release notes stop working, might be because that + // LLEventMailDrop got moved out of LLVersionInfo and hasn't yet been + // instantiated. if (!release_notes_shown && (LLVersionInfo::instance().getChannelAndVersion() != gLastRunVersion) && LLVersionInfo::instance().getViewerMaturity() != LLVersionInfo::TEST_VIEWER // don't show Release Notes for the test builds && gSavedSettings.getBOOL("UpdaterShowReleaseNotes") && !gSavedSettings.getBOOL("FirstLoginThisInstall")) { - LLSD info(LLAppViewer::instance()->getViewerInfo()); - LLWeb::loadURLInternal(info["VIEWER_RELEASE_NOTES_URL"]); + // Instantiate a "relnotes" listener which assumes any arriving event + // is the release notes URL string. Since "relnotes" is an + // LLEventMailDrop, this listener will be invoked whether or not the + // URL has already been posted. If so, it will fire immediately; + // otherwise it will fire whenever the URL is (later) posted. Either + // way, it will display the release notes as soon as the URL becomes + // available. + LLEventPumps::instance().obtain("relnotes").listen( + "showrelnotes", + [](const LLSD& url){ + LLWeb::loadURLInternal(url.asString()); + return false; + }); release_notes_shown = true; } } -- cgit v1.2.3 From 8961be780d5c5ffa4f9cfc8060756a1bac5fc69f Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Sat, 1 Jun 2019 09:30:36 -0400 Subject: SL-11216: Try to pacify VS 2013. --- indra/newview/llappviewer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index ef4500c01f..af70751b37 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -3061,7 +3061,7 @@ LLSD LLAppViewer::getViewerInfo() const // is available to a getInfo() caller as to the user opening // LLFloaterAbout. LLSD info; - auto& versionInfo{ LLVersionInfo::instance() }; + auto& versionInfo(LLVersionInfo::instance()); info["VIEWER_VERSION"] = LLSDArray(versionInfo.getMajor())(versionInfo.getMinor())(versionInfo.getPatch())(versionInfo.getBuild()); info["VIEWER_VERSION_STR"] = versionInfo.getVersion(); info["CHANNEL"] = versionInfo.getChannel(); -- cgit v1.2.3 From bf999f2f84dd26844c60d682f563f982a55e8ee8 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 23 May 2019 15:27:37 -0400 Subject: SL-11215: Add release notes URLs to update-related notifications. Add code to login-fail handler to provide release notes URL from SLVersionChecker handshake event. --- indra/newview/lllogininstance.cpp | 26 ++++++++++++++++++---- .../newview/skins/default/xui/en/notifications.xml | 5 +++++ 2 files changed, 27 insertions(+), 4 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp index a3c78cc5a5..3f665971cb 100644 --- a/indra/newview/lllogininstance.cpp +++ b/indra/newview/lllogininstance.cpp @@ -332,7 +332,7 @@ void LLLoginInstance::handleLoginFailure(const LLSD& event) { data["certificate"] = response["certificate"]; } - + if (gViewerWindow) gViewerWindow->setShowProgress(FALSE); @@ -349,13 +349,31 @@ void LLLoginInstance::handleLoginFailure(const LLSD& event) // login.cgi is insisting on a required update. We were called with an // event that bundles both the login.cgi 'response' and the // synchronization event from the 'updater'. - std::string required_version = response["message_args"]["VERSION"]; - LL_WARNS("LLLogin") << "Login failed because an update to version " << required_version << " is required." << LL_ENDL; + std::string login_version = response["message_args"]["VERSION"]; + std::string vvm_version = updater["VERSION"]; + std::string relnotes = updater["URL"]; + LL_WARNS("LLLogin") << "Login failed because an update to version " << login_version << " is required." << LL_ENDL; + // vvm_version might be empty because we might not have gotten + // SLVersionChecker's LoginSync handshake. But if it IS populated, it + // should (!) be the same as the version we got from login.cgi. + if ((! vvm_version.empty()) && vvm_version != login_version) + { + LL_WARNS("LLLogin") << "VVM update version " << vvm_version + << " differs from login version " << login_version + << "; presenting VVM version to match release notes URL" + << LL_ENDL; + login_version = vvm_version; + } + if (relnotes.empty()) + { + // I thought this would be available in strings.xml or some such + relnotes = "https://secondlife.com/support/downloads/"; + } if (gViewerWindow) gViewerWindow->setShowProgress(FALSE); - LLSD args(LLSDMap("VERSION", required_version)); + LLSD args(LLSDMap("VERSION", login_version)("URL", relnotes)); if (updater.isUndefined()) { // If the updater failed to shake hands, better advise the user to diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index 57183ac3a6..04235e5d81 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -4016,6 +4016,8 @@ Finished download of raw terrain file to: [DOWNLOAD_PATH]. + Version [VERSION] is required for login. +Release notes: [URL] Click OK to download and install. confirm Version [VERSION] has been downloaded and is ready to install. +Release notes: [URL] Click OK to install. confirm Version [VERSION] has been downloaded and is ready to install. +Release notes: [URL] Proceed? confirm Date: Thu, 25 Oct 2018 11:24:06 -0400 Subject: DRTVWR-476: Fix _open_osfhandle() param from long to intptr_t. The Microsoft _open_osfhandle() opens a HANDLE to produce a C-style int file descriptor suitable for passing to _fdopen(). We used to cast the HANDLEs returned by GetStdHandle() to long to pass to _open_osfhandle(). Since HANDLE is an alias for a pointer, this no longer works. Fortunately _open_osfhandle() now accepts intptr_t, so we can change the relevant GetStdHandle() calls. (But why not simply accept HANDLE in the first place?) --- indra/newview/llappviewerwin32.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index d208e135bb..9a8a5f16bb 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -504,7 +504,7 @@ const S32 MAX_CONSOLE_LINES = 500; static bool create_console() { int h_con_handle; - long l_std_handle; + intptr_t l_std_handle; CONSOLE_SCREEN_BUFFER_INFO coninfo; FILE *fp; @@ -518,7 +518,7 @@ static bool create_console() SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coninfo.dwSize); // redirect unbuffered STDOUT to the console - l_std_handle = (long)GetStdHandle(STD_OUTPUT_HANDLE); + l_std_handle = reinterpret_cast(GetStdHandle(STD_OUTPUT_HANDLE)); h_con_handle = _open_osfhandle(l_std_handle, _O_TEXT); if (h_con_handle == -1) { @@ -532,7 +532,7 @@ static bool create_console() } // redirect unbuffered STDIN to the console - l_std_handle = (long)GetStdHandle(STD_INPUT_HANDLE); + l_std_handle = reinterpret_cast(GetStdHandle(STD_INPUT_HANDLE)); h_con_handle = _open_osfhandle(l_std_handle, _O_TEXT); if (h_con_handle == -1) { @@ -546,7 +546,7 @@ static bool create_console() } // redirect unbuffered STDERR to the console - l_std_handle = (long)GetStdHandle(STD_ERROR_HANDLE); + l_std_handle = reinterpret_cast(GetStdHandle(STD_ERROR_HANDLE)); h_con_handle = _open_osfhandle(l_std_handle, _O_TEXT); if (h_con_handle == -1) { -- cgit v1.2.3 From e9c667af96278d277eb2a20a6d8364d21464c3eb Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 25 Oct 2018 11:26:39 -0400 Subject: DRTVWR-476: Eliminate std::mem_fun1() special case for Windows. We used to have to use #if LL_WINDOWS logic to pass std::mem_fun1() to llbind2nd() instead of std::mem_fun() elsewhere. VS 2017 no longer supports std::mem_fun1(), which means we can eliminate the special case for Windows. --- indra/newview/llfloaterregioninfo.cpp | 4 ---- 1 file changed, 4 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp index ec934a4732..8a4f5dfc49 100644 --- a/indra/newview/llfloaterregioninfo.cpp +++ b/indra/newview/llfloaterregioninfo.cpp @@ -573,11 +573,7 @@ void LLFloaterRegionInfo::refreshFromRegion(LLViewerRegion* region) mInfoPanels.begin(), mInfoPanels.end(), llbind2nd( -#if LL_WINDOWS - std::mem_fun1(&LLPanelRegionInfo::refreshFromRegion), -#else std::mem_fun(&LLPanelRegionInfo::refreshFromRegion), -#endif region)); } -- cgit v1.2.3 From 66981fab0b3c8dcc3a031d50710a2b24ec6b0603 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 10 May 2018 21:46:07 -0400 Subject: SL-793: Use Boost.Fiber instead of the "dcoroutine" library. Longtime fans will remember that the "dcoroutine" library is a Google Summer of Code project by Giovanni P. Deretta. He originally called it "Boost.Coroutine," and we originally added it to our 3p-boost autobuild package as such. But when the official Boost.Coroutine library came along (with a very different API), and we still needed the API of the GSoC project, we renamed the unofficial one "dcoroutine" to allow coexistence. The "dcoroutine" library had an internal low-level API more or less analogous to Boost.Context. We later introduced an implementation of that internal API based on Boost.Context, a step towards eliminating the GSoC code in favor of official, supported Boost code. However, recent versions of Boost.Context no longer support the API on which we built the shim for "dcoroutine." We started down the path of reimplementing that shim using the current Boost.Context API -- then realized that it's time to bite the bullet and replace the "dcoroutine" API with the Boost.Fiber API, which we've been itching to do for literally years now. Naturally, most of the heavy lifting is in llcoros.{h,cpp} and lleventcoro.{h,cpp} -- which is good: the LLCoros layer abstracts away most of the differences between "dcoroutine" and Boost.Fiber. The one feature Boost.Fiber does not provide is the ability to forcibly terminate some other fiber. Accordingly, disable LLCoros::kill() and LLCoprocedureManager::shutdown(). The only known shutdown() call was in LLCoprocedurePool's destructor. We also took the opportunity to remove postAndSuspend2() and its associated machinery: FutureListener2, LLErrorEvent, errorException(), errorLog(), LLCoroEventPumps. All that dual-LLEventPump stuff was introduced at a time when the Responder pattern was king, and we assumed we'd want to listen on one LLEventPump with the success handler and on another with the error handler. We have never actually used that in practice. Remove associated tests, of course. There is one other semantic difference that necessitates patching a number of tests: with "dcoroutine," fulfilling a future IMMEDIATELY resumes the waiting coroutine. With Boost.Fiber, fulfilling a future merely marks the fiber as ready to resume next time the scheduler gets around to it. To observe the test side effects, we've inserted a number of llcoro::suspend() calls -- also in the main loop. For a long time we retained a single unit test exercising the raw "dcoroutine" API. Remove that. Eliminate llcoro_get_id.{h,cpp}, which provided llcoro::get_id(), which was a hack to emulate fiber-local variables. Since Boost.Fiber has an actual API for that, remove the hack. In fact, use (new alias) LLCoros::local_ptr for LLSingleton's dependency tracking in place of llcoro::get_id(). In CMake land, replace BOOST_COROUTINE_LIBRARY with BOOST_FIBER_LIBRARY. We don't actually use the Boost.Coroutine for anything (though there exist plausible use cases). --- indra/newview/CMakeLists.txt | 4 ++-- indra/newview/llappviewer.cpp | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index dc0d737540..45f4cb269c 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -2004,7 +2004,7 @@ target_link_libraries(${VIEWER_BINARY_NAME} ${viewer_LIBRARIES} ${BOOST_PROGRAM_OPTIONS_LIBRARY} ${BOOST_REGEX_LIBRARY} - ${BOOST_COROUTINE_LIBRARY} + ${BOOST_FIBER_LIBRARY} ${BOOST_CONTEXT_LIBRARY} ${DBUSGLIB_LIBRARIES} ${OPENGL_LIBRARIES} @@ -2484,7 +2484,7 @@ if (LL_TESTS) ${OPENSSL_LIBRARIES} ${CRYPTO_LIBRARIES} ${LIBRT_LIBRARY} - ${BOOST_COROUTINE_LIBRARY} + ${BOOST_FIBER_LIBRARY} ${BOOST_CONTEXT_LIBRARY} ) diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index af70751b37..db2db43ee1 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -1422,6 +1422,8 @@ bool LLAppViewer::doFrame() // canonical per-frame event mainloop.post(newFrame); + // give listeners a chance to run + llcoro::suspend(); if (!LLApp::isExiting()) { -- cgit v1.2.3 From e039f5e29ee02c37d2febc21b492a0d425661897 Mon Sep 17 00:00:00 2001 From: Anchor Date: Wed, 8 May 2019 17:37:05 -0600 Subject: [DRTVWR-476] - legacy_stdio_definitions shld be the last library linked --- indra/newview/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'indra/newview') diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 45f4cb269c..3ba6767082 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -1977,6 +1977,10 @@ endif (WINDOWS) # dumped into the target binary and runtime lookup will find the most # modern version. +if (WINDOWS) + list(APPEND LLAPPEARANCE_LIBRARIES legacy_stdio_definitions) +endif (WINDOWS) + target_link_libraries(${VIEWER_BINARY_NAME} ${PNG_PRELOAD_ARCHIVES} ${ZLIB_PRELOAD_ARCHIVES} -- cgit v1.2.3 From 761d9aa3bff981d1f322c9fdfe33ac35b30bf338 Mon Sep 17 00:00:00 2001 From: Anchor Date: Wed, 8 May 2019 18:05:49 -0600 Subject: [DRTVWR-476] - test adding at beginiing of list --- indra/newview/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 3ba6767082..2ad969a705 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -1978,7 +1978,7 @@ endif (WINDOWS) # modern version. if (WINDOWS) - list(APPEND LLAPPEARANCE_LIBRARIES legacy_stdio_definitions) + list(INSERT PNG_PRELOAD_ARCHIVES 0 legacy_stdio_definitions) endif (WINDOWS) target_link_libraries(${VIEWER_BINARY_NAME} -- cgit v1.2.3 From b5bb0794f0022517c7aeff9a7775864a56488da6 Mon Sep 17 00:00:00 2001 From: Anchor Date: Wed, 8 May 2019 18:57:33 -0600 Subject: [DRTVWR-476] - fix linking --- indra/newview/CMakeLists.txt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 2ad969a705..0ba3b07566 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -1977,11 +1977,8 @@ endif (WINDOWS) # dumped into the target binary and runtime lookup will find the most # modern version. -if (WINDOWS) - list(INSERT PNG_PRELOAD_ARCHIVES 0 legacy_stdio_definitions) -endif (WINDOWS) - target_link_libraries(${VIEWER_BINARY_NAME} + ${LEGACY_STDIO_LIBS} ${PNG_PRELOAD_ARCHIVES} ${ZLIB_PRELOAD_ARCHIVES} ${URIPARSER_PRELOAD_ARCHIVES} -- cgit v1.2.3 From b09770946a8ae3396517c6796d1bff2a1707de26 Mon Sep 17 00:00:00 2001 From: Anchor Date: Wed, 15 May 2019 03:57:10 -0600 Subject: [DRTVWR-476] - disable dbghelp.h warnings --- indra/newview/llwindebug.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'indra/newview') diff --git a/indra/newview/llwindebug.h b/indra/newview/llwindebug.h index 7e5818ba1c..05f245b311 100644 --- a/indra/newview/llwindebug.h +++ b/indra/newview/llwindebug.h @@ -29,7 +29,11 @@ #include "stdtypes.h" #include "llwin32headerslean.h" + +#pragma warning (push) +#pragma warning (disable:4091) // a microsoft header has warnings. Very nice. #include +#pragma warning (pop) class LLWinDebug: public LLSingleton -- cgit v1.2.3 From 6ffbed484ac9bc8358db44b420a3d598d14b72ac Mon Sep 17 00:00:00 2001 From: Brad Kittenbrink Date: Wed, 1 May 2019 15:28:55 -0700 Subject: Fix stall during login by yielding when needed from the LLXXMLRPCListener's Poller. --- indra/newview/llxmlrpclistener.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'indra/newview') diff --git a/indra/newview/llxmlrpclistener.cpp b/indra/newview/llxmlrpclistener.cpp index 7bc8af4a0b..5871161032 100644 --- a/indra/newview/llxmlrpclistener.cpp +++ b/indra/newview/llxmlrpclistener.cpp @@ -43,6 +43,7 @@ // other Linden headers #include "llerror.h" +#include "lleventcoro.h" #include "stringize.h" #include "llxmlrpctransaction.h" #include "llsecapi.h" @@ -401,6 +402,8 @@ public: // whether successful or not, send reply on requested LLEventPump replyPump.post(data); + // need to wake up the loginCoro now + llcoro::suspend(); // Because mTransaction is a boost::scoped_ptr, deleting this object // frees our LLXMLRPCTransaction object. -- cgit v1.2.3 From 690909716bfb2e2cae3bf9c18f6ec37d3ece086e Mon Sep 17 00:00:00 2001 From: Anchor Date: Thu, 6 Jun 2019 02:49:19 -0700 Subject: [DRTVWR-476] - fix compiler error --- indra/newview/llviewerprecompiledheaders.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'indra/newview') diff --git a/indra/newview/llviewerprecompiledheaders.h b/indra/newview/llviewerprecompiledheaders.h index 999d9092bd..bbbacce8fa 100644 --- a/indra/newview/llviewerprecompiledheaders.h +++ b/indra/newview/llviewerprecompiledheaders.h @@ -29,6 +29,8 @@ #ifndef LL_LLVIEWERPRECOMPILEDHEADERS_H #define LL_LLVIEWERPRECOMPILEDHEADERS_H +#include "llwin32headers.h" + // This file MUST be the first one included by each .cpp file // in viewer. // It is used to precompile headers for improved build speed. -- cgit v1.2.3 From 32f1dfa531062071ccf090b9c3d391b274caf02b Mon Sep 17 00:00:00 2001 From: Anchor Date: Mon, 10 Jun 2019 15:56:44 -0700 Subject: [DRTVWR-476] - fix compiler errors 32 bit windows build --- indra/newview/llpaneleditwearable.cpp | 6 +++--- indra/newview/llvovolume.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llpaneleditwearable.cpp b/indra/newview/llpaneleditwearable.cpp index 6573be0aaf..c601a6c210 100644 --- a/indra/newview/llpaneleditwearable.cpp +++ b/indra/newview/llpaneleditwearable.cpp @@ -778,7 +778,7 @@ BOOL LLPanelEditWearable::postBuild() LL_WARNS() << "could not get wearable dictionary entry for wearable of type: " << type << LL_ENDL; continue; } - U8 num_subparts = wearable_entry->mSubparts.size(); + U8 num_subparts = (U8)(wearable_entry->mSubparts.size()); for (U8 index = 0; index < num_subparts; ++index) { @@ -1181,7 +1181,7 @@ void LLPanelEditWearable::showWearable(LLViewerWearable* wearable, BOOL show, BO updatePanelPickerControls(type); // clear and rebuild visual param list - U8 num_subparts = wearable_entry->mSubparts.size(); + U8 num_subparts = (U8)(wearable_entry->mSubparts.size()); for (U8 index = 0; index < num_subparts; ++index) { @@ -1372,7 +1372,7 @@ void LLPanelEditWearable::updateScrollingPanelUI() const LLEditWearableDictionary::WearableEntry *wearable_entry = LLEditWearableDictionary::getInstance()->getWearable(type); llassert(wearable_entry); if (!wearable_entry) return; - U8 num_subparts = wearable_entry->mSubparts.size(); + U8 num_subparts = (U8)(wearable_entry->mSubparts.size()); LLScrollingPanelParam::sUpdateDelayFrames = 0; for (U8 index = 0; index < num_subparts; ++index) diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 0a1efd564f..fa5938df04 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -2063,7 +2063,7 @@ void LLVOVolume::setNumTEs(const U8 num_tes) } else if(old_num_tes > num_tes && mMediaImplList.size() > num_tes) //old faces removed { - U8 end = mMediaImplList.size() ; + U8 end = (U8)(mMediaImplList.size()) ; for(U8 i = num_tes; i < end ; i++) { removeMediaImpl(i) ; -- cgit v1.2.3 From 16b768370b8587f63231f9bbc06ab48b58a4f15e Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Fri, 4 Oct 2019 08:45:00 -0400 Subject: DRTVWR-476: Fix Windows line endings --- indra/newview/llwindebug.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llwindebug.h b/indra/newview/llwindebug.h index 05f245b311..524adba652 100644 --- a/indra/newview/llwindebug.h +++ b/indra/newview/llwindebug.h @@ -29,8 +29,8 @@ #include "stdtypes.h" #include "llwin32headerslean.h" - -#pragma warning (push) + +#pragma warning (push) #pragma warning (disable:4091) // a microsoft header has warnings. Very nice. #include #pragma warning (pop) -- cgit v1.2.3 From 4d65539db786056cfa8e43fd841a51b5bc0c7612 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 16 Oct 2019 11:19:29 -0400 Subject: DRTVWR-476: Directly reference LLVivoxVoiceClient::mVivoxPump. The LLEventMailDrop used to communicate with the Vivox coroutine is a member of LLVivoxVoiceClient. We don't need to keep looking it up by its string name in LLEventPumps. --- indra/newview/llvoicevivox.cpp | 80 +++++++++++++++++------------------------- 1 file changed, 33 insertions(+), 47 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index 358396632c..7d9085a214 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -1038,8 +1038,6 @@ bool LLVivoxVoiceClient::provisionVoiceAccount() bool LLVivoxVoiceClient::establishVoiceConnection() { - LLEventPump &voiceConnectPump = LLEventPumps::instance().obtain("vivoxClientPump"); - if (!mVoiceEnabled && mIsInitialized) { LL_WARNS("Voice") << "cannot establish connection; enabled "<mHandle)) ("session", "joined")); - LLEventPumps::instance().post("vivoxClientPump", vivoxevent); + mVivoxPump.post(vivoxevent); // Add the current user as a participant here. participantStatePtr_t participant(session->addParticipant(sipURIFromName(mAccountName))); @@ -3644,7 +3630,7 @@ void LLVivoxVoiceClient::leftAudioSession(const sessionStatePtr_t &session) LLSD vivoxevent(LLSDMap("handle", LLSD::String(session->mHandle)) ("session", "removed")); - LLEventPumps::instance().post("vivoxClientPump", vivoxevent); + mVivoxPump.post(vivoxevent); } } @@ -3672,7 +3658,7 @@ void LLVivoxVoiceClient::accountLoginStateChangeEvent( case 1: levent["login"] = LLSD::String("account_login"); - LLEventPumps::instance().post("vivoxClientPump", levent); + mVivoxPump.post(levent); break; case 2: break; @@ -3680,7 +3666,7 @@ void LLVivoxVoiceClient::accountLoginStateChangeEvent( case 3: levent["login"] = LLSD::String("account_loggingOut"); - LLEventPumps::instance().post("vivoxClientPump", levent); + mVivoxPump.post(levent); break; case 4: @@ -3693,7 +3679,7 @@ void LLVivoxVoiceClient::accountLoginStateChangeEvent( case 0: levent["login"] = LLSD::String("account_logout"); - LLEventPumps::instance().post("vivoxClientPump", levent); + mVivoxPump.post(levent); break; default: @@ -3728,7 +3714,7 @@ void LLVivoxVoiceClient::mediaCompletionEvent(std::string &sessionGroupHandle, s } if (!result.isUndefined()) - LLEventPumps::instance().post("vivoxClientPump", result); + mVivoxPump.post(result); } void LLVivoxVoiceClient::mediaStreamUpdatedEvent( @@ -6540,7 +6526,7 @@ void LLVivoxVoiceClient::accountGetSessionFontsResponse(int statusCode, const st // receiving the last one. LLSD result(LLSDMap("voice_fonts", LLSD::Boolean(true))); - LLEventPumps::instance().post("vivoxClientPump", result); + mVivoxPump.post(result); } notifyVoiceFontObservers(); mVoiceFontsReceived = true; @@ -6691,7 +6677,7 @@ void LLVivoxVoiceClient::enablePreviewBuffer(bool enable) else result["recplay"] = "quit"; - LLEventPumps::instance().post("vivoxClientPump", result); + mVivoxPump.post(result); if(mCaptureBufferMode && mIsInChannel) { @@ -6712,7 +6698,7 @@ void LLVivoxVoiceClient::recordPreviewBuffer() mCaptureBufferRecording = true; LLSD result(LLSDMap("recplay", "record")); - LLEventPumps::instance().post("vivoxClientPump", result); + mVivoxPump.post(result); } void LLVivoxVoiceClient::playPreviewBuffer(const LLUUID& effect_id) @@ -6735,7 +6721,7 @@ void LLVivoxVoiceClient::playPreviewBuffer(const LLUUID& effect_id) mCaptureBufferPlaying = true; LLSD result(LLSDMap("recplay", "playback")); - LLEventPumps::instance().post("vivoxClientPump", result); + mVivoxPump.post(result); } void LLVivoxVoiceClient::stopPreviewBuffer() @@ -6744,7 +6730,7 @@ void LLVivoxVoiceClient::stopPreviewBuffer() mCaptureBufferPlaying = false; LLSD result(LLSDMap("recplay", "quit")); - LLEventPumps::instance().post("vivoxClientPump", result); + mVivoxPump.post(result); } bool LLVivoxVoiceClient::isPreviewRecording() -- cgit v1.2.3 From 6805e82acdcde9a3f18681427a33a5bc7be7a0a6 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 17 Oct 2019 12:04:02 -0400 Subject: DRTVWR-476: Introduce LLEventMailDrop::discard() (instead of flush()). Overriding virtual LLEventPump::flush() for the semantic of discarding LLEventMailDrop's queued events turns out not to be such a great idea, because LLEventPumps::flush(), which calls every registered LLEventPump's flush() method, is called every mainloop tick. The first time we hit a use case in which we expected LLEventMailDrop to hold queued events across a mainloop tick, we were baffled that they were never delivered. Moving that logic to a separate method specific to LLEventMailDrop resolves that problem. Naming it discard() clarifies its intended functionality. --- indra/newview/llvoicevivox.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index 7d9085a214..1141b29163 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -1488,7 +1488,7 @@ bool LLVivoxVoiceClient::addAndJoinSession(const sessionStatePtr_t &nextSession) // We are about to start a whole new session. Anything that MIGHT still be in our // maildrop is going to be stale and cause us much wailing and gnashing of teeth. // Just flush it all out and start new. - mVivoxPump.flush(); + mVivoxPump.discard(); // It appears that I need to wait for BOTH the SessionGroup.AddSession response and the SessionStateChangeEvent with state 4 // before continuing from this state. They can happen in either order, and if I don't wait for both, things can get stuck. -- cgit v1.2.3 From 253e360062a74cbaf87c7f9dc30ef26bca1697eb Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Tue, 22 Oct 2019 16:36:16 -0400 Subject: DRTVWR-476: Mention LLApp::stepFrame() in LLAppViewer::idle() which performs "by hand" the same sequence of calls found in stepFrame(). Why not simply call stepFrame()? Hysterical reasons? --- indra/newview/llappviewer.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'indra/newview') diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index db2db43ee1..1bba17dc29 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -4610,6 +4610,9 @@ void LLAppViewer::idle() LLFrameTimer::updateFrameTime(); LLFrameTimer::updateFrameCount(); LLEventTimer::updateClass(); + // LLApp::stepFrame() performs the above three calls plus mRunner.run(). + // Not sure why we don't call stepFrame() here, except that LLRunner seems + // completely redundant with LLEventTimer. LLNotificationsUI::LLToast::updateClass(); LLSmoothInterpolation::updateInterpolants(); LLMortician::updateClass(); -- cgit v1.2.3 From 9008124d352a195616bc8e7b88b048f479cdc4c2 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Fri, 25 Oct 2019 06:55:45 -0400 Subject: DRTVWR-476: Keep coroutine-local data on toplevel()'s stack frame. Instead of heap-allocating a CoroData instance per coroutine, storing the pointer in a ptr_map and deleting it from the ptr_map once the fiber_specific_ptr for that coroutine is cleaned up -- just declare a stack instance on the top-level stack frame, the simplest C++ lifespan management. Derive CoroData from LLInstanceTracker to detect potential name collisions and to enumerate instances. Continue registering each coroutine's CoroData instance in our fiber_specific_ptr, but use a no-op deleter function. Make ~LLCoros() directly pump the fiber scheduler a few times, instead of having a special "LLApp" listener. --- indra/newview/llvoicevivox.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index 1141b29163..23214a6998 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -390,7 +390,7 @@ void LLVivoxVoiceClient::init(LLPumpIO *pump) // constructor will set up LLVoiceClient::getInstance() LLVivoxVoiceClient::getInstance()->mPump = pump; -// LLCoros::instance().launch("LLVivoxVoiceClient::voiceControlCoro();", +// LLCoros::instance().launch("LLVivoxVoiceClient::voiceControlCoro", // boost::bind(&LLVivoxVoiceClient::voiceControlCoro, LLVivoxVoiceClient::getInstance())); } @@ -2537,7 +2537,7 @@ void LLVivoxVoiceClient::tuningStart() mTuningMode = true; if (!mIsCoroutineActive) { - LLCoros::instance().launch("LLVivoxVoiceClient::voiceControlCoro();", + LLCoros::instance().launch("LLVivoxVoiceClient::voiceControlCoro", boost::bind(&LLVivoxVoiceClient::voiceControlCoro, LLVivoxVoiceClient::getInstance())); } else if (mIsInChannel) @@ -5132,7 +5132,7 @@ void LLVivoxVoiceClient::setVoiceEnabled(bool enabled) if (!mIsCoroutineActive) { - LLCoros::instance().launch("LLVivoxVoiceClient::voiceControlCoro();", + LLCoros::instance().launch("LLVivoxVoiceClient::voiceControlCoro", boost::bind(&LLVivoxVoiceClient::voiceControlCoro, LLVivoxVoiceClient::getInstance())); } else -- cgit v1.2.3 From f80b2da513b431b063c74a353d44ffc4a76fa24e Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Mon, 28 Oct 2019 14:40:20 -0400 Subject: DRTVWR-476: Add diagnostic output to llviewerjoystick.cpp. Add ndof_dump_list() call, to enumerate available devices, when ndof_init_first() returns failure. Add "joystick" tags to existing LL_INFOS() (etc.) calls in llviewerjoystick.cpp to make it easier to enable and disable such log messages. Add a specialized operator<<() function to log the contents of an NDOF_Device struct. Add a couple LL_DEBUGS() calls for more visibility into library operations. --- indra/newview/llviewerjoystick.cpp | 69 ++++++++++++++++++++++++++++++-------- 1 file changed, 55 insertions(+), 14 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llviewerjoystick.cpp b/indra/newview/llviewerjoystick.cpp index e44d80b7ce..320bd04fe8 100644 --- a/indra/newview/llviewerjoystick.cpp +++ b/indra/newview/llviewerjoystick.cpp @@ -62,6 +62,43 @@ F32 LLViewerJoystick::sDelta[] = {0,0,0,0,0,0,0}; #define MAX_SPACENAVIGATOR_INPUT 3000.0f #define MAX_JOYSTICK_INPUT_VALUE MAX_SPACENAVIGATOR_INPUT +#if LIB_NDOF +std::ostream& operator<<(std::ostream& out, NDOF_Device* ptr) +{ + if (! ptr) + { + return out << "nullptr"; + } + out << "NDOF_Device{ "; + out << "axes ["; + const char* delim = ""; + for (short axis = 0; axis < ptr->axes_count; ++axis) + { + out << delim << ptr->axes[axis]; + delim = ", "; + } + out << "]"; + out << ", buttons ["; + delim = ""; + for (short button = 0; button < ptr->btn_count; ++button) + { + out << delim << ptr->buttons[button]; + delim = ", "; + } + out << "]"; + out << ", range " << ptr->axes_min << ':' << ptr->axes_max; + // If we don't coerce these to unsigned, they're streamed as characters, + // e.g. ctrl-A or nul. + out << ", absolute " << unsigned(ptr->absolute); + out << ", valid " << unsigned(ptr->valid); + out << ", manufacturer '" << ptr->manufacturer << "'"; + out << ", product '" << ptr->product << "'"; + out << ", private " << ptr->private_data; + out << " }"; + return out; +} +#endif // LIB_NDOF + // ----------------------------------------------------------------------------- void LLViewerJoystick::updateEnabled(bool autoenable) { @@ -107,11 +144,11 @@ NDOF_HotPlugResult LLViewerJoystick::HotPlugAddCallback(NDOF_Device *dev) LLViewerJoystick* joystick(LLViewerJoystick::getInstance()); if (joystick->mDriverState == JDS_UNINITIALIZED) { - LL_INFOS() << "HotPlugAddCallback: will use device:" << LL_ENDL; + LL_INFOS("joystick") << "HotPlugAddCallback: will use device:" << LL_ENDL; ndof_dump(dev); joystick->mNdofDev = dev; - joystick->mDriverState = JDS_INITIALIZED; - res = NDOF_KEEP_HOTPLUGGED; + joystick->mDriverState = JDS_INITIALIZED; + res = NDOF_KEEP_HOTPLUGGED; } joystick->updateEnabled(true); return res; @@ -125,7 +162,7 @@ void LLViewerJoystick::HotPlugRemovalCallback(NDOF_Device *dev) LLViewerJoystick* joystick(LLViewerJoystick::getInstance()); if (joystick->mNdofDev == dev) { - LL_INFOS() << "HotPlugRemovalCallback: joystick->mNdofDev=" + LL_INFOS("joystick") << "HotPlugRemovalCallback: joystick->mNdofDev=" << joystick->mNdofDev << "; removed device:" << LL_ENDL; ndof_dump(dev); joystick->mDriverState = JDS_UNINITIALIZED; @@ -193,6 +230,7 @@ void LLViewerJoystick::init(bool autoenable) { if (mNdofDev) { + LL_DEBUGS("joystick") << "ndof_create() returned: " << mNdofDev << LL_ENDL; // Different joysticks will return different ranges of raw values. // Since we want to handle every device in the same uniform way, // we initialize the mNdofDev struct and we set the range @@ -211,16 +249,19 @@ void LLViewerJoystick::init(bool autoenable) // just have the absolute values instead. mNdofDev->absolute = 1; + LL_DEBUGS("joystick") << "ndof_init_first() received: " << mNdofDev << LL_ENDL; // init & use the first suitable NDOF device found on the USB chain if (ndof_init_first(mNdofDev, NULL)) { mDriverState = JDS_UNINITIALIZED; - LL_WARNS() << "ndof_init_first FAILED" << LL_ENDL; + LL_WARNS("joystick") << "ndof_init_first FAILED" << LL_ENDL; + ndof_dump_list(); } else { mDriverState = JDS_INITIALIZED; } + LL_DEBUGS("joystick") << "ndof_init_first() left: " << mNdofDev << LL_ENDL; } else { @@ -258,8 +299,8 @@ void LLViewerJoystick::init(bool autoenable) { // No device connected, don't change any settings } - - LL_INFOS() << "ndof: mDriverState=" << mDriverState << "; mNdofDev=" + + LL_INFOS("joystick") << "ndof: mDriverState=" << mDriverState << "; mNdofDev=" << mNdofDev << "; libinit=" << libinit << LL_ENDL; #endif } @@ -270,7 +311,7 @@ void LLViewerJoystick::terminate() #if LIB_NDOF ndof_libcleanup(); - LL_INFOS() << "Terminated connection with NDOF device." << LL_ENDL; + LL_INFOS("joystick") << "Terminated connection with NDOF device." << LL_ENDL; mDriverState = JDS_UNINITIALIZED; #endif } @@ -1075,7 +1116,7 @@ std::string LLViewerJoystick::getDescription() bool LLViewerJoystick::isLikeSpaceNavigator() const { -#if LIB_NDOF +#if LIB_NDOF return (isJoystickInitialized() && (strncmp(mNdofDev->product, "SpaceNavigator", 14) == 0 || strncmp(mNdofDev->product, "SpaceExplorer", 13) == 0 @@ -1099,10 +1140,10 @@ void LLViewerJoystick::setSNDefaults() const float platformScaleAvXZ = 2.f; const bool is_3d_cursor = true; #endif - + //gViewerWindow->alertXml("CacheWillClear"); - LL_INFOS() << "restoring SpaceNavigator defaults..." << LL_ENDL; - + LL_INFOS("joystick") << "restoring SpaceNavigator defaults..." << LL_ENDL; + gSavedSettings.setS32("JoystickAxis0", 1); // z (at) gSavedSettings.setS32("JoystickAxis1", 0); // x (slide) gSavedSettings.setS32("JoystickAxis2", 2); // y (up) @@ -1110,11 +1151,11 @@ void LLViewerJoystick::setSNDefaults() gSavedSettings.setS32("JoystickAxis4", 3); // roll gSavedSettings.setS32("JoystickAxis5", 5); // yaw gSavedSettings.setS32("JoystickAxis6", -1); - + gSavedSettings.setBOOL("Cursor3D", is_3d_cursor); gSavedSettings.setBOOL("AutoLeveling", true); gSavedSettings.setBOOL("ZoomDirect", false); - + gSavedSettings.setF32("AvatarAxisScale0", 1.f * platformScaleAvXZ); gSavedSettings.setF32("AvatarAxisScale1", 1.f * platformScaleAvXZ); gSavedSettings.setF32("AvatarAxisScale2", 1.f); -- cgit v1.2.3 From ec208ddfacd25409be49fbec00943c79dd24345f Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 30 Oct 2019 11:18:12 -0400 Subject: DRTVWR-476: Defend against late ~LLWatchdogTimeout() calls. LLAppViewer's heap LLWatchdogTimeout might be destroyed very late -- as late as in LLAppViewer's destructor. By that time, LLAppViewer::cleanup() has already called LLSingletonBase::deleteAll(), destroying the LLWatchdog LLSingleton instance. But LLWatchdogTimeout isa LLWatchdogEntry, and ~LLWatchdogEntry() calls stop(), and stop() tries to remove that instance from LLWatchdog, thus inadvertently resurrecting the deleted LLWatchdog. Which is pointless because the resurrected LLWatchdog has never heard of the LLWatchdogTimeout instance trying to remove itself. Defend LLWatchdogEntry::stop() against the case in which LLWatchdog has already been deleted. --- indra/newview/llwatchdog.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/llwatchdog.cpp b/indra/newview/llwatchdog.cpp index dd6c77ca7d..6273f10c69 100644 --- a/indra/newview/llwatchdog.cpp +++ b/indra/newview/llwatchdog.cpp @@ -91,7 +91,11 @@ void LLWatchdogEntry::start() void LLWatchdogEntry::stop() { - LLWatchdog::getInstance()->remove(this); + // this can happen very late in the shutdown sequence + if (! LLWatchdog::wasDeleted()) + { + LLWatchdog::getInstance()->remove(this); + } } // LLWatchdogTimeout -- cgit v1.2.3 From 6e093662571195dbca8ba13027beeeb4afe88de6 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 30 Oct 2019 12:44:31 -0400 Subject: DRTVWR-476: Update llviewerjoystick.cpp for updated libndofdev API. --- indra/newview/llviewerjoystick.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llviewerjoystick.cpp b/indra/newview/llviewerjoystick.cpp index 320bd04fe8..3d06c95080 100644 --- a/indra/newview/llviewerjoystick.cpp +++ b/indra/newview/llviewerjoystick.cpp @@ -145,7 +145,7 @@ NDOF_HotPlugResult LLViewerJoystick::HotPlugAddCallback(NDOF_Device *dev) if (joystick->mDriverState == JDS_UNINITIALIZED) { LL_INFOS("joystick") << "HotPlugAddCallback: will use device:" << LL_ENDL; - ndof_dump(dev); + ndof_dump(stderr, dev); joystick->mNdofDev = dev; joystick->mDriverState = JDS_INITIALIZED; res = NDOF_KEEP_HOTPLUGGED; @@ -164,7 +164,7 @@ void LLViewerJoystick::HotPlugRemovalCallback(NDOF_Device *dev) { LL_INFOS("joystick") << "HotPlugRemovalCallback: joystick->mNdofDev=" << joystick->mNdofDev << "; removed device:" << LL_ENDL; - ndof_dump(dev); + ndof_dump(stderr, dev); joystick->mDriverState = JDS_UNINITIALIZED; } joystick->updateEnabled(true); @@ -255,7 +255,7 @@ void LLViewerJoystick::init(bool autoenable) { mDriverState = JDS_UNINITIALIZED; LL_WARNS("joystick") << "ndof_init_first FAILED" << LL_ENDL; - ndof_dump_list(); + ndof_dump_list(stderr); } else { -- cgit v1.2.3 From 235b37bb761082b19266bc51e44ae44b21ad1188 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 31 Oct 2019 08:13:00 -0400 Subject: DRTVWR-476: Update to VS 2017 versions of runtime DLLs. Also forget obsolete references to VS 2010 runtime DLLs. --- indra/newview/CMakeLists.txt | 6 ------ indra/newview/viewer_manifest.py | 12 ++++++------ 2 files changed, 6 insertions(+), 12 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 0ba3b07566..d7e10f610b 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -1791,12 +1791,6 @@ if (WINDOWS) ${SHARED_LIB_STAGING_DIR}/Release/openjpeg.dll ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/openjpeg.dll ${SHARED_LIB_STAGING_DIR}/Debug/openjpegd.dll - ${SHARED_LIB_STAGING_DIR}/Release/msvcr100.dll - ${SHARED_LIB_STAGING_DIR}/Release/msvcp100.dll - ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/msvcr100.dll - ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/msvcp100.dll - ${SHARED_LIB_STAGING_DIR}/Debug/msvcr100d.dll - ${SHARED_LIB_STAGING_DIR}/Debug/msvcp100d.dll ${SHARED_LIB_STAGING_DIR}/Release/libhunspell.dll ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/libhunspell.dll ${SHARED_LIB_STAGING_DIR}/Debug/libhunspell.dll diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index a403760670..ea8c341e97 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -528,11 +528,11 @@ class WindowsManifest(ViewerManifest): # These need to be installed as a SxS assembly, currently a 'private' assembly. # See http://msdn.microsoft.com/en-us/library/ms235291(VS.80).aspx if self.args['configuration'].lower() == 'debug': - self.path("msvcr120d.dll") - self.path("msvcp120d.dll") + self.path("msvcr150d.dll") + self.path("msvcp150d.dll") else: - self.path("msvcr120.dll") - self.path("msvcp120.dll") + self.path("msvcr150.dll") + self.path("msvcp150.dll") # SLVoice executable with self.prefix(src=os.path.join(pkgdir, 'bin', 'release')): @@ -606,8 +606,8 @@ class WindowsManifest(ViewerManifest): # MSVC DLLs needed for CEF and have to be in same directory as plugin with self.prefix(src=os.path.join(self.args['build'], os.pardir, 'sharedlibs', 'Release')): - self.path("msvcp120.dll") - self.path("msvcr120.dll") + self.path("msvcp150.dll") + self.path("msvcr150.dll") # CEF files common to all configurations with self.prefix(src=os.path.join(pkgdir, 'resources')): -- cgit v1.2.3 From e9ef66815766d87949e35498a0883286142c9665 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 31 Oct 2019 09:06:09 -0400 Subject: DRTVWR-476: Correct runtime DLL names for VS 2017. --- indra/newview/viewer_manifest.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index ea8c341e97..292b8b9122 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -528,11 +528,11 @@ class WindowsManifest(ViewerManifest): # These need to be installed as a SxS assembly, currently a 'private' assembly. # See http://msdn.microsoft.com/en-us/library/ms235291(VS.80).aspx if self.args['configuration'].lower() == 'debug': - self.path("msvcr150d.dll") - self.path("msvcp150d.dll") + self.path("msvcr140d.dll") + self.path("msvcp140d.dll") else: - self.path("msvcr150.dll") - self.path("msvcp150.dll") + self.path("msvcr140.dll") + self.path("msvcp140.dll") # SLVoice executable with self.prefix(src=os.path.join(pkgdir, 'bin', 'release')): @@ -606,8 +606,8 @@ class WindowsManifest(ViewerManifest): # MSVC DLLs needed for CEF and have to be in same directory as plugin with self.prefix(src=os.path.join(self.args['build'], os.pardir, 'sharedlibs', 'Release')): - self.path("msvcp150.dll") - self.path("msvcr150.dll") + self.path("msvcp140.dll") + self.path("msvcr140.dll") # CEF files common to all configurations with self.prefix(src=os.path.join(pkgdir, 'resources')): -- cgit v1.2.3 From e9a75ad31ccfb2e97d5d7bab2dec680e5b52f9a5 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 31 Oct 2019 09:14:43 -0400 Subject: DRTVWR-476: Throw some more Microsoft runtime DLLs at the viewer. --- indra/newview/viewer_manifest.py | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'indra/newview') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 292b8b9122..bff18afd53 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -531,8 +531,14 @@ class WindowsManifest(ViewerManifest): self.path("msvcr140d.dll") self.path("msvcp140d.dll") else: + # SL-12205: For reasons not yet diagnosed, an early build of + # the VS 2017 viewer requires VS 2013 runtime DLLs as well as + # VS 2017 runtime DLLs. + self.path("msvcr120.dll") + self.path("msvcp120.dll") self.path("msvcr140.dll") self.path("msvcp140.dll") + self.path("vcruntime140.dll") # SLVoice executable with self.prefix(src=os.path.join(pkgdir, 'bin', 'release')): @@ -606,8 +612,11 @@ class WindowsManifest(ViewerManifest): # MSVC DLLs needed for CEF and have to be in same directory as plugin with self.prefix(src=os.path.join(self.args['build'], os.pardir, 'sharedlibs', 'Release')): + self.path("msvcp120.dll") + self.path("msvcr120.dll") self.path("msvcp140.dll") self.path("msvcr140.dll") + self.path("vcruntime140.dll") # CEF files common to all configurations with self.prefix(src=os.path.join(pkgdir, 'resources')): -- cgit v1.2.3 From 70a63ca331484575fbd6ffb432e40f6555bb8a51 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 31 Oct 2019 13:54:51 -0400 Subject: DRTVWR-476, SL-12205: Update to glod built with VS 2017 runtime libs. --- indra/newview/viewer_manifest.py | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index bff18afd53..57099f8ac9 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -527,18 +527,8 @@ class WindowsManifest(ViewerManifest): # These need to be installed as a SxS assembly, currently a 'private' assembly. # See http://msdn.microsoft.com/en-us/library/ms235291(VS.80).aspx - if self.args['configuration'].lower() == 'debug': - self.path("msvcr140d.dll") - self.path("msvcp140d.dll") - else: - # SL-12205: For reasons not yet diagnosed, an early build of - # the VS 2017 viewer requires VS 2013 runtime DLLs as well as - # VS 2017 runtime DLLs. - self.path("msvcr120.dll") - self.path("msvcp120.dll") - self.path("msvcr140.dll") - self.path("msvcp140.dll") - self.path("vcruntime140.dll") + self.path("msvcp140.dll") + self.path("vcruntime140.dll") # SLVoice executable with self.prefix(src=os.path.join(pkgdir, 'bin', 'release')): @@ -612,10 +602,7 @@ class WindowsManifest(ViewerManifest): # MSVC DLLs needed for CEF and have to be in same directory as plugin with self.prefix(src=os.path.join(self.args['build'], os.pardir, 'sharedlibs', 'Release')): - self.path("msvcp120.dll") - self.path("msvcr120.dll") self.path("msvcp140.dll") - self.path("msvcr140.dll") self.path("vcruntime140.dll") # CEF files common to all configurations -- cgit v1.2.3 From 71f6f43a320e9b3538d86035f01a5279340547e5 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Fri, 1 Nov 2019 10:23:31 -0400 Subject: DRTVWR-476: Annotate Mani's plea from 2009 with a suggested solution. However, this is not the right moment to perform that refactoring. --- indra/newview/CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'indra/newview') diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index d7e10f610b..522b97f9d3 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -1773,6 +1773,11 @@ if (WINDOWS) # be met. I'm looking forward to a source-code split-up project next year that will address this kind of thing. # In the meantime, if you have any ideas on how to easily maintain one list, either here or in viewer_manifest.py # and have the build deps get tracked *please* tell me about it. + # nat: https://cmake.org/cmake/help/v3.14/command/file.html + # "For example, the code + # file(STRINGS myfile.txt myfile) + # stores a list in the variable myfile in which each item is a line from the input file." + # And of course it's straightforward to read a text file in Python. set(COPY_INPUT_DEPENDENCIES # The following commented dependencies are determined at variably at build time. Can't do this here. -- cgit v1.2.3 From 5918620426fd81944e6d3eb2a866d2104ad4ae69 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Fri, 1 Nov 2019 10:48:38 -0400 Subject: DRTVWR-476: Make viewer_manifest.py report its own command line. That way, if there's a problem, a developer can rerun the same command. --- indra/newview/viewer_manifest.py | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'indra/newview') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 57099f8ac9..2b412d01b7 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -1548,6 +1548,11 @@ class Linux_x86_64_Manifest(LinuxManifest): ################################################################ if __name__ == "__main__": + # Report our own command line so that, in case of trouble, a developer can + # manually rerun the same command. + print('%s \\\n%s' % + (sys.executable, + ' '.join((("'%s'" % arg) if ' ' in arg else arg) for arg in sys.argv))) extra_arguments = [ dict(name='bugsplat', description="""BugSplat database to which to post crashes, if BugSplat crash reporting is desired""", default=''), -- cgit v1.2.3 From c91e5e3a2417e64da6f6404481741f211768eadd Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Fri, 15 Nov 2019 10:38:23 -0500 Subject: DRTVWR-476: Remove diagnostics around 'SetFile -a V' commands. Earlier versions of macOS manifested frustrating problems in finishing the built package. Those build steps seem to have been behaving better for a few years now. Eliminate (what we fervently hope has become) a bit of ancient cruft. --- indra/newview/viewer_manifest.py | 20 -------------------- 1 file changed, 20 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 2b412d01b7..e647ce3efb 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -1201,11 +1201,6 @@ class DarwinManifest(ViewerManifest): devfile = re.search("/dev/disk([0-9]+)[^s]", hdi_output).group(0).strip() volpath = re.search('HFS\s+(.+)', hdi_output).group(1).strip() - if devfile != '/dev/disk1': - # adding more debugging info based upon nat's hunches to the - # logs to help track down 'SetFile -a V' failures -brad - print "WARNING: 'SetFile -a V' command below is probably gonna fail" - # Copy everything in to the mounted .dmg app_name = self.app_name() @@ -1233,21 +1228,6 @@ class DarwinManifest(ViewerManifest): # Hide the background image, DS_Store file, and volume icon file (set their "visible" bit) for f in ".VolumeIcon.icns", "background.jpg", ".DS_Store": pathname = os.path.join(volpath, f) - # We've observed mysterious "no such file" failures of the SetFile - # command, especially on the first file listed above -- yet - # subsequent inspection of the target directory confirms it's - # there. Timing problem with copy command? Try to handle. - for x in xrange(3): - if os.path.exists(pathname): - print "Confirmed existence: %r" % pathname - break - print "Waiting for %s copy command to complete (%s)..." % (f, x+1) - sys.stdout.flush() - time.sleep(1) - # If we fall out of the loop above without a successful break, oh - # well, possibly we've mistaken the nature of the problem. In any - # case, don't hang up the whole build looping indefinitely, let - # the original problem manifest by executing the desired command. self.run_command(['SetFile', '-a', 'V', pathname]) # Create the alias file (which is a resource file) from the .r -- cgit v1.2.3 From 582f9e156ebaf55f076edaad52fce39b79dac388 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Fri, 15 Nov 2019 10:43:17 -0500 Subject: DRTVWR-476: Have to package libhunspell dylib now, not .a lib. --- indra/newview/viewer_manifest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index e647ce3efb..94908d201a 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -952,7 +952,7 @@ class DarwinManifest(ViewerManifest): with self.prefix(src=relpkgdir, dst=""): self.path("libndofdev.dylib") - self.path("libhunspell-1.3.a") + self.path("libhunspell-*.dylib") with self.prefix(src_dst="cursors_mac"): self.path("*.tif") -- cgit v1.2.3 From 2a56ab44360aa49bd0df9281efc8a8a97a510013 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Fri, 22 Nov 2019 11:58:27 -0500 Subject: DRTVWR-476, SL-12197: Don't throw Stopping from main coroutine. The new LLCoros::Stop exception is intended to terminate long-lived coroutines -- not interrupt mainstream shutdown processing. Only throw it on an explicitly-launched coroutine. Make LLCoros::getName() (used by the above test) static. As with other LLCoros methods, it might be called after the LLCoros LLSingleton instance has been deleted. Requiring the caller to call instance() implies a possible need to also call wasDeleted(). Encapsulate that nuance into a static method instead. --- indra/newview/llaccountingcostmanager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llaccountingcostmanager.cpp b/indra/newview/llaccountingcostmanager.cpp index 1dddf52961..e09527a34b 100644 --- a/indra/newview/llaccountingcostmanager.cpp +++ b/indra/newview/llaccountingcostmanager.cpp @@ -48,7 +48,7 @@ LLAccountingCostManager::LLAccountingCostManager() void LLAccountingCostManager::accountingCostCoro(std::string url, eSelectionType selectionType, const LLHandle observerHandle) { - LL_DEBUGS("LLAccountingCostManager") << "Entering coroutine " << LLCoros::instance().getName() + LL_DEBUGS("LLAccountingCostManager") << "Entering coroutine " << LLCoros::getName() << " with url '" << url << LL_ENDL; LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); @@ -158,7 +158,7 @@ void LLAccountingCostManager::accountingCostCoro(std::string url, } catch (...) { - LOG_UNHANDLED_EXCEPTION(STRINGIZE("coroutine " << LLCoros::instance().getName() + LOG_UNHANDLED_EXCEPTION(STRINGIZE("coroutine " << LLCoros::getName() << "('" << url << "')")); throw; } -- cgit v1.2.3 From 1c62f52af83aa6e6684f5d1f496d8095c7ca321f Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 18 Dec 2019 15:29:23 -0500 Subject: DRTVWR-476: LLChannelManager depends on LLUI. Tell LLSingleton. --- indra/newview/llchannelmanager.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/llchannelmanager.cpp b/indra/newview/llchannelmanager.cpp index 0b7b9cbbc7..9e7a8ba95c 100644 --- a/indra/newview/llchannelmanager.cpp +++ b/indra/newview/llchannelmanager.cpp @@ -48,11 +48,18 @@ LLChannelManager::LLChannelManager() LLAppViewer::instance()->setOnLoginCompletedCallback(boost::bind(&LLChannelManager::onLoginCompleted, this)); mChannelList.clear(); mStartUpChannel = NULL; - + if(!gViewerWindow) { LL_ERRS() << "LLChannelManager::LLChannelManager() - viwer window is not initialized yet" << LL_ENDL; } + + // We don't actually need this instance right now, but our + // cleanupSingleton() method deletes LLScreenChannels, which need to + // unregister from LLUI. Calling LLUI::instance() here establishes the + // dependency so LLSingletonBase::deleteAll() calls our deleteSingleton() + // before LLUI::deleteSingleton(). + LLUI::instance(); } //-------------------------------------------------------------------------- -- cgit v1.2.3 From 9d5d257ceeb8297bcd8ac17164b6584717b5c024 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Thu, 14 May 2020 16:58:33 -0400 Subject: DRTVWR-476, SL-12204: Fix crash in Marketplace Listings. The observed crash was due to sharing a stateful global resource (the global LLMessageSystem instance) between different tasks. Specifically, a coroutine sets its mMessageReader one way, expecting that value to persist until it's done with message parsing, but another coroutine sneaks in at a suspension point and sets it differently. Introduce LockMessageReader and LockMessageChecker classes, which must be instantiated by a consumer of the resource. The constructor of each locks a coroutine-aware mutex, so that for the lifetime of the lock object no other coroutine can instantiate another. Refactor the code so that LLMessageSystem::mMessageReader can only be modified by LockMessageReader, not by direct assignment. mMessageReader is now an instance of LLMessageReaderPointer, which supports dereferencing and comparison but not assignment. Only LockMessageReader can change its value. LockMessageReader addresses the use case in which the specific mMessageReader value need only persist for the duration of a single method call. Add an instance in LLMessageHandlerBridge::post(). LockMessageChecker is a subclass of LockMessageReader: both lock the same mutex. LockMessageChecker addresses the use case in which the specific mMessageReader value must persist across multiple method calls. Modify the methods in question to require a LockMessageChecker instance. Provide LockMessageChecker forwarding methods to facilitate calling the underlying LLMessageSystem methods via the LockMessageChecker instance. Add LockMessageChecker instances to LLAppViewer::idleNetwork(), a couple cases in idle_startup() and LLMessageSystem::establishBidirectionalTrust(). --- indra/newview/llappviewer.cpp | 49 +++++++++++++++++++++++-------------------- indra/newview/llstartup.cpp | 42 ++++++++++++++++++++----------------- 2 files changed, 49 insertions(+), 42 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 65bfcec8c4..70d3c10524 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -5250,37 +5250,40 @@ void LLAppViewer::idleNetwork() const S64 frame_count = gFrameCount; // U32->S64 F32 total_time = 0.0f; - while (gMessageSystem->checkAllMessages(frame_count, gServicePump)) { - if (gDoDisconnect) + LockMessageChecker lmc(gMessageSystem); + while (lmc.checkAllMessages(frame_count, gServicePump)) { - // We're disconnecting, don't process any more messages from the server - // We're usually disconnecting due to either network corruption or a - // server going down, so this is OK. - break; - } + if (gDoDisconnect) + { + // We're disconnecting, don't process any more messages from the server + // We're usually disconnecting due to either network corruption or a + // server going down, so this is OK. + break; + } - total_decoded++; - gPacketsIn++; + total_decoded++; + gPacketsIn++; - if (total_decoded > MESSAGE_MAX_PER_FRAME) - { - break; - } + if (total_decoded > MESSAGE_MAX_PER_FRAME) + { + break; + } #ifdef TIME_THROTTLE_MESSAGES - // Prevent slow packets from completely destroying the frame rate. - // This usually happens due to clumps of avatars taking huge amount - // of network processing time (which needs to be fixed, but this is - // a good limit anyway). - total_time = check_message_timer.getElapsedTimeF32(); - if (total_time >= CheckMessagesMaxTime) - break; + // Prevent slow packets from completely destroying the frame rate. + // This usually happens due to clumps of avatars taking huge amount + // of network processing time (which needs to be fixed, but this is + // a good limit anyway). + total_time = check_message_timer.getElapsedTimeF32(); + if (total_time >= CheckMessagesMaxTime) + break; #endif - } + } - // Handle per-frame message system processing. - gMessageSystem->processAcks(gSavedSettings.getF32("AckCollectTime")); + // Handle per-frame message system processing. + lmc.processAcks(gSavedSettings.getF32("AckCollectTime")); + } #ifdef TIME_THROTTLE_MESSAGES if (total_time >= CheckMessagesMaxTime) diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 4d25e8b2a3..ee12c451eb 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -1534,12 +1534,14 @@ bool idle_startup() { LLStartUp::setStartupState( STATE_AGENT_SEND ); } - LLMessageSystem* msg = gMessageSystem; - while (msg->checkAllMessages(gFrameCount, gServicePump)) { - display_startup(); + LockMessageChecker lmc(gMessageSystem); + while (lmc.checkAllMessages(gFrameCount, gServicePump)) + { + display_startup(); + } + lmc.processAcks(); } - msg->processAcks(); display_startup(); return FALSE; } @@ -1589,25 +1591,27 @@ bool idle_startup() //--------------------------------------------------------------------- if (STATE_AGENT_WAIT == LLStartUp::getStartupState()) { - LLMessageSystem* msg = gMessageSystem; - while (msg->checkAllMessages(gFrameCount, gServicePump)) { - if (gAgentMovementCompleted) - { - // Sometimes we have more than one message in the - // queue. break out of this loop and continue - // processing. If we don't, then this could skip one - // or more login steps. - break; - } - else + LockMessageChecker lmc(gMessageSystem); + while (lmc.checkAllMessages(gFrameCount, gServicePump)) { - LL_DEBUGS("AppInit") << "Awaiting AvatarInitComplete, got " - << msg->getMessageName() << LL_ENDL; + if (gAgentMovementCompleted) + { + // Sometimes we have more than one message in the + // queue. break out of this loop and continue + // processing. If we don't, then this could skip one + // or more login steps. + break; + } + else + { + LL_DEBUGS("AppInit") << "Awaiting AvatarInitComplete, got " + << gMessageSystem->getMessageName() << LL_ENDL; + } + display_startup(); } - display_startup(); + lmc.processAcks(); } - msg->processAcks(); display_startup(); -- cgit v1.2.3 From 6148a6443af886f9b71b4c88084db943950e146c Mon Sep 17 00:00:00 2001 From: Nicky Dasmijn Date: Tue, 19 May 2020 00:03:19 +0200 Subject: Remove DirectX.cmake. With recent SDKs (dating back to at least VS 2013 and the 8.1 SDK) DirectX is included in the SDK and does not need any special detection logic. --- indra/newview/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index a01e6ee4f6..6f21ec93cc 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -15,7 +15,6 @@ include(BuildPackagesInfo) include(BuildVersion) include(CMakeCopyIfDifferent) include(DBusGlib) -include(DirectX) include(DragDrop) include(EXPAT) include(FMODEX) -- cgit v1.2.3 From e29ba3bbdaf70127944389d3b4910d47dcf02aff Mon Sep 17 00:00:00 2001 From: Nicky Dasmijn Date: Tue, 19 May 2020 19:17:32 +0200 Subject: Remove more traces of find_library to search for DirectX and instead rely on the SDK setup. Remove old dinput8 import library as it is not needed --- indra/newview/CMakeLists.txt | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 6f21ec93cc..460b2e6985 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -1582,20 +1582,12 @@ if (WINDOWS) list(APPEND viewer_SOURCE_FILES ${viewer_RESOURCE_FILES}) endif (NOT USESYSTEMLIBS) - find_library(DINPUT_LIBRARY dinput8 ${DIRECTX_LIBRARY_DIR}) - find_library(DXGUID_LIBRARY dxguid ${DIRECTX_LIBRARY_DIR}) - mark_as_advanced( - DINPUT_LIBRARY - DXGUID_LIBRARY - ) - # see EXP-1765 - theory is opengl32.lib needs to be included before gdi32.lib (windows libs) set(viewer_LIBRARIES opengl32 ${WINDOWS_LIBRARIES} comdlg32 - ${DINPUT_LIBRARY} - ${DXGUID_LIBRARY} + dxguid kernel32 odbc32 odbccp32 -- cgit v1.2.3 From a0356e977d15dd30878f80f5a097b07dd67d3bcd Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 27 May 2020 10:39:20 -0400 Subject: DRTVWR-476: Make LLVivoxVoiceClient::logoutOfVivox() wait for logout. It can happen that we arrive at logoutOfVivox() with some other message queued on the LLEventMailDrop in question. If logoutOfVivox() assumes that other message is logout and exits, then subsequent code gets confused. Introduce a loop to wait (with the existing timeout) for the real logout message. --- indra/newview/llvoicevivox.cpp | 41 ++++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 17 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index 5d0b3e5dd6..27cc19072f 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -338,15 +338,15 @@ LLVivoxVoiceClient::LLVivoxVoiceClient() : mPlayRequestCount(0), mAvatarNameCacheConnection(), - mIsInTuningMode(false), - mIsInChannel(false), - mIsJoiningSession(false), - mIsWaitingForFonts(false), - mIsLoggingIn(false), - mIsLoggedIn(false), - mIsProcessingChannels(false), - mIsCoroutineActive(false), - mVivoxPump("vivoxClientPump") + mIsInTuningMode(false), + mIsInChannel(false), + mIsJoiningSession(false), + mIsWaitingForFonts(false), + mIsLoggingIn(false), + mIsLoggedIn(false), + mIsProcessingChannels(false), + mIsCoroutineActive(false), + mVivoxPump("vivoxClientPump") { mSpeakerVolume = scale_speaker_volume(0); @@ -1255,15 +1255,22 @@ void LLVivoxVoiceClient::logoutOfVivox(bool wait) if (wait) { LLSD timeoutResult(LLSDMap("logout", "timeout")); + LLSD result; - LL_DEBUGS("Voice") - << "waiting for logout response on " - << mVivoxPump.getName() - << LL_ENDL; - - LLSD result = llcoro::suspendUntilEventOnWithTimeout(mVivoxPump, LOGOUT_ATTEMPT_TIMEOUT, timeoutResult); - - LL_DEBUGS("Voice") << "event=" << ll_stream_notation_sd(result) << LL_ENDL; + do + { + LL_DEBUGS("Voice") + << "waiting for logout response on " + << mVivoxPump.getName() + << LL_ENDL; + + result = llcoro::suspendUntilEventOnWithTimeout(mVivoxPump, LOGOUT_ATTEMPT_TIMEOUT, timeoutResult); + + LL_DEBUGS("Voice") << "event=" << ll_stream_notation_sd(result) << LL_ENDL; + // Don't get confused by prior queued events -- note that it's + // very important that mVivoxPump is an LLEventMailDrop, which + // does queue events. + } while (! result["logout"]); } else { -- cgit v1.2.3 From 1f4fbc8d11d37efbd6c2f2336f33b7e2eb010986 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 27 May 2020 12:36:59 -0400 Subject: DRTVWR-476, VOICE-88, SL-13025: Use a new port every SLVoice launch. The observed failure is that SLVoice, on relaunch, produces an error that bind() returned EADDRINUSE and terminates. Using a different port every time we relaunch avoids that collision. --- indra/newview/llvoicevivox.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index 27cc19072f..42a1cf95a7 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -806,6 +806,21 @@ bool LLVivoxVoiceClient::startAndLaunchDaemon() LLProcess::Params params; params.executable = exe_path; + // VOICE-88: Cycle through [portbase..portbase+portrange) on + // successive tries because attempting to relaunch (after manually + // disabling and then re-enabling voice) with the same port can + // cause SLVoice's bind() call to fail with EADDRINUSE. We expect + // that eventually the OS will time out previous ports, which is + // why we cycle instead of incrementing indefinitely. + U32 portbase = gSavedSettings.getU32("VivoxVoicePort"); + static U32 portoffset = 0; + static const U32 portrange = 100; + std::string host(gSavedSettings.getString("VivoxVoiceHost")); + U32 port = portbase + portoffset; + portoffset = (portoffset + 1) % portrange; + params.args.add("-i"); + params.args.add(STRINGIZE(host << ':' << port)); + std::string loglevel = gSavedSettings.getString("VivoxDebugLevel"); if (loglevel.empty()) { @@ -862,7 +877,7 @@ bool LLVivoxVoiceClient::startAndLaunchDaemon() sGatewayPtr = LLProcess::create(params); - mDaemonHost = LLHost(gSavedSettings.getString("VivoxVoiceHost").c_str(), gSavedSettings.getU32("VivoxVoicePort")); + mDaemonHost = LLHost(host.c_str(), port); } else { -- cgit v1.2.3 From e2dd15397c709a3a37e70942d40373f5476a434b Mon Sep 17 00:00:00 2001 From: Rider Linden Date: Wed, 20 May 2020 15:37:21 -0700 Subject: SL-9756: Take the "session_id" from the offline message that was passed. --- indra/newview/llimprocessing.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/llimprocessing.cpp b/indra/newview/llimprocessing.cpp index 6da7bbe263..b534fc0b4a 100644 --- a/indra/newview/llimprocessing.cpp +++ b/indra/newview/llimprocessing.cpp @@ -1608,7 +1608,7 @@ void LLIMProcessing::requestOfflineMessagesCoro(std::string url) message_data["to_agent_id"].asUUID(), IM_OFFLINE, (EInstantMessage)message_data["dialog"].asInteger(), - LLUUID::null, // session id, since there is none we can only use frienship/group invite caps + message_data["session_id"].asUUID(), message_data["timestamp"].asInteger(), message_data["from_agent_name"].asString(), message_data["message"].asString(), -- cgit v1.2.3 From c8b7466c1999cc834b90c9aed76d8548b66032c6 Mon Sep 17 00:00:00 2001 From: Rider Linden Date: Mon, 8 Jun 2020 11:28:05 -0700 Subject: SL-11430, SL-9756: Take transaction-id from offline messages. Correct LLSD names. Use offline flag rather than implicit tests of session_id and aux_id. --- indra/newview/llimprocessing.cpp | 61 +++++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 26 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llimprocessing.cpp b/indra/newview/llimprocessing.cpp index b534fc0b4a..60f1de4e8c 100644 --- a/indra/newview/llimprocessing.cpp +++ b/indra/newview/llimprocessing.cpp @@ -857,7 +857,7 @@ void LLIMProcessing::processNewMessage(LLUUID from_id, } else // IM_TASK_INVENTORY_OFFERED { - if (offline == IM_OFFLINE && session_id.isNull() && aux_id.notNull() && binary_bucket_size > sizeof(S8)* 5) + if (offline) { // cap received offline message std::string str_bucket = ll_safe_string((char*)binary_bucket, binary_bucket_size); @@ -889,9 +889,10 @@ void LLIMProcessing::processNewMessage(LLUUID from_id, info->mIM = dialog; info->mFromID = from_id; info->mFromGroup = from_group; - info->mTransactionID = session_id; info->mFolderID = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(info->mType)); + info->mTransactionID = session_id.notNull() ? session_id : aux_id; + info->mFromName = name; info->mDesc = message; info->mHost = sender; @@ -1569,7 +1570,7 @@ void LLIMProcessing::requestOfflineMessagesCoro(std::string url) return; } - if (gAgent.getRegion() == NULL) + if (!gAgent.getRegion()) { LL_WARNS("Messaging") << "Region null while attempting to load messages." << LL_ENDL; return; @@ -1577,8 +1578,8 @@ void LLIMProcessing::requestOfflineMessagesCoro(std::string url) LL_INFOS("Messaging") << "Processing offline messages." << LL_ENDL; - std::vector data; - S32 binary_bucket_size = 0; +// std::vector data; +// S32 binary_bucket_size = 0; LLHost sender = gAgent.getRegionHost(); LLSD::array_iterator i = messages.beginArray(); @@ -1587,38 +1588,46 @@ void LLIMProcessing::requestOfflineMessagesCoro(std::string url) { const LLSD &message_data(*i); - LLVector3 position(message_data["local_x"].asReal(), message_data["local_y"].asReal(), message_data["local_z"].asReal()); - data = message_data["binary_bucket"].asBinary(); - binary_bucket_size = data.size(); // message_data["count"] always 0 - U32 parent_estate_id = message_data.has("parent_estate_id") ? message_data["parent_estate_id"].asInteger() : 1; // 1 - IMMainland + /* RIDER: Many fields in this message are using a '_' rather than the standard '-'. This + * should be changed but would require tight coordination with the simulator. + */ + LLVector3 position; + if (message_data.has("position")) + { + position.setValue(message_data["position"]); + } + else + { + position.set(message_data["local_x"].asReal(), message_data["local_y"].asReal(), message_data["local_z"].asReal()); + } - // Todo: once dirtsim-369 releases, remove one of the int/str options - BOOL from_group; - if (message_data["from_group"].isInteger()) + std::vector bin_bucket; + if (message_data.has("binary_bucket")) { - from_group = message_data["from_group"].asInteger(); + bin_bucket = message_data["binary_bucket"].asBinary(); } else { - from_group = message_data["from_group"].asString() == "Y"; + bin_bucket.push_back(0); } - LLIMProcessing::processNewMessage(message_data["from_agent_id"].asUUID(), - from_group, + LLIMProcessing::processNewMessage( + message_data["from_id"].asUUID(), + message_data["from_group"].asBoolean(), message_data["to_agent_id"].asUUID(), - IM_OFFLINE, - (EInstantMessage)message_data["dialog"].asInteger(), - message_data["session_id"].asUUID(), - message_data["timestamp"].asInteger(), - message_data["from_agent_name"].asString(), - message_data["message"].asString(), - parent_estate_id, + static_cast(message_data["offline"].asInteger()), + static_cast(message_data["dialog"].asInteger()), + message_data["transaction-id"].asUUID(), + static_cast(message_data["timestamp"].asInteger()), + message_data["from_name"].asString(), + (message_data.has("message")) ? message_data["message"].asString() : std::string(), + static_cast((message_data.has("parent_estate_id")) ? message_data["parent_estate_id"].asInteger() : 1), // 1 - IMMainland message_data["region_id"].asUUID(), position, - &data[0], - binary_bucket_size, + bin_bucket.data(), + bin_bucket.size(), sender, - message_data["asset_id"].asUUID()); // not necessarily an asset + message_data["asset_id"].asUUID()); } } -- cgit v1.2.3 From f8e53adce7c089abe9a50c353d14f7a548ce3f95 Mon Sep 17 00:00:00 2001 From: Rider Linden Date: Thu, 18 Jun 2020 12:56:00 -0700 Subject: SL-9756: Get session_id/transaction id from aux if session is missing. --- indra/newview/llimprocessing.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'indra/newview') diff --git a/indra/newview/llimprocessing.cpp b/indra/newview/llimprocessing.cpp index 60f1de4e8c..c274267b21 100644 --- a/indra/newview/llimprocessing.cpp +++ b/indra/newview/llimprocessing.cpp @@ -1628,6 +1628,7 @@ void LLIMProcessing::requestOfflineMessagesCoro(std::string url) bin_bucket.size(), sender, message_data["asset_id"].asUUID()); + } } -- cgit v1.2.3 From f72759c16d74d6a996b4b63f610b50c80c3db825 Mon Sep 17 00:00:00 2001 From: Rider Linden Date: Mon, 22 Jun 2020 10:55:05 -0700 Subject: SL-9756: IM_TASK_INVENTORY_OFFERED bucket offline format conforms to the online format. --- indra/newview/llimprocessing.cpp | 32 +++++++------------------------- 1 file changed, 7 insertions(+), 25 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llimprocessing.cpp b/indra/newview/llimprocessing.cpp index c274267b21..a2900c553c 100644 --- a/indra/newview/llimprocessing.cpp +++ b/indra/newview/llimprocessing.cpp @@ -857,33 +857,15 @@ void LLIMProcessing::processNewMessage(LLUUID from_id, } else // IM_TASK_INVENTORY_OFFERED { - if (offline) + if (sizeof(S8) != binary_bucket_size) { - // cap received offline message - std::string str_bucket = ll_safe_string((char*)binary_bucket, binary_bucket_size); - typedef boost::tokenizer > tokenizer; - boost::char_separator sep("|", "", boost::keep_empty_tokens); - tokenizer tokens(str_bucket, sep); - tokenizer::iterator iter = tokens.begin(); - - info->mType = (LLAssetType::EType)(atoi((*(iter++)).c_str())); - // Note There is more elements in 'tokens' ... - - info->mObjectID = LLUUID::null; - info->mFromObject = TRUE; - } - else - { - if (sizeof(S8) != binary_bucket_size) - { - LL_WARNS("Messaging") << "Malformed inventory offer from object" << LL_ENDL; - delete info; - break; - } - info->mType = (LLAssetType::EType) binary_bucket[0]; - info->mObjectID = LLUUID::null; - info->mFromObject = TRUE; + LL_WARNS("Messaging") << "Malformed inventory offer from object" << LL_ENDL; + delete info; + break; } + info->mType = (LLAssetType::EType) binary_bucket[0]; + info->mObjectID = LLUUID::null; + info->mFromObject = TRUE; } info->mIM = dialog; -- cgit v1.2.3 From 01f2308c85dd02d199072006e6b9ff42c90a1986 Mon Sep 17 00:00:00 2001 From: Rider Linden Date: Mon, 22 Jun 2020 16:08:11 -0700 Subject: SL-9756: Get the LLSD names right. --- indra/newview/llimprocessing.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/llimprocessing.cpp b/indra/newview/llimprocessing.cpp index a2900c553c..fc209c2eae 100644 --- a/indra/newview/llimprocessing.cpp +++ b/indra/newview/llimprocessing.cpp @@ -1594,7 +1594,7 @@ void LLIMProcessing::requestOfflineMessagesCoro(std::string url) } LLIMProcessing::processNewMessage( - message_data["from_id"].asUUID(), + message_data["from_agent_id"].asUUID(), message_data["from_group"].asBoolean(), message_data["to_agent_id"].asUUID(), static_cast(message_data["offline"].asInteger()), -- cgit v1.2.3 From 4708662091760f90a7782b726a5a7d89f376ce53 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Tue, 2 Jun 2020 10:29:15 -0400 Subject: SL-13361: Distill redundant create_console() code to set_stream(). There are separate stanzas in llappviewerwin32.cpp's create_console() function for each of STD_INPUT_HANDLE, STD_OUTPUT_HANDLE and STD_ERROR_HANDLE. SL-13361 wants to add more code to each. Factor out new local set_stream() function and make create_console() call it three times. (cherry picked from commit 13b78a0c5a788c617866e3530c65dae616e6520f) --- indra/newview/llappviewerwin32.cpp | 59 +++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 30 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index 9a8a5f16bb..1f66177c37 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -501,11 +501,12 @@ void LLAppViewerWin32::disableWinErrorReporting() const S32 MAX_CONSOLE_LINES = 500; -static bool create_console() -{ - int h_con_handle; - intptr_t l_std_handle; +namespace { + +FILE* set_stream(const char* which, DWORD handle_id, const char* mode); +bool create_console() +{ CONSOLE_SCREEN_BUFFER_INFO coninfo; FILE *fp; @@ -518,50 +519,48 @@ static bool create_console() SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coninfo.dwSize); // redirect unbuffered STDOUT to the console - l_std_handle = reinterpret_cast(GetStdHandle(STD_OUTPUT_HANDLE)); - h_con_handle = _open_osfhandle(l_std_handle, _O_TEXT); - if (h_con_handle == -1) + FILE* fp = set_stream("stdout", STD_OUTPUT_HANDLE, "w"); + if (fp) { - LL_WARNS() << "create_console() failed to open stdout handle" << LL_ENDL; - } - else - { - fp = _fdopen( h_con_handle, "w" ); *stdout = *fp; - setvbuf( stdout, NULL, _IONBF, 0 ); } // redirect unbuffered STDIN to the console - l_std_handle = reinterpret_cast(GetStdHandle(STD_INPUT_HANDLE)); - h_con_handle = _open_osfhandle(l_std_handle, _O_TEXT); - if (h_con_handle == -1) - { - LL_WARNS() << "create_console() failed to open stdin handle" << LL_ENDL; - } - else + fp = set_stream("stdin", STD_INPUT_HANDLE, "r"); + if (fp) { - fp = _fdopen( h_con_handle, "r" ); *stdin = *fp; - setvbuf( stdin, NULL, _IONBF, 0 ); } // redirect unbuffered STDERR to the console - l_std_handle = reinterpret_cast(GetStdHandle(STD_ERROR_HANDLE)); - h_con_handle = _open_osfhandle(l_std_handle, _O_TEXT); + fp = set_stream("stderr", STD_ERROR_HANDLE, "w"); + if (fp) + { + *stderr = *fp; + } + + return isConsoleAllocated; +} + +FILE* set_stream(const char* which, DWORD handle_id, const char* mode) +{ + long l_std_handle = (long)GetStdHandle(handle_id); + int h_con_handle = _open_osfhandle(l_std_handle, _O_TEXT); if (h_con_handle == -1) { - LL_WARNS() << "create_console() failed to open stderr handle" << LL_ENDL; + LL_WARNS() << "create_console() failed to open " << which << " handle" << LL_ENDL; + return nullptr; } else { - fp = _fdopen( h_con_handle, "w" ); - *stderr = *fp; - setvbuf( stderr, NULL, _IONBF, 0 ); + FILE* fp = _fdopen( h_con_handle, mode ); + setvbuf( fp, NULL, _IONBF, 0 ); + return fp; } - - return isConsoleAllocated; } +} // anonymous namespace + LLAppViewerWin32::LLAppViewerWin32(const char* cmd_line) : mCmdLine(cmd_line), mIsConsoleAllocated(false) -- cgit v1.2.3 From d8649dbb8a5a20753248923a25c13f729cadd99a Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Tue, 2 Jun 2020 16:44:22 -0400 Subject: SL-13361: Enable color processing on Windows 10 debug console. (cherry picked from commit 0b61150e698537a7e42a4cdae02496da500399d9) --- indra/newview/llappviewerwin32.cpp | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index 1f66177c37..f0aa355342 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -500,6 +500,10 @@ void LLAppViewerWin32::disableWinErrorReporting() } const S32 MAX_CONSOLE_LINES = 500; +// Only defined in newer SDKs than we currently use +#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING +#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 4 +#endif namespace { @@ -507,13 +511,11 @@ FILE* set_stream(const char* which, DWORD handle_id, const char* mode); bool create_console() { - CONSOLE_SCREEN_BUFFER_INFO coninfo; - FILE *fp; - // allocate a console for this app const bool isConsoleAllocated = AllocConsole(); // set the screen buffer to be big enough to let us scroll text + CONSOLE_SCREEN_BUFFER_INFO coninfo; GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &coninfo); coninfo.dwSize.Y = MAX_CONSOLE_LINES; SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coninfo.dwSize); @@ -542,19 +544,24 @@ bool create_console() return isConsoleAllocated; } -FILE* set_stream(const char* which, DWORD handle_id, const char* mode) +FILE* set_stream(const char* desc, DWORD handle_id, const char* mode) { - long l_std_handle = (long)GetStdHandle(handle_id); - int h_con_handle = _open_osfhandle(l_std_handle, _O_TEXT); + auto l_std_handle = GetStdHandle(handle_id); + int h_con_handle = _open_osfhandle(reinterpret_cast(l_std_handle), _O_TEXT); if (h_con_handle == -1) { - LL_WARNS() << "create_console() failed to open " << which << " handle" << LL_ENDL; + LL_WARNS() << "create_console() failed to open " << desc << " handle" << LL_ENDL; return nullptr; } else { FILE* fp = _fdopen( h_con_handle, mode ); setvbuf( fp, NULL, _IONBF, 0 ); + // Enable color processing on Windows 10 console windows. + DWORD dwMode = 0; + GetConsoleMode(l_std_handle, &dwMode); + dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; + SetConsoleMode(l_std_handle, dwMode); return fp; } } -- cgit v1.2.3 From 01128f9f945f20bc3c472ed953cb0c0fae6ce407 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 1 Jul 2020 16:29:59 -0400 Subject: DRTVWR-476, SL-13528: Use freopen_s() instead of assigning stderr. The llappviewerwin32.cpp create_console() function called by LLAppViewerWin32::initConsole() used to assign *stderr = *(new FILE* value), and so forth for stdout and stdin. That dubious tactic no longer works with the new Windows CRT introduced with VS 2015. freopen_s() works much better. --- indra/newview/llappviewerwin32.cpp | 100 +++++++++++++++++++------------------ 1 file changed, 51 insertions(+), 49 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index f0aa355342..156a1c5893 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -507,63 +507,65 @@ const S32 MAX_CONSOLE_LINES = 500; namespace { -FILE* set_stream(const char* which, DWORD handle_id, const char* mode); +void set_stream(const char* desc, FILE* fp, DWORD handle_id, const char* name, const char* mode="w"); bool create_console() { - // allocate a console for this app - const bool isConsoleAllocated = AllocConsole(); - - // set the screen buffer to be big enough to let us scroll text - CONSOLE_SCREEN_BUFFER_INFO coninfo; - GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &coninfo); - coninfo.dwSize.Y = MAX_CONSOLE_LINES; - SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coninfo.dwSize); - - // redirect unbuffered STDOUT to the console - FILE* fp = set_stream("stdout", STD_OUTPUT_HANDLE, "w"); - if (fp) - { - *stdout = *fp; - } - - // redirect unbuffered STDIN to the console - fp = set_stream("stdin", STD_INPUT_HANDLE, "r"); - if (fp) - { - *stdin = *fp; - } + // allocate a console for this app + const bool isConsoleAllocated = AllocConsole(); - // redirect unbuffered STDERR to the console - fp = set_stream("stderr", STD_ERROR_HANDLE, "w"); - if (fp) - { - *stderr = *fp; - } + if (isConsoleAllocated) + { + // set the screen buffer to be big enough to let us scroll text + CONSOLE_SCREEN_BUFFER_INFO coninfo; + GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &coninfo); + coninfo.dwSize.Y = MAX_CONSOLE_LINES; + SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coninfo.dwSize); + + // redirect unbuffered STDOUT to the console + set_stream("stdout", stdout, STD_OUTPUT_HANDLE, "CONOUT$"); + // redirect unbuffered STDERR to the console + set_stream("stderr", stderr, STD_ERROR_HANDLE, "CONOUT$"); + // redirect unbuffered STDIN to the console + // Don't bother: our console is solely for log output. We never read stdin. +// set_stream("stdin", stdin, STD_INPUT_HANDLE, "CONIN$", "r"); + } - return isConsoleAllocated; + return isConsoleAllocated; } -FILE* set_stream(const char* desc, DWORD handle_id, const char* mode) +void set_stream(const char* desc, FILE* fp, DWORD handle_id, const char* name, const char* mode) { - auto l_std_handle = GetStdHandle(handle_id); - int h_con_handle = _open_osfhandle(reinterpret_cast(l_std_handle), _O_TEXT); - if (h_con_handle == -1) - { - LL_WARNS() << "create_console() failed to open " << desc << " handle" << LL_ENDL; - return nullptr; - } - else - { - FILE* fp = _fdopen( h_con_handle, mode ); - setvbuf( fp, NULL, _IONBF, 0 ); - // Enable color processing on Windows 10 console windows. - DWORD dwMode = 0; - GetConsoleMode(l_std_handle, &dwMode); - dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; - SetConsoleMode(l_std_handle, dwMode); - return fp; - } + // SL-13528: This code used to be based on + // http://dslweb.nwnexus.com/~ast/dload/guicon.htm + // (referenced in https://stackoverflow.com/a/191880). + // But one of the comments on that StackOverflow answer points out that + // assigning to *stdout or *stderr "probably doesn't even work with the + // Universal CRT that was introduced in 2015," suggesting freopen_s() + // instead. Code below is based on https://stackoverflow.com/a/55875595. + auto std_handle = GetStdHandle(handle_id); + if (std_handle == INVALID_HANDLE_VALUE) + { + LL_WARNS() << "create_console() failed to get " << desc << " handle" << LL_ENDL; + } + else + { + if (mode == std::string("w")) + { + // Enable color processing on Windows 10 console windows. + DWORD dwMode = 0; + GetConsoleMode(std_handle, &dwMode); + dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; + SetConsoleMode(std_handle, dwMode); + } + // Redirect the passed fp to the console. + FILE* ignore; + if (freopen_s(&ignore, name, mode, fp) == 0) + { + // use unbuffered I/O + setvbuf( fp, NULL, _IONBF, 0 ); + } + } } } // anonymous namespace -- cgit v1.2.3 From 766b21a0a624ffb75c06801cf8ea3573e6dc4b5d Mon Sep 17 00:00:00 2001 From: Rider Linden Date: Wed, 1 Jul 2020 16:52:44 -0700 Subject: SL-13533: Use the old name for from_agent_name SL-13540: Do not fail if binary bucket is too large, attempt to extract the asset type from the old style bucket. Notification still not shown. --- indra/newview/llimprocessing.cpp | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llimprocessing.cpp b/indra/newview/llimprocessing.cpp index fc209c2eae..301b4c9214 100644 --- a/indra/newview/llimprocessing.cpp +++ b/indra/newview/llimprocessing.cpp @@ -857,13 +857,28 @@ void LLIMProcessing::processNewMessage(LLUUID from_id, } else // IM_TASK_INVENTORY_OFFERED { - if (sizeof(S8) != binary_bucket_size) + if (sizeof(S8) == binary_bucket_size) { - LL_WARNS("Messaging") << "Malformed inventory offer from object" << LL_ENDL; - delete info; - break; + info->mType = (LLAssetType::EType) binary_bucket[0]; + } + else + { + /*RIDER*/ // The previous version of the protocol returned the wrong binary bucket... we + // still might be able to figure out the type... even though the offer is not retrievable. + std::string str_bucket(reinterpret_cast(binary_bucket)); + std::string str_type(str_bucket.substr(0, str_bucket.find('|'))); + + std::stringstream type_convert(str_type); + + S32 type; + type_convert >> type; + + // We could try AT_UNKNOWN which would be more accurate, but that causes an auto decline + info->mType = static_cast(type); + // Don't break in the case of a bad binary bucket. Go ahead and show the + // accept/decline popup even though it will not do anything. + LL_WARNS("Messaging") << "Malformed inventory offer from object, type might be " << info->mType << LL_ENDL; } - info->mType = (LLAssetType::EType) binary_bucket[0]; info->mObjectID = LLUUID::null; info->mFromObject = TRUE; } @@ -1601,8 +1616,8 @@ void LLIMProcessing::requestOfflineMessagesCoro(std::string url) static_cast(message_data["dialog"].asInteger()), message_data["transaction-id"].asUUID(), static_cast(message_data["timestamp"].asInteger()), - message_data["from_name"].asString(), - (message_data.has("message")) ? message_data["message"].asString() : std::string(), + message_data["from_agent_name"].asString(), + message_data["message"].asString(), static_cast((message_data.has("parent_estate_id")) ? message_data["parent_estate_id"].asInteger() : 1), // 1 - IMMainland message_data["region_id"].asUUID(), position, -- cgit v1.2.3 From bf5585c0ec9d6c2159a203ebdbd1b639689a5c50 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 2 Jul 2020 13:03:57 +0300 Subject: SL-13540 Offline scripted inventory offers not shown on non drtsim-451 --- indra/newview/llimprocessing.cpp | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) (limited to 'indra/newview') diff --git a/indra/newview/llimprocessing.cpp b/indra/newview/llimprocessing.cpp index 301b4c9214..5c9d53e0b9 100644 --- a/indra/newview/llimprocessing.cpp +++ b/indra/newview/llimprocessing.cpp @@ -865,6 +865,8 @@ void LLIMProcessing::processNewMessage(LLUUID from_id, { /*RIDER*/ // The previous version of the protocol returned the wrong binary bucket... we // still might be able to figure out the type... even though the offer is not retrievable. + + // Should be safe to remove once DRTSIM-451 fully deploys std::string str_bucket(reinterpret_cast(binary_bucket)); std::string str_type(str_bucket.substr(0, str_bucket.find('|'))); @@ -1575,8 +1577,6 @@ void LLIMProcessing::requestOfflineMessagesCoro(std::string url) LL_INFOS("Messaging") << "Processing offline messages." << LL_ENDL; -// std::vector data; -// S32 binary_bucket_size = 0; LLHost sender = gAgent.getRegionHost(); LLSD::array_iterator i = messages.beginArray(); @@ -1608,11 +1608,22 @@ void LLIMProcessing::requestOfflineMessagesCoro(std::string url) bin_bucket.push_back(0); } + // Todo: once drtsim-451 releases, remove the string option + BOOL from_group; + if (message_data["from_group"].isInteger()) + { + from_group = message_data["from_group"].asInteger(); + } + else + { + from_group = message_data["from_group"].asString() == "Y"; + } + LLIMProcessing::processNewMessage( message_data["from_agent_id"].asUUID(), - message_data["from_group"].asBoolean(), + from_group, message_data["to_agent_id"].asUUID(), - static_cast(message_data["offline"].asInteger()), + message_data.has("offline") ? static_cast(message_data["offline"].asInteger()) : IM_OFFLINE, static_cast(message_data["dialog"].asInteger()), message_data["transaction-id"].asUUID(), static_cast(message_data["timestamp"].asInteger()), -- cgit v1.2.3 From 72423372d6cd7f763a5567ad75752fa4e7131d60 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Mon, 20 Jul 2020 15:04:30 -0400 Subject: Increment viewer version to 6.4.6 following promotion of DRTVWR-476 --- indra/newview/VIEWER_VERSION.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/newview') diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt index 7d765dabde..3d05e8cfb4 100644 --- a/indra/newview/VIEWER_VERSION.txt +++ b/indra/newview/VIEWER_VERSION.txt @@ -1 +1 @@ -6.4.5 +6.4.6 -- cgit v1.2.3