Age | Commit message (Collapse) | Author |
|
|
|
For the main coroutine on each thread, show the 'main0' (or whatever) name
instead of the empty-string name.
|
|
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.
|
|
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.
|
|
|
|
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.
|
|
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.
|
|
|
|
Delete the test for SRV timeout: lllogin no longer issues an SRV query. That
test only confuses the test program without exercising any useful paths in
production code.
As with other tests dating from the previous LLCoros implementation, we need a
few llcoro::suspend() calls sprinkled in so that a fiber marked ready -- by
fulfilling the future for which it is waiting -- gets a chance to run.
Clear LLEventPumps between test functions.
|
|
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).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
autobuild 1.1 now supports expanding $variables within a config file --
support that was explicitly added to address this very problem. So now the
windows platform in autobuild.xml uses $AUTOBUILD_ADDRSIZE,
$AUTOBUILD_WIN_VSPLATFORM and $AUTOBUILD_WIN_CMAKE_GEN, which should handle
most of the deltas between the windows platform and windows64.
This permits removing the windows64 platform definition from autobuild.xml.
The one remaining delta between the windows64 and windows platform definitions
was -DLL_64BIT_BUILD=TRUE. But we can handle that instead by checking
ADDRESS_SIZE. Change all existing references to WORD_SIZE to ADDRESS_SIZE
instead, and set ADDRESS_SIZE to $AUTOBUILD_ADDRSIZE. Change the one existing
LL_64BIT_BUILD reference to test (ADDRESS_SIZE EQUAL 64) instead.
|
|
|
|
Until now, the "main coroutine" (the initial context) of each thread left
LLCoros::Current() NULL. The trouble with that is that llcoro::get_id()
returns that CoroData* as an opaque token, and we want distinct values for
every stack in the process. That would not be true if the "main coroutine" on
thread A returned the same value (NULL) as the "main coroutine" on thread B,
and so forth. Give each thread's "main coroutine" a dummy heap CoroData
instance of its own.
|
|
|
|
|
|
Change the module-static thread_specific_ptr to a function-static
thread_specific_ptr so it will be initialized on demand -- since LLSingleton
will need to rely on get_id(). Note that since LLCoros isa LLSingleton, we
must take great care to avoid circularity.
Introduce a private helper class LLCoros::Current to obtain and bind that
thread_specific_ptr. Change all existing internal references from the static
thread_specific_ptr to the new Current helper class.
|
|
|
|
|
|
Wrap coroutine call in try/catch in top-level coroutine wrapper function
LLCoros::toplevel(). Distinguish exception classes derived from
LLContinueError (log and continue) from all others (crash with LL_ERRS).
Enhance CRASH_ON_UNHANDLED_EXCEPTIONS() and LOG_UNHANDLED_EXCEPTIONS() macros
to accept a context string to supplement the log message. This lets us replace
many places that called boost::current_exception_diagnostic_information() with
LOG_UNHANDLED_EXCEPTIONS() instead, since the explicit calls were mostly to
log supplemental information.
Provide supplemental information (coroutine name, function parameters) for
some of the previous LOG_UNHANDLED_EXCEPTIONS() calls. This information
duplicates LL_DEBUGS() information at the top of these functions, but in a
typical log file we wouldn't see the LL_DEBUGS() message.
Eliminate a few catch (std::exception e) clauses: the information we get from
boost::current_exception_diagnostic_information() in a catch (...) clause
makes it unnecessary to distinguish.
In a few cases, add a final 'throw;' to a catch (...) clause: having logged
the local context info, propagate the exception to be caught by higher-level
try/catch.
In a couple places, couldn't resist reconciling indentation within a
particular function: tabs where the rest of the function uses tabs, spaces
where the rest of the function uses spaces.
In LLLogin::Impl::loginCoro(), eliminate some confusing comments about an
array of rewritten URIs that date back to a long-deleted implementation.
|
|
|
|
on the advice of NickyD.
|
|
|
|
set_consuming(true) tells each postAndSuspend() call to consume the event for
which it is suspending.
|
|
|
|
|
|
|
|
|
|
|
|
Our first cut at tracking the "current" coroutine simply reset the pointer to
NULL every time we context-switched away. But that strategy doesn't handle the
case of coroutine A launching coroutine B.
Introduce LLCoros::CoroData to track, among other things, the previous value
of the current-coroutine pointer each time we switch into a coroutine. Restore
THAT value when we switch back out.
|
|
|
|
To date, the coroutine helper functions in lleventcoro.h have been in the
global namespace. Migrate them into llcoro namespace, and fix references.
Specifically, LLVoidListener => llcoro::VoidListener, and voidlistener(),
postAndWait(), both waitForEventOn(), postAndWait2(), errorException() and
errorLog() have been moved into llcoro.
Also migrate new LLCoros::get_self() and Suspending to llcoro:: namespace.
While at it, I realized that -- having converted several lleventcoro.h
functions from templates (for arbitrary 'self' parameter type) to ordinary
functions, having moved them from lleventcoro.h to lleventcoro.cpp, we can now
migrate their helpers from lleventcoro.h to lleventcoro.cpp as well. This
eliminates the need for the LLEventDetail namespace; the relevant helpers are
now in an anonymous namespace in the .cpp file: listenerNameForCoro(),
storeToLLSDPath(), WaitForEventOnHelper and wfeoh().
|
|
lleventcoro_test.cpp runs clean (as modified for new API), and all the rest
builds clean, but the resulting viewer is as yet untested.
|
|
|
|
throwing unhandlable exceptions in coroutines in RelWithDebInfo builds
|
|
|
|
Introduce LLCoros::setStackSize(), with a compile-time default value we hope
we never have to use. Make LLAppViewer call it with the value of the new
settings variable CoroutineStackSize as soon as we've read settings files.
(While we're at it, notify interested parties that we've read settings files.)
Give CoroutineStackSize a default value four times the previous default stack
size. Make LLCoros::launch() pass the saved stack size to each new coroutine
instance.
Re-enable lleventcoro integration test. Use LLSDMap() construct rather than
LLSD::insert(), which used to return the modified object but is now void.
|
|
|
|
|
|
In autobuild.xml, specify today's build of the Boost package that includes the
Boost.Context library, and whose boost::dcoroutines library uses Boost.Context
exclusively instead of its previous context-switching underpinnings (source of
the ucontext.h dependency).
Add BOOST_CONTEXT_LIBRARY to Boost.cmake and Copy3rdPartyLibs.cmake. Link it
with the viewer and with the lllogin.cpp test executable.
Track new Boost package convention that our (early, unofficial) Boost.Coroutine
library is now accessed as boost/dcoroutine/etc.h and boost::dcoroutines::etc.
Remove #include <boost/coroutine/coroutine.hpp> from
llviewerprecompiledheaders.h and lllogin.cpp: old rule that Boost.Coroutine
header must be #included before anything else that might use ucontext.h is
gone now that we no longer depend on ucontext.h. In fact remove
-D_XOPEN_SOURCE in 00-Common.cmake because that was inserted specifically to
work around a known problem with the ucontext.h facilities.
|
|
|
|
LLCoros::launchImpl().
This fixes the Release-build crash in lllogin_test.cpp.
|