Commit Graph

40505 Commits (bf8aea5059f127dcce2fdf613d62c253bb3fa8fd)

Author SHA1 Message Date
Nat Goodspeed bf8aea5059 DRTVWR-476: Use LLThreadSafeQueue, not boost::fibers::buffered_channel.
We've observed buffered_channel::try_push() hanging, which seems very odd. Try
our own LLThreadSafeQueue instead.
2020-03-25 19:07:22 -04:00
Nat Goodspeed af35391114 DRTVWR-476: Make LLThreadSafeQueue coroutine-safe as well. 2020-03-25 19:07:22 -04:00
Nat Goodspeed b461b5dcef DRTVWR-476: Manually count items in LLCoprocedurePool's pending queue.
Reinstate LLCoprocedureManager::countPending() and count() methods. These were
removed because boost::fibers::buffered_channel has no size() method, but
since all users run within a single thread, it works to increment and
decrement a simple counter.

Add count information and max queue size to log messages.
2020-03-25 19:06:13 -04:00
Nat Goodspeed 7826683fa2 DRTVWR-476: Back out 355d9db4a59f: unroll stderr redirection. 2020-03-25 19:06:13 -04:00
Nat Goodspeed 99d4ddc668 DRTVWR-476: Back out e913c05d43b6: unroll stderr redirection. 2020-03-25 19:06:13 -04:00
Nat Goodspeed d94e4613ca DRTVWR-476: Back out e66ec842b851: unrolling stderr redirection. 2020-03-25 19:06:13 -04:00
Nat Goodspeed 950204a5d7 DRTVWR-476: Partially revert 978e09882565: undo using LLTempRedirect.
But leave LLTempRedirect available in the code base.
2020-03-25 19:06:13 -04:00
Nat Goodspeed 7ef10fe11c DRTVWR-476: Don't test configuration.emptyMap().
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-25 19:06:13 -04:00
Nat Goodspeed 9c315851a3 DRTVWR-476: Always clear both fields even if mOrigTarget invalid. 2020-03-25 19:06:13 -04:00
Nat Goodspeed 5918620426 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.
2020-03-25 19:06:12 -04:00
Nat Goodspeed b08c44a0dc DRTVWR-476, SL-12205: Refactor MSVC redist library copying.
Specify all of msvcp$VER.dll, msvcr$VER.dll and vcruntime$VER.dll -- but check
each of them individually, because any given VS release has only a subset of
those. Add messaging to clarify what we're doing.

