Age | Commit message (Collapse) | Author |
|
|
|
being empty as well as the status flag condition
|
|
|
|
|
|
# Conflicts:
# autobuild.xml
# indra/newview/llimprocessing.cpp
|
|
|
|
Ever since February 2010, the body of the login coroutine function has been
enclosed in try/catch (...), with an llerrs message to try to crash more
informatively than the runtime's unhandled-exception termination. Over the
years this evolved to LL_ERRS and then to CRASH_ON_UNHANDLED_EXCEPTION.
This persisted despite the August 2016 addition of generic catch clauses in
the LLCoros::toplevel() function to serve the same purpose, and despite the
subsequent introduction of the LLCoros::Stop family of exceptions to
deliberately throw into waiting coroutines on viewer shutdown.
That's exactly what was happening. When the user closed the viewer while
waiting for the response from login.cgi, the waiting operation threw
LLCoros::Stopping, which was caught by that CRASH_ON_UNHANDLED_EXCEPTION,
which crashed the viewer with LL_ERRS rather than propagating up to the
toplevel() and cleanly terminating the coroutine.
Change CRASH_ON_UNHANDLED_EXCEPTION() to LOG_UNHANDLED_EXCEPTION() and
re-throw so toplevel() can handle.
|
|
(cherry picked from commit 0b61150e698537a7e42a4cdae02496da500399d9)
|
|
Specifically, llcoro::suspendUntilTimeout() is definitely called concurrently
by multiple coroutines. New code that instantiates a local LLEventStream must
allow the name to be tweaked for uniqueness.
|
|
Specifically, the shutdown crash reported in SL-13512 was due to
LLExperienceCache::idleCoro() looping on suspendUntilTimeout(), failing to
notice in its slumbers that the viewer was shutting down around it.
Make suspendUntilTimeout() internally call suspendUntilEventOnWithTimeout(),
which already listens for "LLApp" state-change events and throws Stopping when
LLApp enters its shutdown sequence.
|
|
Changes were moved to DRTVWR-514
|
|
|
|
|
|
tryPushFrontFor() is pushFront() with a std::chrono::duration timeout.
|
|
Specifically:
LLCoros::Mutex means boost::fibers::mutex
LLCoros::LockType means std::unique_lock<boost::fibers::mutex>
LLCoros::ConditionVariable means boost::fibers::condition_variable
LLCoros::cv_status means boost::fibers::cv_status
So as not to drag in all of boost::fibers::mutex.hpp or condition_variable.hpp
for each consumer of llcoros.h, instead #define LLCOROS_MUTEX_HEADER and
LLCOROS_CONDVAR_HEADER. Those who need them can #include the relevant macro.
Update llcond.h and llthreadsafequeue.h accordingly.
|
|
for compatibility with Python llbase.llsd.parse().
The Python parse() currently requires uppercase hex digits for b16"hex"
coding; lowercase hex digits cause it to raise LLSDParseError.
|
|
First, the signature classname(const T*) was wrong: that function could only
accept a pointer to const T. The expression classname(someptr) where someptr
was a pointer to non-const SomeType displayed "SomeType*" because it could
only match classname(const T&), where T was SomeType*.
classname(T* const) is what we should have written, meaning "const pointer to
T" rather than "pointer to const T."
Second, the previous implementation failed to handle the case in which the
pointer was nullptr.
|
|
LLSDNotationFormatter (also LLSDNotationStreamer that uses it, plus
operator<<(std::ostream&, const LLSD&) that uses LLSDNotationStreamer) is most
useful for displaying LLSD to a human, e.g. for logging. Having the default
dump raw binary bytes into the log file is not only suboptimal, it can
truncate the output if one of those bytes is '\0'. (This is a problem with the
logging subsystem, but that's a story for another day.)
Use OPTIONS_PRETTY_BINARY wherever there is a default LLSDFormatter
::EFormatterOptions argument.
Also, allow setting LLSDFormatter subclass boolalpha(), realFormat() and
format(options) using optional constructor arguments. Naturally, each subclass
that supports this must accept and forward these constructor arguments to its
LLSDFormatter base class constructor.
Fix a couple bugs in LLSDNotationFormatter::format_impl() for an LLSD::Binary
value with OPTIONS_PRETTY_BINARY:
- The code unconditionally emitted a b(len) type prefix followed by either raw
binary or hex, depending on the option flag. OPTIONS_PRETTY_BINARY caused it
to emit "0x" before the hex representation of the data. This is wrong in
that it can't be read back by either the C++ or the Python LLSD parser.
Correct OPTIONS_PRETTY_BINARY formatting consists of b16"hex digits" rather
than b(len)"raw bytes".
- Although the code did set hex mode, it didn't set either the field width or
the fill character, so that a byte value less than 16 would emit a single
digit rather than two.
Instead of having one LLSDFormatter::format() method with an optional options
argument, declare two overloads. The format() overload without options passes
the mOptions data member to the overload accepting options.
Refactor the LLSDFormatter family, hoisting the recursive format_impl() method
(accepting level) to a pure virtual method at LLSDFormatter base-class level.
Most subclasses therefore need not override either base-class format() method,
only format_impl(). In fact the short format() overload isn't even virtual.
Consistently use LLSDFormatter::EFormatterOptions enum as the options
parameter wherever such options are accepted.
|
|
for new llsd_clone(), llsd_shallow() functions.
|
|
|
|
|
|
|
|
# Conflicts:
# indra/newview/pipeline.cpp
|
|
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.
|
|
|
|
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.)
|
|
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.
|
|
For the main coroutine on each thread, show the 'main0' (or whatever) name
instead of the empty-string name.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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.
|
|
|
|
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.
|
|
|
|
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.
|
|
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!
|
|
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.
|
|
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.
|
|
|
|
|
|
|
|
|
|
But leave LLTempRedirect available in the code base.
|
|
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).
|
|
|
|
|