diff options
author | Nat Goodspeed <nat@lindenlab.com> | 2015-07-02 17:00:32 -0400 |
---|---|---|
committer | Nat Goodspeed <nat@lindenlab.com> | 2015-07-02 17:00:32 -0400 |
commit | f90023fc0b3b61fd346a2b56e30e5f3c35814192 (patch) | |
tree | 3c020043d54ef45a6f8f1e9c638ab19dcd590ae0 /indra/llcommon | |
parent | 2a29dbc48295ad24a8a7137a10b9d891debea978 (diff) |
MAINT-5357: Introduce and populate llcoro:: namespace.
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().
Diffstat (limited to 'indra/llcommon')
-rwxr-xr-x | indra/llcommon/llcoros.cpp | 10 | ||||
-rwxr-xr-x | indra/llcommon/llcoros.h | 35 | ||||
-rwxr-xr-x | indra/llcommon/lleventcoro.cpp | 119 | ||||
-rwxr-xr-x | indra/llcommon/lleventcoro.h | 122 | ||||
-rwxr-xr-x | indra/llcommon/tests/lleventcoro_test.cpp | 5 |
5 files changed, 156 insertions, 135 deletions
diff --git a/indra/llcommon/llcoros.cpp b/indra/llcommon/llcoros.cpp index 2d0c419ae0..957fe034e1 100755 --- a/indra/llcommon/llcoros.cpp +++ b/indra/llcommon/llcoros.cpp @@ -69,9 +69,9 @@ sCurrentSelf(no_cleanup); } // anonymous //static -LLCoros::coro::self& LLCoros::get_self() +LLCoros::coro::self& llcoro::get_self() { - coro::self* current_self = sCurrentSelf.get(); + LLCoros::coro::self* current_self = sCurrentSelf.get(); if (! current_self) { LL_ERRS("LLCoros") << "Calling get_self() from non-coroutine context!" << LL_ENDL; @@ -79,7 +79,7 @@ LLCoros::coro::self& LLCoros::get_self() return *current_self; } -LLCoros::Suspending::Suspending(): +llcoro::Suspending::Suspending(): mSuspended(sCurrentSelf.get()) { // For the duration of our time away from this coroutine, sCurrentSelf @@ -87,7 +87,7 @@ LLCoros::Suspending::Suspending(): sCurrentSelf.reset(); } -LLCoros::Suspending::~Suspending() +llcoro::Suspending::~Suspending() { // Okay, we're back, reinstate previous value of sCurrentSelf. sCurrentSelf.reset(mSuspended); @@ -171,7 +171,7 @@ bool LLCoros::kill(const std::string& name) std::string LLCoros::getName() const { // Walk the existing coroutines, looking for the current one. - void* self_id = get_self().get_id(); + void* self_id = llcoro::get_self().get_id(); for (CoroMap::const_iterator mi(mCoros.begin()), mend(mCoros.end()); mi != mend; ++mi) { namespace coro_private = boost::dcoroutines::detail; diff --git a/indra/llcommon/llcoros.h b/indra/llcommon/llcoros.h index 3f58a17aa9..e478600f00 100755 --- a/indra/llcommon/llcoros.h +++ b/indra/llcommon/llcoros.h @@ -137,21 +137,6 @@ public: */ std::string getName() const; - /// get the current coro::self& for those who really really care - static coro::self& get_self(); - - /// Instantiate one of these in a block surrounding any leaf point when - /// control literally switches away from this coroutine. - class Suspending - { - public: - Suspending(); - ~Suspending(); - - private: - coro::self* mSuspended; - }; - /// for delayed initialization void setStackSize(S32 stacksize); @@ -166,4 +151,24 @@ private: CoroMap mCoros; }; +namespace llcoro +{ + +/// get the current coro::self& for those who really really care +LLCoros::coro::self& get_self(); + +/// Instantiate one of these in a block surrounding any leaf point when +/// control literally switches away from this coroutine. +class Suspending +{ +public: + Suspending(); + ~Suspending(); + +private: + LLCoros::coro::self* mSuspended; +}; + +} // namespace llcoro + #endif /* ! defined(LL_LLCOROS_H) */ diff --git a/indra/llcommon/lleventcoro.cpp b/indra/llcommon/lleventcoro.cpp index be93e9c83b..b7e7edec5a 100755 --- a/indra/llcommon/lleventcoro.cpp +++ b/indra/llcommon/lleventcoro.cpp @@ -41,7 +41,23 @@ #include "llerror.h" #include "llcoros.h" -std::string LLEventDetail::listenerNameForCoro() +namespace +{ + +/** + * waitForEventOn() permits a coroutine to temporarily listen on an + * LLEventPump any number of times. We don't really want to have to ask + * the caller to label each such call with a distinct string; the whole + * point of waitForEventOn() is to present a nice sequential interface to + * the underlying LLEventPump-with-named-listeners machinery. So we'll use + * LLEventPump::inventName() to generate a distinct name for each + * temporary listener. On the other hand, because a given coroutine might + * call waitForEventOn() any number of times, we don't really want to + * consume an arbitrary number of generated inventName()s: that namespace, + * though large, is nonetheless finite. So we memoize an invented name for + * each distinct coroutine instance. + */ +std::string listenerNameForCoro() { // If this coroutine was launched by LLCoros::launch(), find that name. std::string name(LLCoros::instance().getName()); @@ -56,7 +72,25 @@ std::string LLEventDetail::listenerNameForCoro() return name; } -void LLEventDetail::storeToLLSDPath(LLSD& dest, const LLSD& rawPath, const LLSD& value) +/** + * Implement behavior described for postAndWait()'s @a replyPumpNamePath + * parameter: + * + * * If <tt>path.isUndefined()</tt>, do nothing. + * * If <tt>path.isString()</tt>, @a dest is an LLSD map: store @a value + * into <tt>dest[path.asString()]</tt>. + * * If <tt>path.isInteger()</tt>, @a dest is an LLSD array: store @a + * value into <tt>dest[path.asInteger()]</tt>. + * * If <tt>path.isArray()</tt>, iteratively apply the rules above to step + * down through the structure of @a dest. The last array entry in @a + * path specifies the entry in the lowest-level structure in @a dest + * into which to store @a value. + * + * @note + * In the degenerate case in which @a path is an empty array, @a dest will + * @em become @a value rather than @em containing it. + */ +void storeToLLSDPath(LLSD& dest, const LLSD& rawPath, const LLSD& value) { if (rawPath.isUndefined()) { @@ -109,14 +143,16 @@ void LLEventDetail::storeToLLSDPath(LLSD& dest, const LLSD& rawPath, const LLSD& *pdest = value; } -LLSD postAndWait(const LLSD& event, const LLEventPumpOrPumpName& requestPump, - const LLEventPumpOrPumpName& replyPump, const LLSD& replyPumpNamePath) +} // anonymous + +LLSD llcoro::postAndWait(const LLSD& event, const LLEventPumpOrPumpName& requestPump, + const LLEventPumpOrPumpName& replyPump, const LLSD& replyPumpNamePath) { // declare the future - boost::dcoroutines::future<LLSD> future(LLCoros::get_self()); + boost::dcoroutines::future<LLSD> future(llcoro::get_self()); // make a callback that will assign a value to the future, and listen on // the specified LLEventPump with that callback - std::string listenerName(LLEventDetail::listenerNameForCoro()); + std::string listenerName(listenerNameForCoro()); LLTempBoundListener connection( replyPump.getPump().listen(listenerName, voidlistener(boost::dcoroutines::make_callback(future)))); @@ -126,7 +162,7 @@ LLSD postAndWait(const LLSD& event, const LLEventPumpOrPumpName& requestPump, // If replyPumpNamePath is non-empty, store the replyPump name in the // request event. LLSD modevent(event); - LLEventDetail::storeToLLSDPath(modevent, replyPumpNamePath, replyPump.getPump().getName()); + storeToLLSDPath(modevent, replyPumpNamePath, replyPump.getPump().getName()); LL_DEBUGS("lleventcoro") << "postAndWait(): coroutine " << listenerName << " posting to " << requestPump.getPump().getName() << LL_ENDL; @@ -142,7 +178,7 @@ LLSD postAndWait(const LLSD& event, const LLEventPumpOrPumpName& requestPump, LLSD value; { // instantiate Suspending to manage the "current" coroutine - LLCoros::Suspending suspended; + llcoro::Suspending suspended; value = *future; } // destroy Suspending as soon as we're back LL_DEBUGS("lleventcoro") << "postAndWait(): coroutine " << listenerName @@ -151,6 +187,53 @@ LLSD postAndWait(const LLSD& event, const LLEventPumpOrPumpName& requestPump, return value; } +namespace +{ + +/** + * This helper is specifically for the two-pump version of waitForEventOn(). + * We use a single future object, but we want to listen on two pumps with it. + * Since we must still adapt from (the callable constructed by) + * boost::dcoroutines::make_callback() (void return) to provide an event + * listener (bool return), we've adapted VoidListener for the purpose. The + * basic idea is that we construct a distinct instance of WaitForEventOnHelper + * -- binding different instance data -- for each of the pumps. Then, when a + * pump delivers an LLSD value to either WaitForEventOnHelper, it can combine + * that LLSD with its discriminator to feed the future object. + */ +template <typename LISTENER> +class WaitForEventOnHelper +{ +public: + WaitForEventOnHelper(const LISTENER& listener, int discriminator): + mListener(listener), + mDiscrim(discriminator) + {} + // this signature is required for an LLEventPump listener + bool operator()(const LLSD& event) + { + // our future object is defined to accept LLEventWithID + mListener(LLEventWithID(event, mDiscrim)); + // don't swallow the event, let other listeners see it + return false; + } +private: + LISTENER mListener; + const int mDiscrim; +}; + +/// WaitForEventOnHelper type-inference helper +template <typename LISTENER> +WaitForEventOnHelper<LISTENER> wfeoh(const LISTENER& listener, int discriminator) +{ + return WaitForEventOnHelper<LISTENER>(listener, discriminator); +} + +} // anonymous + +namespace llcoro +{ + LLEventWithID postAndWait2(const LLSD& event, const LLEventPumpOrPumpName& requestPump, const LLEventPumpOrPumpName& replyPump0, @@ -159,26 +242,26 @@ LLEventWithID postAndWait2(const LLSD& event, const LLSD& replyPump1NamePath) { // declare the future - boost::dcoroutines::future<LLEventWithID> future(LLCoros::get_self()); + boost::dcoroutines::future<LLEventWithID> future(llcoro::get_self()); // either callback will assign a value to this future; listen on // each specified LLEventPump with a callback - std::string name(LLEventDetail::listenerNameForCoro()); + std::string name(listenerNameForCoro()); LLTempBoundListener connection0( replyPump0.getPump().listen(name + "a", - LLEventDetail::wfeoh(boost::dcoroutines::make_callback(future), 0))); + wfeoh(boost::dcoroutines::make_callback(future), 0))); LLTempBoundListener connection1( replyPump1.getPump().listen(name + "b", - LLEventDetail::wfeoh(boost::dcoroutines::make_callback(future), 1))); + wfeoh(boost::dcoroutines::make_callback(future), 1))); // skip the "post" part if requestPump is default-constructed if (requestPump) { // If either replyPumpNamePath is non-empty, store the corresponding // replyPump name in the request event. LLSD modevent(event); - LLEventDetail::storeToLLSDPath(modevent, replyPump0NamePath, - replyPump0.getPump().getName()); - LLEventDetail::storeToLLSDPath(modevent, replyPump1NamePath, - replyPump1.getPump().getName()); + storeToLLSDPath(modevent, replyPump0NamePath, + replyPump0.getPump().getName()); + storeToLLSDPath(modevent, replyPump1NamePath, + replyPump1.getPump().getName()); LL_DEBUGS("lleventcoro") << "postAndWait2(): coroutine " << name << " posting to " << requestPump.getPump().getName() << ": " << modevent << LL_ENDL; @@ -191,7 +274,7 @@ LLEventWithID postAndWait2(const LLSD& event, LLEventWithID value; { // instantiate Suspending to manage "current" coroutine - LLCoros::Suspending suspended; + llcoro::Suspending suspended; value = *future; } // destroy Suspending as soon as we're back LL_DEBUGS("lleventcoro") << "postAndWait(): coroutine " << name @@ -227,3 +310,5 @@ LLSD errorLog(const LLEventWithID& result, const std::string& desc) // A simple return must therefore be from the reply pump (pump 0). return result.first; } + +} // namespace llcoro diff --git a/indra/llcommon/lleventcoro.h b/indra/llcommon/lleventcoro.h index daf9360a2e..2a60f2b1e0 100755 --- a/indra/llcommon/lleventcoro.h +++ b/indra/llcommon/lleventcoro.h @@ -72,13 +72,16 @@ private: boost::optional<LLEventPump&> mPump; }; +namespace llcoro +{ + /// This is an adapter for a signature like void LISTENER(const LLSD&), which /// isn't a valid LLEventPump listener: such listeners should return bool. template <typename LISTENER> -class LLVoidListener +class VoidListener { public: - LLVoidListener(const LISTENER& listener): + VoidListener(const LISTENER& listener): mListener(listener) {} bool operator()(const LLSD& event) @@ -91,51 +94,13 @@ private: LISTENER mListener; }; -/// LLVoidListener helper function to infer the type of the LISTENER +/// VoidListener helper function to infer the type of the LISTENER template <typename LISTENER> -LLVoidListener<LISTENER> voidlistener(const LISTENER& listener) +VoidListener<LISTENER> voidlistener(const LISTENER& listener) { - return LLVoidListener<LISTENER>(listener); + return VoidListener<LISTENER>(listener); } -namespace LLEventDetail -{ - /** - * waitForEventOn() permits a coroutine to temporarily listen on an - * LLEventPump any number of times. We don't really want to have to ask - * the caller to label each such call with a distinct string; the whole - * point of waitForEventOn() is to present a nice sequential interface to - * the underlying LLEventPump-with-named-listeners machinery. So we'll use - * LLEventPump::inventName() to generate a distinct name for each - * temporary listener. On the other hand, because a given coroutine might - * call waitForEventOn() any number of times, we don't really want to - * consume an arbitrary number of generated inventName()s: that namespace, - * though large, is nonetheless finite. So we memoize an invented name for - * each distinct coroutine instance. - */ - std::string listenerNameForCoro(); - - /** - * Implement behavior described for postAndWait()'s @a replyPumpNamePath - * parameter: - * - * * If <tt>path.isUndefined()</tt>, do nothing. - * * If <tt>path.isString()</tt>, @a dest is an LLSD map: store @a value - * into <tt>dest[path.asString()]</tt>. - * * If <tt>path.isInteger()</tt>, @a dest is an LLSD array: store @a - * value into <tt>dest[path.asInteger()]</tt>. - * * If <tt>path.isArray()</tt>, iteratively apply the rules above to step - * down through the structure of @a dest. The last array entry in @a - * path specifies the entry in the lowest-level structure in @a dest - * into which to store @a value. - * - * @note - * In the degenerate case in which @a path is an empty array, @a dest will - * @em become @a value rather than @em containing it. - */ - LL_COMMON_API void storeToLLSDPath(LLSD& dest, const LLSD& path, const LLSD& value); -} // namespace LLEventDetail - /** * Post specified LLSD event on the specified LLEventPump, then wait for a * response on specified other LLEventPump. This is more than mere @@ -196,50 +161,13 @@ LLSD waitForEventOn(const LLEventPumpOrPumpName& pump) return postAndWait(LLSD(), LLEventPumpOrPumpName(), pump); } +} // namespace llcoro + /// return type for two-pump variant of waitForEventOn() typedef std::pair<LLSD, int> LLEventWithID; -namespace LLEventDetail +namespace llcoro { - /** - * This helper is specifically for the two-pump version of waitForEventOn(). - * We use a single future object, but we want to listen on two pumps with it. - * Since we must still adapt from (the callable constructed by) - * boost::dcoroutines::make_callback() (void return) to provide an event - * listener (bool return), we've adapted LLVoidListener for the purpose. The - * basic idea is that we construct a distinct instance of WaitForEventOnHelper - * -- binding different instance data -- for each of the pumps. Then, when a - * pump delivers an LLSD value to either WaitForEventOnHelper, it can combine - * that LLSD with its discriminator to feed the future object. - */ - template <typename LISTENER> - class WaitForEventOnHelper - { - public: - WaitForEventOnHelper(const LISTENER& listener, int discriminator): - mListener(listener), - mDiscrim(discriminator) - {} - // this signature is required for an LLEventPump listener - bool operator()(const LLSD& event) - { - // our future object is defined to accept LLEventWithID - mListener(LLEventWithID(event, mDiscrim)); - // don't swallow the event, let other listeners see it - return false; - } - private: - LISTENER mListener; - const int mDiscrim; - }; - - /// WaitForEventOnHelper type-inference helper - template <typename LISTENER> - WaitForEventOnHelper<LISTENER> wfeoh(const LISTENER& listener, int discriminator) - { - return WaitForEventOnHelper<LISTENER>(listener, discriminator); - } -} // namespace LLEventDetail /** * This function waits for a reply on either of two specified LLEventPumps. @@ -334,6 +262,8 @@ private: */ LL_COMMON_API LLSD errorLog(const LLEventWithID& result, const std::string& desc); +} // namespace llcoro + /** * Certain event APIs require the name of an LLEventPump on which they should * post results. While it works to invent a distinct name and let @@ -365,13 +295,13 @@ public: */ LLSD wait() { - return ::waitForEventOn(mPump); + return llcoro::waitForEventOn(mPump); } LLSD postAndWait(const LLSD& event, const LLEventPumpOrPumpName& requestPump, const LLSD& replyPumpNamePath=LLSD()) { - return ::postAndWait(event, requestPump, mPump, replyPumpNamePath); + return llcoro::postAndWait(event, requestPump, mPump, replyPumpNamePath); } private: @@ -410,19 +340,19 @@ public: /// waitForEventOn(either of our two LLEventPumps) LLEventWithID wait() { - return waitForEventOn(mPump0, mPump1); + return llcoro::waitForEventOn(mPump0, mPump1); } /// errorException(wait()) LLSD waitWithException() { - return errorException(wait(), std::string("Error event on ") + getName1()); + return llcoro::errorException(wait(), std::string("Error event on ") + getName1()); } /// errorLog(wait()) LLSD waitWithLog() { - return errorLog(wait(), std::string("Error event on ") + getName1()); + return llcoro::errorLog(wait(), std::string("Error event on ") + getName1()); } LLEventWithID postAndWait(const LLSD& event, @@ -430,8 +360,8 @@ public: const LLSD& replyPump0NamePath=LLSD(), const LLSD& replyPump1NamePath=LLSD()) { - return postAndWait2(event, requestPump, mPump0, mPump1, - replyPump0NamePath, replyPump1NamePath); + return llcoro::postAndWait2(event, requestPump, mPump0, mPump1, + replyPump0NamePath, replyPump1NamePath); } LLSD postAndWaitWithException(const LLSD& event, @@ -439,9 +369,9 @@ public: const LLSD& replyPump0NamePath=LLSD(), const LLSD& replyPump1NamePath=LLSD()) { - return errorException(postAndWait(event, requestPump, - replyPump0NamePath, replyPump1NamePath), - std::string("Error event on ") + getName1()); + return llcoro::errorException(postAndWait(event, requestPump, + replyPump0NamePath, replyPump1NamePath), + std::string("Error event on ") + getName1()); } LLSD postAndWaitWithLog(const LLSD& event, @@ -449,9 +379,9 @@ public: const LLSD& replyPump0NamePath=LLSD(), const LLSD& replyPump1NamePath=LLSD()) { - return errorLog(postAndWait(event, requestPump, - replyPump0NamePath, replyPump1NamePath), - std::string("Error event on ") + getName1()); + return llcoro::errorLog(postAndWait(event, requestPump, + replyPump0NamePath, replyPump1NamePath), + std::string("Error event on ") + getName1()); } private: diff --git a/indra/llcommon/tests/lleventcoro_test.cpp b/indra/llcommon/tests/lleventcoro_test.cpp index da927038ab..79bcfe58ed 100755 --- a/indra/llcommon/tests/lleventcoro_test.cpp +++ b/indra/llcommon/tests/lleventcoro_test.cpp @@ -86,6 +86,8 @@ #include "lleventcoro.h" #include "../test/debug.h" +using namespace llcoro; + /***************************************************************************** * from the banana.cpp example program borrowed for test<1>() *****************************************************************************/ @@ -259,8 +261,7 @@ namespace tut // Construct the coroutine instance that will run explicit_wait. // Pass the ctor a callable that accepts the coroutine_type::self // param passed by the library. - boost::dcoroutines::coroutine<void()> - coro(explicit_wait); + boost::dcoroutines::coroutine<void()> coro(explicit_wait); // Start the coroutine coro(std::nothrow); // When the coroutine waits for the event pump, it returns here. |