Introduce to_staging_dirs CMake macro to cut down on redundant boilerplate:
the idiom in which we use copy_if_different twice, once to the Release staging
directory and once to the RelWithDebInfo staging directory, each time
appending the target pathnames to third_party_targets. Replace that idiom with
calls to to_staging_dirs.
2020-03-25 19:06:12 -04:00
Nat Goodspeed 71f6f43a32 DRTVWR-476: Annotate Mani's plea from 2009 with a suggested solution.
However, this is not the right moment to perform that refactoring.
2020-03-25 19:06:12 -04:00
Nat Goodspeed 44b9dd2e80 DRTVWR-476, SL-12205: Search for msvcp140.dll, not msvcr140.dll
Evidently, with VS 2017, what would have been msvcr140.dll has become
vcruntime140.dll instead. msvcr140.dll is no longer a good sample DLL for
which to search.
2020-03-25 19:06:12 -04:00
Nat Goodspeed 70a63ca331 DRTVWR-476, SL-12205: Update to glod built with VS 2017 runtime libs. 2020-03-25 19:06:12 -04:00
Nat Goodspeed ec2bd40d3e DRTVWR-476: Encapsulate dup()/dup2() fd saving as LLTempRedirect. 2020-03-25 19:06:12 -04:00
Nat Goodspeed 5f1140c03c DRTVWR-476: For VS 2017, MSVC_VERSION can be any of a range.
Thanks NickyD.
2020-03-25 19:06:12 -04:00
Nat Goodspeed e9a75ad31c DRTVWR-476: Throw some more Microsoft runtime DLLs at the viewer. 2020-03-25 19:06:12 -04:00
Nat Goodspeed e9ef668157 DRTVWR-476: Correct runtime DLL names for VS 2017. 2020-03-25 19:06:12 -04:00
Nat Goodspeed 235b37bb76 DRTVWR-476: Update to VS 2017 versions of runtime DLLs.
Also forget obsolete references to VS 2010 runtime DLLs.
2020-03-25 19:06:12 -04:00
Nat Goodspeed 698922e0ed DRTVWR-476: Update to slvoice build 532334 2020-03-25 19:06:12 -04:00
Nat Goodspeed 6e09366257 DRTVWR-476: Update llviewerjoystick.cpp for updated libndofdev API. 2020-03-25 19:05:17 -04:00
Nat Goodspeed bf3c04ac38 DRTVWR-476: Update libndofdev to codeticket version 532324. 2020-03-25 19:05:17 -04:00
Nat Goodspeed ec208ddfac 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.
2020-03-25 19:05:17 -04:00
Nat Goodspeed 7f1a200214 DRTVWR-476: On Windows, dup2() et al. need <io.h> 2020-03-25 19:05:17 -04:00
Nat Goodspeed 07134aaee7 DRTVWR-476: Try to extend stderr redirection to Windows as well.
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-25 19:05:17 -04:00
Nat Goodspeed f80b2da513 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.
2020-03-25 19:05:17 -04:00
Nat Goodspeed 7845f73c76 DRTVWR-476: Try to log stderr output from classic-C libraries.
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-25 19:05:17 -04:00
Nat Goodspeed 9f446be76e DRTVWR-476: Add LLUniqueFile, adding RAII semantics to LLFILE*.
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-25 19:05:17 -04:00
Nat Goodspeed cc6f1d6195 DRTVWR-476: Use shared_ptr to manage lifespan of coprocedure queue.
Since the consuming coroutine LLCoprocedurePool::coprocedureInvokerCoro() has
been observed to outlive the LLCoprocedurePool instance that owns the
CoprocQueue_t, closing that queue isn't enough to keep the coroutine from
crashing at shutdown: accessing a deleted CoprocQueue_t is fatal whether or
not it's been closed.

Make LLCoprocedurePool store a shared_ptr to a heap CoprocQueue_t instance,
and pass that shared_ptr by value to consuming coroutines. That way the
CoprocQueue_t instance is guaranteed to live as long as the last interested
party.
2020-03-25 19:05:17 -04:00
Nat Goodspeed 9008124d35 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.
2020-03-25 19:05:16 -04:00
Nat Goodspeed 26c8ccfc06 DRTVWR-476: Back out changeset 40c0c6a8407d ("final" LLApp listener) 2020-03-25 19:02:24 -04:00
Nat Goodspeed cbf146f2b3 DRTVWR-476: Pump coroutines a few more times when we start quitting.
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-25 19:02:24 -04:00
Nat Goodspeed 7541e784d9 DRTVWR-476: Don't name the caught exception
unless we're going to reference it.
2020-03-25 19:02:24 -04:00
Nat Goodspeed 1345a02b21 DRTVWR-476: Terminate long-lived coroutines to avoid shutdown crash.
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-25 19:02:24 -04:00
Nat Goodspeed 28a54c2f7b DRTVWR-476: Infrastructure to help manage long-lived coroutines.
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-25 19:02:24 -04:00
Nat Goodspeed 253e360062 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?
2020-03-25 19:00:10 -04:00
Nat Goodspeed aea1e46982 DRTVWR-476: Make ~LLEventPumps() call reset() on its way out.
~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-25 19:00:10 -04:00
Nat Goodspeed 5ec81cf0f7 DRTVWR-476: Defer #include "lleventtimer.h" until lleventfilter.cpp. 2020-03-25 19:00:10 -04:00
Nat Goodspeed aaae44788d DRTVWR-476: Update to bugsplat build 532004 2020-03-25 18:59:10 -04:00
Nat Goodspeed 2f866c9d98 DRTVWR-476: Add LLEventTimer::run_every(), run_at(), run_after().
Also add corresponding LLEventTimeout::post_every(), post_at(), post_after()
methods.
2020-03-25 18:59:10 -04:00
Nat Goodspeed 95a218fcc0 DRTVWR-476: Eliminate static LLEventPump factory maps.
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-25 18:58:16 -04:00
Nat Goodspeed 3ec92b0ede DRTVWR-476: Seems gcc 4.8 forbids brace-init of reference vars.
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-25 18:58:16 -04:00
Nat Goodspeed d43dcc50c5 DRTVWR-476: We've observed a couple different values for VS 2017. 2020-03-25 18:58:16 -04:00
Nat Goodspeed 79a3e391d3 DRTVWR-476: Kill LLEventQueue, per-frame LLEventPump::flush() calls.
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-25 18:58:16 -04:00
Nat Goodspeed 6805e82acd 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.
2020-03-25 18:58:16 -04:00
Nat Goodspeed 4d65539db7 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.
2020-03-25 18:58:16 -04:00
Nat Goodspeed 53aeea4d82 DRTVWR-476: Add LLEventLogProxy, LLEventLogProxyFor<T>.
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.
2020-03-25 18:58:16 -04:00
Nat Goodspeed 6945755e52 DRTVWR-476: Validate LLEventPumpOrPumpName replyPump
passed to postAndSuspendsetup().

The requestPump is optional, and the function varies its behavior depending on
whether that parameter is empty or meaningful. But it unconditionally uses the
replyPump. Passing an empty LLEventPumpOrPumpName caused mysterious crashes.
Add llassert_always_msg() to make the coding error explicit in such a case.

Also streamline access to meaningful requestPump and replyPump by temporarily
caching the bound LLEventPump reference.
2020-03-25 18:52:11 -04:00
Nat Goodspeed afaad3cef7 DRTVWR-476: Remove special case for listen(boost::bind(weak_ptr)).
LLEventDetail::visit_and_connect() promised special treatment for the
specific case when an LLEventPump::listen() listener was composed of (possibly
nested) boost::bind() objects storing boost::weak_ptr values -- specifically
boost::bind() rather than std::bind or lambdas, specifically boost::weak_ptr
rather than std::weak_ptr.

Outside of self-tests, it does not appear that anyone actually uses that
support.

There is good reason not to: it's a silent side effect of a complicated
compile-time inspection that could be silently derailed by use of std::bind()
or a lambda or a std::weak_ptr. Can you be sure you've engaged that promise?
How?

A more robust guarantee can be achieved by storing an LLTempBoundConnection in
the transient object itself. When the object is destroyed, the listener is
disconnected. Normal C++ rules around object destruction guarantee it. This
idiom is widely used.

There are a couple good reasons to remove the visit_and_connect() machinery:

* boost::bind() and boost::weak_ptr do not constitute the wave of the future.
  Preferring those constructs to lambdas and std::weak_ptr penalizes new code,
  whether by silently failing or by discouraging use of modern idioms.
* The visit_and_connect() machinery was always complicated, and apparently
  never very robust. Most of its promised features have been commented out
  over the years. Making the code base simpler, clearer and more maintainable
  is always a useful effect.

LLEventDetail::visit_and_connect() was also used by the four
LLNotificationChannelBase::connectMumble() methods. Streamline those as well.

Of course, remove related test code.
2020-03-25 18:52:11 -04:00
Nat Goodspeed 18e2b9ca8b DRTVWR-476: Remove llwrap(), LLListenerWrapper[Base] and support.
The only usage of any of this was in test code.
2020-03-25 18:52:11 -04:00