summaryrefslogtreecommitdiff
path: root/indra/llcommon
AgeCommit message (Collapse)Author
2020-05-06DRTVWR-476: Add llsd::clone(), llsd::shallow() aliasesNat Goodspeed
for new llsd_clone(), llsd_shallow() functions.
2020-05-06DRTVWR-476: Merge branch 'master' of lindenlab/viewer into DRTVWR-476-boost-1.72Nat Goodspeed
2020-04-29Merge branch 'DRTVWR-500' into DRTVWR-501-maintAndrey Lihatskiy
2020-04-21AMD CPUs list updateAndrey Lihatskiy
2020-04-20Merge branch 'master' into DRTVWR-500Andrey Lihatskiy
# Conflicts: # indra/newview/pipeline.cpp
2020-04-03DRTVWR-476: Facilitate debugging test programs with logging.Nat Goodspeed
On Mac, even if you run a test program with --debug or set LOGTEST=DEBUG, it won't log to stderr if you're filtering build output or running the build in an emacs compile buffer. This is because, on Mac, a viewer launched by mouse rather than from the command line is passed a stderr stream that ultimately gets logged to the system Console. The shouldLogToStderr() function is intended to avoid spamming the Console with the (voluminous) viewer log output. It tests whether stderr isatty() and, if not, suppresses calling LLError::logToStderr(). This makes debugging test programs using log output trickier than necessary. Change shouldLogToStderr() to permit logging when either stderr isatty() or is a pipe. The original intention is preserved in that empirically, a viewer launched by mouse is passed a stderr stream identified as a character device rather than as a pipe. Also introduce SetEnv, a class that facilitates setting (e.g.) LOGTEST=DEBUG for specific test programs without setting it for all test programs in the build. Using the constructor for a static object means you can set environment variables before main() is entered, which is important because it's the main() function in test.cpp that acts on the LOGTEST and LOGFAIL environment variables. These changes make it unnecessary to retain the temporary change in test.cpp to force LOGTEST to DEBUG.
2020-04-03DRTVWR-476: Cherry-pick debug aids from commit 77b0c53 (fiber-mutex)Nat Goodspeed
2020-03-26DRTVWR-476: Apparently it can take more than 2s for threads to chat.Nat Goodspeed
llmainthreadtask_test builds in a Sync timeout to keep build-time tests from hanging. That timeout was set to 2000ms, which seems as though it ought to be plenty enough time for a process with only 2 threads to exchange data between them. But on TeamCity EC2 Windows build hosts, sometimes we hit that timeout and fail. Extend it to try to improve the robustness of builds, even though the possibility of a production viewer blocking for that long for anything seems worrisome. (Fortunately the production viewer does not use Sync.)
2020-03-25DRTVWR-476: Introduce LLThreadSafeQueue::close().Nat Goodspeed
Also isClosed() and explicit operator bool() to detect closed state. close() causes every subsequent pushFront() to throw LLThreadSafeQueueInterrupt. Once the queue is drained, it causes popBack() to throw likewise.
2020-03-25DRTVWR-476: make printActiveCoroutines() output slightly clearer.Nat Goodspeed
For the main coroutine on each thread, show the 'main0' (or whatever) name instead of the empty-string name.
2020-03-25DRTVWR-476: Re-enable LLInstanceTracker tests disabled months ago.Nat Goodspeed
2020-03-25DRTVWR-476: Log calls to LLParamSingleton::initParamSingleton().Nat Goodspeed
2020-03-25DRTVWR-476: Update LLMainThreadTask tests for simpler API.Nat Goodspeed
2020-03-25DRTVWR-476: Fix merge glitch.Nat Goodspeed
2020-03-25DRTVWR-476: On Windows, use prebuilt Boost.Stacktrace.Nat Goodspeed
2020-03-25DRTVWR-476: Adapt LLInstanceTracker::snapshot for VS limitations.Nat Goodspeed
2020-03-25DRTVWR-476: Add unit tests for LLMainThreadTask.Nat Goodspeed
Now that we have the Sync class to help construct unit tests that move forward in a deterministic stepwise order, we can build suitable unit tests for LLMainThreadTask.
2020-03-25DRTVWR-476: LLTHROW() requires LLException or subclass.Nat Goodspeed
2020-03-25DRTVWR-476: Make llcoro::logname() distinguish different threads.Nat Goodspeed
Actually, introduce static LLCoros::logname() and make the namespaced free function an alias for that. Because CoroData is a subclass of LLInstanceTracker with a key, every instance requires a distinct key. That conflicts with our "getName() returns empty string for default coroutine on thread" convention. Introduce a new CoroData constructor, specifically for the default coroutine on each thread, that initializes the getName() name to empty string while providing a distinct "mainN" key. Make get_CoroData() use that new constructor for its thread_local instance, passing an atomic<int> incremented each time we initialize one for a new thread. Then LLCoros::logname() returns either the getName() name or the key.
2020-03-25DRTVWR-476: Adjust LLCoros to new LLInstanceTracker API.Nat Goodspeed
2020-03-25DRTVWR-476, SL-12197: Don't throw Stopping from main coroutine.Nat Goodspeed
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.
2020-03-25DRTVWR-476: Enrich LLExceptions thrown by LLTHROW() with stack trace.Nat Goodspeed
The LLTHROW() abstraction allows us to enrich the subject exception with a boost::stacktrace -- without having to propagate the boost/stacktrace.hpp header throughout the code base. To my delight, our existing use of boost::current_exception_diagnostic_information() already reports the newly added boost::stacktrace information -- we don't have to query it specifically!
2020-03-25DRTVWR-476: Add LLTHROW()/LOG_UNHANDLED_EXCEPTION() test.Nat Goodspeed
llexception_test.cpp is about discovering appropriate infrastructure to get good information from the LLTHROW() and LOG_UNHANDLED_EXCEPTION() mechanism. But we didn't before have a test that actually exercises them. Now we do.
2020-03-25DRTVWR-476: Introduce LLStacktrace, a token to stream stack trace.Nat Goodspeed
LLStacktrace has no behavior except when you stream an instance to a std::ostream. Then it reports the current traceback at that point to the ostream. This bit of indirection is intended to avoid the boost/stacktrace.hpp header from being included everywhere.
2020-03-25DRTVWR-476: Make LLThreadSafeQueue coroutine-safe as well.Nat Goodspeed
2020-03-25DRTVWR-476: Back out 355d9db4a59f: unroll stderr redirection.Nat Goodspeed
2020-03-25DRTVWR-476: Back out e913c05d43b6: unroll stderr redirection.Nat Goodspeed
2020-03-25DRTVWR-476: Back out e66ec842b851: unrolling stderr redirection.Nat Goodspeed
2020-03-25DRTVWR-476: Partially revert 978e09882565: undo using LLTempRedirect.Nat Goodspeed
But leave LLTempRedirect available in the code base.
2020-03-25DRTVWR-476: Don't test configuration.emptyMap().Nat Goodspeed
LLSD::emptyMap() is a factory for an empty map instance, NOT a predicate on any particular instance. In fact checking configuration.isUndefined() and testing whether the map is empty are both subsumed by (! configuration).
2020-03-25DRTVWR-476: Always clear both fields even if mOrigTarget invalid.Nat Goodspeed
2020-03-25DRTVWR-476: Encapsulate dup()/dup2() fd saving as LLTempRedirect.Nat Goodspeed
2020-03-25DRTVWR-476: On Windows, dup2() et al. need <io.h>Nat Goodspeed
2020-03-25DRTVWR-476: Try to extend stderr redirection to Windows as well.Nat Goodspeed
Make the LLError::Settings LLSingleton duplicate the file handle for stderr (usually 2) on construction. Make its destructor restore the original target for that file handle. Provide a getDupStderr() method to obtain the duplicate file handle. Move Settings declaration up to the top of the file so other code can reference it. Make RecordToFile (the Recorder subclass engaged by LLError::logToFile()), instead of duplicating stderr's file handle itself, capture the duplicate stderr file handle from Settings to revert stderr redirection on destruction. Make RecordToStderr (the Recorder subclass engaged by LLError::logToStderr()) use fdopen() to create an LLFILE* targeting the duplicate file handle from Settings. Write output to that instead of to stderr so logToStderr() continues to provide output for the user instead of duplicating each line into the log file.
2020-03-25DRTVWR-476: Try to log stderr output from classic-C libraries.Nat Goodspeed
Some of the libraries we use produce log output to stderr. Such output can be informative, but is invisible unless you launch the viewer from a console. In particular, it's invisible to anyone trying to diagnose a problem by reading someone else's SecondLife.log file. Make RecordToFile -- the Recorder subclass engaged by LLError::logToFile() -- redirect STDERR_FILENO to the newly-opened log file so that any subsequent writes to stderr (or cerr, for that matter) will be captured in the log file. But first duplicate the original stderr file handle, and restore it when RecordToFile is destroyed. That way, output written to stderr during the final moments of application shutdown should still appear on (console) stderr.
2020-03-25DRTVWR-476: Add LLUniqueFile, adding RAII semantics to LLFILE*.Nat Goodspeed
LLUniqueFile wraps an LLFILE* in a move-only class that closes the wrapped LLFILE* on destruction. It provides conversion operators to permit idiomatic usage as an LLFILE* value.
2020-03-25DRTVWR-476: Keep coroutine-local data on toplevel()'s stack frame.Nat Goodspeed
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.
2020-03-25DRTVWR-476: Back out changeset 40c0c6a8407d ("final" LLApp listener)Nat Goodspeed
2020-03-25DRTVWR-476: Pump coroutines a few more times when we start quitting.Nat Goodspeed
By the time "LLApp" listeners are notified that the app is quitting, the mainloop is no longer running. Even though those listeners do things like close work queues and inject exceptions into pending promises, any coroutines waiting on those resources must regain control before they can notice and shut down properly. Add a final "LLApp" listener that resumes ready coroutines a few more times. Make sure every other "LLApp" listener is positioned before that new one.
2020-03-25DRTVWR-476: Don't name the caught exceptionNat Goodspeed
unless we're going to reference it.
2020-03-25DRTVWR-476: Terminate long-lived coroutines to avoid shutdown crash.Nat Goodspeed
Add LLCoros::TempStatus instances around known suspension points so printActiveCoroutines() can report what each suspended coroutine is waiting for. Similarly, sprinkle checkStop() calls at known suspension points. Make LLApp::setStatus() post an event to a new LLEventPump "LLApp" with a string corresponding to the status value being set, but only until ~LLEventPumps() -- since setStatus() also gets called very late in the application's lifetime. Make postAndSuspendSetup() (used by postAndSuspend(), suspendUntilEventOn(), postAndSuspendWithTimeout(), suspendUntilEventOnWithTimeout()) add a listener on the new "LLApp" LLEventPump that pushes the new LLCoros::Stopping exception to the coroutine waiting on the LLCoros::Promise. Make it return the new LLBoundListener along with the previous one. Accordingly, make postAndSuspend() and postAndSuspendWithTimeout() store the new LLBoundListener returned by postAndSuspendSetup() in a LLTempBoundListener (as with the previous one) so it will automatically disconnect once the wait is over. Make each LLCoprocedurePool instance listen on "LLApp" with a listener that closes the queue on which new work items are dispatched. Closing the queue causes the waiting dispatch coroutine to terminate. Store the connection in an LLTempBoundListener on the LLCoprocedurePool so it will disconnect automatically on destruction. Refactor the loop in coprocedureInvokerCoro() to instantiate TempStatus around the suspending call. Change a couple spammy LL_INFOS() calls to LL_DEBUGS(). Give all logging calls in that module a "CoProcMgr" tag to make it straightforward to re-enable the LL_DEBUGS() calls as desired.
2020-03-25DRTVWR-476: Infrastructure to help manage long-lived coroutines.Nat Goodspeed
Introduce LLCoros::Stop exception, with subclasses Stopping, Stopped and Shutdown. Add LLCoros::checkStop(), intended to be called periodically by any coroutine with nontrivial lifespan. It checks the LLApp status and, unless isRunning(), throws one of these new exceptions. Make LLCoros::toplevel() catch Stop specially and log forcible coroutine termination. Now that LLApp status matters even in a test program, introduce a trivial LLTestApp subclass whose sole function is to make isRunning() true. (LLApp::setStatus() is protected: only a subclass can call it.) Add LLTestApp instances to lleventcoro_test.cpp and lllogin_test.cpp. Make LLCoros::toplevel() accept parameters by value rather than by const reference so we can continue using them even after context switches. Make private LLCoros::get_CoroData() static. Given that we've observed some coroutines living past LLCoros destruction, making the caller call LLCoros::instance() is more dangerous than encapsulating it within a static method -- since the encapsulated call can check LLCoros::wasDeleted() first and do something reasonable instead. This also eliminates the need for both a const and non-const overload. Defend LLCoros::delete_CoroData() (cleanup function for fiber_specific_ptr for CoroData, implicitly called after coroutine termination) against calls after ~LLCoros(). Add a status string to coroutine-local data, with LLCoro::setStatus(), getStatus() and RAII class TempStatus. Add an optional 'when' string argument to LLCoros::printActiveCoroutines(). Make ~LLCoros() print the coroutines still active at destruction.
2020-03-25DRTVWR-476: Make ~LLEventPumps() call reset() on its way out.Nat Goodspeed
~LLEventPumps() deletes every LLEventPump instance it created itself. However, many classes themselves contain LLEventPump subclass instances. These are registered with LLEventPumps without it managing their lifespan. But LLEventPump::reset() frees the LLStandardSignal aka boost::signals2::signal instance owned by the LLEventPump, perforce disconnecting all current listeners and disabling the LLEventPump. Even though the instance still exists, if someone subsequently calls post(), nothing will happen -- which is better than control trying to reach a method of a deleted object.
2020-03-25DRTVWR-476: Defer #include "lleventtimer.h" until lleventfilter.cpp.Nat Goodspeed
2020-03-25DRTVWR-476: Add LLEventTimer::run_every(), run_at(), run_after().Nat Goodspeed
Also add corresponding LLEventTimeout::post_every(), post_at(), post_after() methods.
2020-03-25DRTVWR-476: Eliminate static LLEventPump factory maps.Nat Goodspeed
Having a map from std::string to a factory function returning LLEventPump* is a cool idea, especially since you could statically populate such a map with string literals and little lambdas. Unfortunately, static initialization of any data is a bad idea when control can reach consuming code before that module's static data are constructed. Since LLEventPumps is already an LLSingleton, it's simple enough to make its map non-static and initialize it in the constructor. But another recent static factory-function map was introduced in llleaplistener.cpp to support the LLLeapListener::newpump() operation. That involves no LLSingletons. Introduce LLEventPumps::make(name, tweak, type) to instantiate an LLEventPump subclass of the specified type with specified (name, tweak) parameters. Instances returned by make() are owned by LLEventPumps, as with obtain(). Introduce LLEventPumps::BadType exception for when the type string isn't recognized. LLEventPumps::obtain() can then simply call make() when the specified instance name doesn't already exist. The configuration data used internally by obtain() becomes { string instance name, string subclass name }. Although this too is currently initialized in the LLEventPumps constructor, migrating it to a configuration file would now be far more straightforward than before. LLLeapListener::newpump(), too, can call LLEventPumps::make() with the caller-specified type string. This eliminates that static factory map. newpump() must catch BadType and report the error back to its invoker. Given that the LLEventPump subclass instances returned by make() are owned by LLEventPumps rather than LLLeapListener, there is no further need for the LLLeapListener::mEventPumps ptr_map, which was used only to manage lifetime. Also remove LLLeapListener's "killpump" operation since LLEventPumps provides no corresponding functionality.
2020-03-25DRTVWR-476: Seems gcc 4.8 forbids brace-init of reference vars.Nat Goodspeed
Although this is legal, apparently there was a bug in the C++11 standard (to which gcc 4.8 conforms) that was subsequently fixed in the standard (and thus in gcc 4.9). Thanks Henri Beauchamp.
2020-03-25DRTVWR-476: Kill LLEventQueue, per-frame LLEventPump::flush() calls.Nat Goodspeed
No one uses LLEventQueue to defer posted events until the next mainloop tick -- and with LLCoros moving to Boost.Fiber, cross-coroutine event posting works that way anyway, making LLEventQueue pretty unnecessary. The static RegisterFlush instance in llevents.cpp was used to call LLEventPumps::flush() once per mainloop tick, which in turn called flush() on every registered LLEventPump. But the only reason for that mechanism was to support LLEventQueue. In fact, when LLEventMailDrop overrode its flush() method for something quite different, it was startling to find that the new flush() override was being called once per frame -- which caused at least one fairly mysterious bug. Remove RegisterFlush. Both LLEventPumps::flush() and LLEventPump::flush() remain for now, though intended usage is unclear. Eliminating LLEventQueue means we must at least repurpose LLEventPumps::mQueueNames, a map intended to make LLEventPumps::obtain() instantiate an LLEventQueue rather than the default LLEventPump. Replace it with mFactories, a map from desired instance name to a callable returning LLEventPump*. New map initialization syntax plus lambda support allows us to populate that map at compile time with little lambdas returning the correct subclass instance. Similarly, LLLeapListener::newpump() used to check the ["type"] entry in the LLSD request specifically for "LLEventQueue". Introduce another such map in llleaplistener.cpp for potential future extensibility. Eliminate the LLEventQueue-specific test.
2020-03-25DRTVWR-476: Introduce LLEventMailDrop::discard() (instead of flush()).Nat Goodspeed
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.
2020-03-25DRTVWR-476: Add LLEventLogProxy, LLEventLogProxyFor<T>.Nat Goodspeed
LLEventLogProxy can be introduced to serve as a logging proxy for an existing LLEventPump subclass instance. Access through the LLEventLogProxy will be logged; access directly to the underlying LLEventPump will not. LLEventLogProxyFor<LLEventPumpSubclass> functions as a drop-in replacement for the original LLEventPumpSubclass instance. It internally instantiates LLEventPumpSubclass and serves as a proxy for that instance. Add unit tests for LLEventMailDrop and LLEventLogProxyFor<LLEventMailDrop>, both "plain" (events only) and via lleventcoro.h synchronization.