From 6f9f89ee71751a0e88bbda91fef1a575a5a68ed9 Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Fri, 10 Jul 2015 16:47:07 -0400
Subject: Backed out changeset 6e1fa9518747: reapply 'selfless' changes

---
 indra/llcommon/llcoros.cpp                |  10 +--
 indra/llcommon/llcoros.h                  |  35 ++++----
 indra/llcommon/lleventcoro.cpp            | 127 ++++++++++++++++++++++++----
 indra/llcommon/lleventcoro.h              | 132 +++++++++---------------------
 indra/llcommon/tests/lleventcoro_test.cpp |   5 +-
 5 files changed, 175 insertions(+), 134 deletions(-)

(limited to 'indra/llcommon')

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..ad02e139b8 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,24 @@ 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
+
+void llcoro::yield()
+{
+    // By viewer convention, we post an event on the "mainloop" LLEventPump
+    // each iteration of the main event-handling loop. So waiting for a single
+    // event on "mainloop" gives us a one-frame yield.
+    waitForEventOn("mainloop");
+}
+
+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 +170,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 +186,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 +195,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 +250,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 +282,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 +318,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..e2ce4bb193 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,50 +94,19 @@ 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
+/**
+ * Yield control from a coroutine for one "mainloop" tick. If your coroutine
+ * runs without suspending for nontrivial time, sprinkle in calls to this
+ * function to avoid stalling the rest of the viewer processing.
+ */
+void yield();
 
 /**
  * Post specified LLSD event on the specified LLEventPump, then wait for a
@@ -196,50 +168,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.
@@ -308,6 +243,8 @@ waitForEventOn(const LLEventPumpOrPumpName& pump0, const LLEventPumpOrPumpName&
  */
 LLSD errorException(const LLEventWithID& result, const std::string& desc);
 
+} // namespace llcoro
+
 /**
  * Exception thrown by errorException(). We don't call this LLEventError
  * because it's not an error in event processing: rather, this exception
@@ -328,12 +265,17 @@ private:
     LLSD mData;
 };
 
+namespace llcoro
+{
+
 /**
  * Like errorException(), save that this trips a fatal error using LL_ERRS
  * rather than throwing an exception.
  */
 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 +307,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 +352,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 +372,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 +381,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 +391,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.
-- 
cgit v1.2.3