summaryrefslogtreecommitdiff
path: root/indra/llcommon/lleventcoro.h
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llcommon/lleventcoro.h')
-rwxr-xr-xindra/llcommon/lleventcoro.h132
1 files changed, 95 insertions, 37 deletions
diff --git a/indra/llcommon/lleventcoro.h b/indra/llcommon/lleventcoro.h
index e2ce4bb193..daf9360a2e 100755
--- a/indra/llcommon/lleventcoro.h
+++ b/indra/llcommon/lleventcoro.h
@@ -72,16 +72,13 @@ 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 VoidListener
+class LLVoidListener
{
public:
- VoidListener(const LISTENER& listener):
+ LLVoidListener(const LISTENER& listener):
mListener(listener)
{}
bool operator()(const LLSD& event)
@@ -94,19 +91,50 @@ private:
LISTENER mListener;
};
-/// VoidListener helper function to infer the type of the LISTENER
+/// LLVoidListener helper function to infer the type of the LISTENER
template <typename LISTENER>
-VoidListener<LISTENER> voidlistener(const LISTENER& listener)
+LLVoidListener<LISTENER> voidlistener(const LISTENER& listener)
{
- return VoidListener<LISTENER>(listener);
+ return LLVoidListener<LISTENER>(listener);
}
-/**
- * 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();
+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
@@ -168,13 +196,50 @@ 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 llcoro
+namespace LLEventDetail
{
+ /**
+ * 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.
@@ -243,8 +308,6 @@ 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
@@ -265,17 +328,12 @@ 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
@@ -307,13 +365,13 @@ public:
*/
LLSD wait()
{
- return llcoro::waitForEventOn(mPump);
+ return ::waitForEventOn(mPump);
}
LLSD postAndWait(const LLSD& event, const LLEventPumpOrPumpName& requestPump,
const LLSD& replyPumpNamePath=LLSD())
{
- return llcoro::postAndWait(event, requestPump, mPump, replyPumpNamePath);
+ return ::postAndWait(event, requestPump, mPump, replyPumpNamePath);
}
private:
@@ -352,19 +410,19 @@ public:
/// waitForEventOn(either of our two LLEventPumps)
LLEventWithID wait()
{
- return llcoro::waitForEventOn(mPump0, mPump1);
+ return waitForEventOn(mPump0, mPump1);
}
/// errorException(wait())
LLSD waitWithException()
{
- return llcoro::errorException(wait(), std::string("Error event on ") + getName1());
+ return errorException(wait(), std::string("Error event on ") + getName1());
}
/// errorLog(wait())
LLSD waitWithLog()
{
- return llcoro::errorLog(wait(), std::string("Error event on ") + getName1());
+ return errorLog(wait(), std::string("Error event on ") + getName1());
}
LLEventWithID postAndWait(const LLSD& event,
@@ -372,8 +430,8 @@ public:
const LLSD& replyPump0NamePath=LLSD(),
const LLSD& replyPump1NamePath=LLSD())
{
- return llcoro::postAndWait2(event, requestPump, mPump0, mPump1,
- replyPump0NamePath, replyPump1NamePath);
+ return postAndWait2(event, requestPump, mPump0, mPump1,
+ replyPump0NamePath, replyPump1NamePath);
}
LLSD postAndWaitWithException(const LLSD& event,
@@ -381,9 +439,9 @@ public:
const LLSD& replyPump0NamePath=LLSD(),
const LLSD& replyPump1NamePath=LLSD())
{
- return llcoro::errorException(postAndWait(event, requestPump,
- replyPump0NamePath, replyPump1NamePath),
- std::string("Error event on ") + getName1());
+ return errorException(postAndWait(event, requestPump,
+ replyPump0NamePath, replyPump1NamePath),
+ std::string("Error event on ") + getName1());
}
LLSD postAndWaitWithLog(const LLSD& event,
@@ -391,9 +449,9 @@ public:
const LLSD& replyPump0NamePath=LLSD(),
const LLSD& replyPump1NamePath=LLSD())
{
- return llcoro::errorLog(postAndWait(event, requestPump,
- replyPump0NamePath, replyPump1NamePath),
- std::string("Error event on ") + getName1());
+ return errorLog(postAndWait(event, requestPump,
+ replyPump0NamePath, replyPump1NamePath),
+ std::string("Error event on ") + getName1());
}
private: