summaryrefslogtreecommitdiff
AgeCommit message (Collapse)Author
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: Mention LLApp::stepFrame() in LLAppViewer::idle()Nat Goodspeed
which performs "by hand" the same sequence of calls found in stepFrame(). Why not simply call stepFrame()? Hysterical reasons?
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: Update to bugsplat build 532004Nat 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: We've observed a couple different values for VS 2017.Nat Goodspeed
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: Directly reference LLVivoxVoiceClient::mVivoxPump.Nat Goodspeed
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-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.
2020-03-25DRTVWR-476: Validate LLEventPumpOrPumpName replyPumpNat Goodspeed
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-25DRTVWR-476: Remove special case for listen(boost::bind(weak_ptr)).Nat Goodspeed
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-25DRTVWR-476: Remove llwrap(), LLListenerWrapper[Base] and support.Nat Goodspeed
The only usage of any of this was in test code.
2020-03-25DRTVWR-476: Update to viewer-manager build 531762Nat Goodspeed
2020-03-25DRTVWR-476: Add llsd::array() and llsd::map() variadic functions.Nat Goodspeed
llsd::array(), as one might suspect, takes an arbitrary number of arguments of arbitrary convertible types and returns an LLSD::Array constructed from those elements. This supercedes the older LLSDArray class. llsd::map() takes an even number of arguments paired as (LLSD::String, arbitrary convertible type) and returns an LLSD::Map constructed from those (key, value) pairs. This supercedes the older LLSDMap class. These two functions not only have a simpler API -- arbitrary function arguments rather than an (arg list)(arg list) sequence -- but also specifically return a final LLSD object, rather than needing conversion to LLSD from the LLSDArray or LLSDMap object. Also support LLSD == LLSD and LLSD != LLSD comparisons, using llsd_equals() with default exact-float-equality semantics.
2020-03-25DRTVWR-476: Engage variadic llmake() implementation.Nat Goodspeed
2020-03-25DRTVWR-476: Make test program --debug switch work like LOGTEST=DEBUG.Nat Goodspeed
The comments within indra/test/test.cpp promise that --debug is, in fact, like LOGTEST=DEBUG. Until now, that was a lie. LOGTEST=level displayed log output on stderr as well as in testprogram.log, while --debug did not. Add LLError::logToStderr() function, and make initForApplication() (i.e. commonInit()) call that instead of instantiating RecordToStderr inline. Also call it when test.cpp recognizes --debug switch. Remove the mFileRecorder, mFixedBufferRecorder and mFileRecorderFileName members from SettingsConfig. That tactic doesn't scale. Instead, add findRecorder<RECORDER>() and removeRecorder<RECORDER>() template functions to locate (or remove) a RecorderPtr to an object of the specified subclass. Both are based on an underlying findRecorderPos<RECORDER>() template function. Since we never expect to manage more than a handful of RecorderPtrs, and since access to the deleted members is very much application setup rather than any kind of ongoing access, a search loop suffices. logToFile() uses removeRecorder<RecordToFile>() rather than removing mFileRecorder (the only use of mFileRecorder). logToFixedBuffer() uses removeRecorder<RecordToFixedBuffer>() rather than removing mFixedBufferRecorder (the only use of mFixedBufferRecorder). Make RecordToFile store the filename with which it was instantiated. Add a getFilename() method to retrieve it. logFileName() is now based on findRecorder<RecordToFile>() instead of mFileRecorderFileName (the only use of mFileRecorderFileName). Make RecordToStderr::mUseANSI a simple bool rather than a three-state enum, and set it immediately on construction. Apparently the reason it was set lazily was because it consults its own checkANSI() method, and of course 'this' doesn't acquire the leaf class type until the constructor has completed successfully. But since nothing in checkANSI() depends on anything else in RecordToStderr, making it static solves that problem.
2020-03-25DRTVWR-476: Fix overflow case in llcoro::postAndSuspend().Nat Goodspeed
Actually the fix is in postAndSuspendSetup(), which affects postAndSuspend(), postAndSuspendWithTimeout(), suspendUntilEventOnWithTimeout() and suspendUntilEventOn(). By "overflow case" we mean the special circumstance in which: * the LLEventPump in question is an LLEventMailDrop, meaning its listeners eventually expect to see every post()ed value * one of the listeners is supposed to consume those values (has called LLCoros::set_consuming(true)) * post() is called more than once before that listener is resumed. The magic of postAndSuspend() (et al.) is a temporary LLCoros::Promise. The waiting coroutine calls get() on the corresponding Future, causing it to suspend (as promised) until the Promise is fulfilled. With the Boost.Fiber implementation of coroutines, fulfilling the Promise doesn't immediately resume the suspended coroutine -- it merely marks it ready to resume, next time the scheduler gets control. A second post() call before the suspended coroutine is resumed results in a second call to Promise::set_value(). But Promise is a one-shot entity. This results in a promise_already_satisfied exception. Because a second post() call during that time window is perfectly reasonable, we catch that exception and carry on. The tricky part is: when that exception is thrown, what should the listener return? Previously we were returning the listener's current consuming setting, just as when the set_value() call succeeds. But when the LLEventPump is an LLEventMailDrop, and the listener's consuming flag is true, that told LLEventMailDrop::post() that the value got through, and that it needn't bother to save it in its history queue. The net effect was to discard the value. Instead, return the listener's consuming flag only when Promise::set_value() succeeds. When it throws promise_already_satisfied, unconditionally return false. That directs LLEventMailDrop::post() to enqueue the undelivered value so that the *next* suspendUntilEventOn() call can pick it up.
2020-03-25DRTVWR-476: Fix Windows line endingsNat Goodspeed
2020-03-25DRTVWR-476: Update to viewer-manager build 531568Nat Goodspeed
2020-03-25DRTVWR-476: Update to openjpeg build 531548Nat Goodspeed
2020-03-25DRTVWR-476: Update vlc-bin, jsoncpp, pcre, libndofdev, libhunspell, ↵Nat Goodspeed
bugsplat, fmodex, llca, jpeglib, libxml2, slvoice, glod, dullahan, glext, kdu, uriparser, glh_linear, tut, nghttp2, dictionaries, zlib, llphysicsextensions_source, openjpeg, nvapi, expat, viewer-manager, google_breakpad, libpng, ogg_vorbis, openssl, xmlrpc-epi, apr_suite, freetype, boost, colladadom, googlemock, curl, havok-source Update vlc-bin to codeticket version 531366. Update jsoncpp to codeticket version 531360. Update pcre to codeticket version 531373. Update libndofdev to codeticket version 531359. Update libhunspell to codeticket version 531369. Update bugsplat to codeticket version 531352. Update fmodex to codeticket version 531266. Update llca to codeticket version 531253. Update jpeglib to codeticket version 531361. Update libxml2 to codeticket version 531380. Update slvoice to codeticket version 531358. Update glod to codeticket version 531370. Update dullahan to codeticket version 531387. Update glext to codeticket version 531247. Update kdu to codeticket version 531363. Update uriparser to codeticket version 531367. Update glh_linear to codeticket version 531260. Update tut to codeticket version 531246. Update nghttp2 to codeticket version 531364. Update dictionaries to codeticket version 531288. Update zlib to codeticket version 531372. Update llphysicsextensions_source to codeticket version 531362. Update openjpeg to codeticket version 531368. Update nvapi to codeticket version 531376. Update expat to codeticket version 531365. Update viewer-manager to codeticket version 531239. Update google_breakpad to codeticket version 531388. Update libpng to codeticket version 531386. Update ogg_vorbis to codeticket version 531357. Update openssl to codeticket version 531379. Update xmlrpc-epi to codeticket version 531374. Update apr_suite to codeticket version 531375. Update freetype to codeticket version 531385. Update boost to codeticket version 531381. Update colladadom to codeticket version 531391. Update googlemock to codeticket version 531390. Update curl to codeticket version 531389. Update havok-source to codeticket version 531509.
2020-03-25DRTVWR-476: Update to havok-source build 531405Nat Goodspeed
2020-03-25DRTVWR-476: Re-enable an llcoproceduremanager_test case.Nat Goodspeed
Use new Sync class to make the driving logic wait for the coprocedure to run.
2020-03-25DRTVWR-476: Add Sync class to help with stepwise coroutine tests.Nat Goodspeed
Sync is specifically intended for test programs. It is based on an LLScalarCond<int>. The idea is that each of two coroutines can watch for the other to get a chance to run, indicated by incrementing the wrapped int and notifying the wrapped condition_variable. This is less hand-wavy than calling llcoro::suspend() and hoping that the other routine will have had a chance to run. Use Sync in lleventcoro_test.cpp. Also refactor lleventcoro_test.cpp so that instead of a collection of static data requiring a clear() call at start of each individual test function, the relevant data is all part of the test_data struct common to all test functions. Make the helper coroutine functions members of test_data too. Introduce llcoro::logname(), a convenience function to log the name of the currently executing coroutine or "main" if in the thread's main coroutine.
2020-03-25DRTVWR-476: Improve llprocess_test.cpp diagnostic output.Nat Goodspeed
If the test<1>() child process terminates with nonzero rc, also report any stdout/stderr it might have emitted first.
2020-03-25DRTVWR-476: Update to libndofdev build 530327Nat Goodspeed
2020-03-25DRTVWR-476: Add basic tests for LLCond.Nat Goodspeed
2020-03-25DRTVWR-476: Fix first round of compile errors.Nat Goodspeed
2020-03-25DRTVWR-476: Fix convert(F32Milliseconds)Nat Goodspeed
2020-03-25DRTVWR-476: Review response: remove wait_until() methods and LLDate.Nat Goodspeed
2020-03-25DRTVWR-476: Review response: support LLDate and llunits.h durations.Nat Goodspeed
Also introduce value_type typedef.
2020-03-25DRTVWR-476: WIP: Untested preliminary implementation of LLCond.Nat Goodspeed
LLCond encapsulates the usage patterns required to properly use condition_variable. We also provide LLScalarCond, LLBoolCond and LLOneShotCond.
2020-03-25DRTVWR-476: Fix confusing comment in LLProcess::handle_status().Nat Goodspeed
The global replace in changeset bd80903cf987 was a bit too sweeping: a comment mentioning the OS function wait() (which exists) was inadvertently changed to talk about an OS function suspend() (which does not).
2020-03-25Tweaks to VSTool source and executable for compatibility with VS 2017callum_linden
2020-03-25[DRTVWR-476] - temp fix to test. comment it out. access violation in releaseAnchor
2020-03-25[DRTVWR-476] - temp fix to a testAnchor
2020-03-25DRTVWR-476: Disable test_httprequest.hpp on Mac Release builds.Nat Goodspeed
For reasons not yet diagnosed, specifically in Mac Release builds, the tests in test_httprequest.hpp consistently crash with a backtrace suggesting that the worker thread is calling LLCore::HttpLibcurl::completeRequest() after the foreground thread calls HttpRequest::destroyService(). Weirdly, even executing a tut::skip() call in every test<n>() function up to the point of the crash does not eliminate the crash.
2020-03-25DRTVWR-476: Remove special llcorehttp test memory manager.Nat Goodspeed
NickyD discovered that the substitute default allocator used for llcorehttp tests was returning badly-aligned storage, which caused access violations on alignment-sensitive data such as std::atomic. Thanks Nicky!! Moreover, the llcorehttp test assertions regarding memory usage, well- intentioned though they are, have been causing us trouble for years. Many have already been disabled. The problem is that use of test_allocator.h affected *everything* defined with that header file's declarations visible. That inevitably included specific functions in other subsystems. Those functions then (unintentionally) consumed the special allocator, throwing off the memory tracking and making certain memory-related assertions consistently fail. This is a particular, observable bad effect of One Definition Rule violations. Within a given program, C++ allows multiple definitions for the same entity, but requires that all such definitions be the same. Partial visibility of the global operator new() and operator delete() overrides meant that some definitions of certain entities used the default global allocator, some used llcorehttp's. There may have been other, more subtle bad effects of these ODR violations. If one wanted to reimplement verification of the memory consumption of llcorehttp classes: * Each llcorehttp class (for which memory tracking was desired) should declare class-specific operator new() and operator delete() methods. Naturally, these would all consume a central llcorehttp-specific allocator, but that allocator should *not* be named global operator new(). * Presumably that would require runtime indirection to allow using the default allocator in production while substituting the special allocator for tests. * Recording and verifying the memory consumption in each test should be performed in the test-object constructor and destructor, rather than being sprinkled throughout the test<n>() methods. * With that mechanism in place, the test object should provide methods to adjust (or entirely disable) memory verification for a particular test. * The test object should also provide a "yes, we're still consuming llcorehttp memory" method to be used for spot checks in the middle of tests -- instead of sprinkling in explicit comparisons as before. * In fact, the llcorehttp test object in each test_*.hpp file should be derived from a central llcorehttp test-object base class providing those methods.
2020-03-25DRTVWR-476: On Mac, copy libhunspell-1.3.0.dylib for test programs.Nat Goodspeed
2020-03-25DRTVWR-476: Add LLCOREHTTP_TESTS CMake var, OFF by default on Mac.Nat Goodspeed
Hopefully this is temporary until we solve the problem of crashy llcorehttp test executable on Mac.
2020-03-25General cleanup. Delete commented out code.Nicky
2020-03-25Replace boost::fibers::unbuffered_channel with boost::fibers::buffered_channel.Nicky
Using boost::fibers::unbuffered_channel can block the mainthread when calling mPendingCoprocs.push (LLCoprocedurePool::enqueueCoprocedure) From the documentation: - If a fiber attempts to send a value through an unbuffered channel and no fiber is waiting to receive the value, the channel will block the sending fiber. This can happen if LLCoprocedurePool::coprocedureInvokerCoro is running a coroutine and this coroutine calls yield, resuming the viewers main loop. If inside the main loop someone calls LLCoprocedurePool::enqueueCoprocedure now push will block, as there's no one waiting for a result right now. The wait would be in LLCoprocedurePool::coprocedureInvokerCoro at the start of the while loop, but we have not reached that yet again as LLCoprocedurePool::coprocedureInvokerCoro did yield before reaching pop_wait_for. The result is a deadlock. boost::fibers::buffered_channel will not block as long as there's space in the channel. A size of 4096 (DEFAULT_QUEUE_SIZE) should be plenty enough for this.
2020-03-25[DRTVWR-476] - fix compiler errors 32 bit windows buildAnchor
2020-03-25SL-1968: Extend lllogin_test login-failed cases for new sync timing.Nat Goodspeed
On login failure, LLLogin now tries to sync up with SLVersionChecker. It waits for up to 10 seconds before shrugging and giving up. Since that coroutine can now block for that long, make the llogin_test failure cases wait at least that long too.
2020-03-25Ignore build-vc150-* directories as those are the VS2017 build dirs (n.b. ↵Nicky
due to the rather strange version numbering of VS this really should be build-vc141-*; as VS2017 is vc141 internally).
2020-03-25Do not use string/chrono literals, sadly that won't work with GCC (4.9)Nicky