summaryrefslogtreecommitdiff
path: root/indra/llcommon/llevents.h
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llcommon/llevents.h')
-rw-r--r--indra/llcommon/llevents.h203
1 files changed, 50 insertions, 153 deletions
diff --git a/indra/llcommon/llevents.h b/indra/llcommon/llevents.h
index 73a35af035..2f6515a4cb 100644
--- a/indra/llcommon/llevents.h
+++ b/indra/llcommon/llevents.h
@@ -19,6 +19,7 @@
#include <map>
#include <set>
#include <vector>
+#include <list>
#include <deque>
#include <stdexcept>
#include <boost/signals2.hpp>
@@ -27,9 +28,13 @@
#include <boost/enable_shared_from_this.hpp>
#include <boost/utility.hpp> // noncopyable
#include <boost/optional/optional.hpp>
+#include <boost/ptr_container/ptr_vector.hpp>
#include <boost/visit_each.hpp>
#include <boost/ref.hpp> // reference_wrapper
#include <boost/type_traits/is_pointer.hpp>
+#include <boost/utility/addressof.hpp>
+#include <boost/preprocessor/repetition/enum_params.hpp>
+#include <boost/preprocessor/iteration/local.hpp>
#include <boost/function.hpp>
#include <boost/static_assert.hpp>
#include "llsd.h"
@@ -106,9 +111,6 @@ typedef LLStandardSignal::slot_type LLEventListener;
/// Result of registering a listener, supports <tt>connected()</tt>,
/// <tt>disconnect()</tt> and <tt>blocked()</tt>
typedef boost::signals2::connection LLBoundListener;
-/// Storing an LLBoundListener in LLTempBoundListener will disconnect the
-/// referenced listener when the LLTempBoundListener instance is destroyed.
-typedef boost::signals2::scoped_connection LLTempBoundListener;
/**
* A common idiom for event-based code is to accept either a callable --
@@ -125,7 +127,7 @@ typedef boost::signals2::scoped_connection LLTempBoundListener;
* LLListenerOrPumpName::Empty. Test for this condition beforehand using
* either <tt>if (param)</tt> or <tt>if (! param)</tt>.
*/
-class LL_COMMON_API LLListenerOrPumpName
+class LLListenerOrPumpName
{
public:
/// passing string name of LLEventPump
@@ -172,13 +174,13 @@ private:
/*****************************************************************************
* LLEventPumps
*****************************************************************************/
-class LL_COMMON_API LLEventPump;
+class LLEventPump;
/**
* LLEventPumps is a Singleton manager through which one typically accesses
* this subsystem.
*/
-class LL_COMMON_API LLEventPumps: public LLSingleton<LLEventPumps>
+class LLEventPumps: public LLSingleton<LLEventPumps>
{
friend class LLSingleton<LLEventPumps>;
public:
@@ -253,61 +255,13 @@ namespace LLEventDetail
} // namespace LLEventDetail
/*****************************************************************************
-* LLEventTrackable
-*****************************************************************************/
-/**
- * LLEventTrackable wraps boost::signals2::trackable, which resembles
- * boost::trackable. Derive your listener class from LLEventTrackable instead,
- * and use something like
- * <tt>LLEventPump::listen(boost::bind(&YourTrackableSubclass::method,
- * instance, _1))</tt>. This will implicitly disconnect when the object
- * referenced by @c instance is destroyed.
- *
- * @note
- * LLEventTrackable doesn't address a couple of cases:
- * * Object destroyed during call
- * - You enter a slot call in thread A.
- * - Thread B destroys the object, which of course disconnects it from any
- * future slot calls.
- * - Thread A's call uses 'this', which now refers to a defunct object.
- * Undefined behavior results.
- * * Call during destruction
- * - @c MySubclass is derived from LLEventTrackable.
- * - @c MySubclass registers one of its own methods using
- * <tt>LLEventPump::listen()</tt>.
- * - The @c MySubclass object begins destruction. <tt>~MySubclass()</tt>
- * runs, destroying state specific to the subclass. (For instance, a
- * <tt>Foo*</tt> data member is <tt>delete</tt>d but not zeroed.)
- * - The listening method will not be disconnected until
- * <tt>~LLEventTrackable()</tt> runs.
- * - Before we get there, another thread posts data to the @c LLEventPump
- * instance, calling the @c MySubclass method.
- * - The method in question relies on valid @c MySubclass state. (For
- * instance, it attempts to dereference the <tt>Foo*</tt> pointer that was
- * <tt>delete</tt>d but not zeroed.)
- * - Undefined behavior results.
- * If you suspect you may encounter any such scenario, you're better off
- * managing the lifespan of your object with <tt>boost::shared_ptr</tt>.
- * Passing <tt>LLEventPump::listen()</tt> a <tt>boost::bind()</tt> expression
- * involving a <tt>boost::weak_ptr<Foo></tt> is recognized specially, engaging
- * thread-safe Boost.Signals2 machinery.
- */
-typedef boost::signals2::trackable LLEventTrackable;
-
-/*****************************************************************************
* LLEventPump
*****************************************************************************/
/**
* LLEventPump is the base class interface through which we access the
* concrete subclasses LLEventStream and LLEventQueue.
- *
- * @NOTE
- * LLEventPump derives from LLEventTrackable so that when you "chain"
- * LLEventPump instances together, they will automatically disconnect on
- * destruction. Please see LLEventTrackable documentation for situations in
- * which this may be perilous across threads.
*/
-class LL_COMMON_API LLEventPump: public LLEventTrackable
+class LLEventPump: boost::noncopyable
{
public:
/**
@@ -410,22 +364,10 @@ public:
* themselves. listen() can throw any ListenError; see ListenError
* subclasses.
*
- * The listener name must be unique among active listeners for this
- * LLEventPump, else you get DupListenerName. If you don't care to invent
- * a name yourself, use inventName(). (I was tempted to recognize e.g. ""
- * and internally generate a distinct name for that case. But that would
- * handle badly the scenario in which you want to add, remove, re-add,
- * etc. the same listener: each new listen() call would necessarily
- * perform a new dependency sort. Assuming you specify the same
- * after/before lists each time, using inventName() when you first
- * instantiate your listener, then passing the same name on each listen()
- * call, allows us to optimize away the second and subsequent dependency
- * sorts.
- *
- * If (as is typical) you pass a <tt>boost::bind()</tt> expression as @a
- * listener, listen() will inspect the components of that expression. If a
- * bound object matches any of several cases, the connection will
- * automatically be disconnected when that object is destroyed.
+ * If (as is typical) you pass a <tt>boost::bind()</tt> expression,
+ * listen() will inspect the components of that expression. If a bound
+ * object matches any of several cases, the connection will automatically
+ * be disconnected when that object is destroyed.
*
* * You bind a <tt>boost::weak_ptr</tt>.
* * Binding a <tt>boost::shared_ptr</tt> that way would ensure that the
@@ -487,9 +429,6 @@ public:
/// query
virtual bool enabled() const { return mEnabled; }
- /// Generate a distinct name for a listener -- see listen()
- static std::string inventName(const std::string& pfx="listener");
-
private:
friend class LLEventPumps;
/// flush queued events
@@ -528,7 +467,7 @@ protected:
* LLEventStream is a thin wrapper around LLStandardSignal. Posting an
* event immediately calls all registered listeners.
*/
-class LL_COMMON_API LLEventStream: public LLEventPump
+class LLEventStream: public LLEventPump
{
public:
LLEventStream(const std::string& name, bool tweak=false): LLEventPump(name, tweak) {}
@@ -545,7 +484,7 @@ public:
* LLEventQueue isa LLEventPump whose post() method defers calling registered
* listeners until flush() is called.
*/
-class LL_COMMON_API LLEventQueue: public LLEventPump
+class LLEventQueue: public LLEventPump
{
public:
LLEventQueue(const std::string& name, bool tweak=false): LLEventPump(name, tweak) {}
@@ -564,89 +503,47 @@ private:
};
/*****************************************************************************
-* LLReqID
+* LLEventTrackable and underpinnings
*****************************************************************************/
/**
- * This class helps the implementer of a given event API to honor the
- * ["reqid"] convention. By this convention, each event API stamps into its
- * response LLSD a ["reqid"] key whose value echoes the ["reqid"] value, if
- * any, from the corresponding request.
- *
- * This supports an (atypical, but occasionally necessary) use case in which
- * two or more asynchronous requests are multiplexed onto the same ["reply"]
- * LLEventPump. Since the response events could arrive in arbitrary order, the
- * caller must be able to demux them. It does so by matching the ["reqid"]
- * value in each response with the ["reqid"] value in the corresponding
- * request.
- *
- * It is the caller's responsibility to ensure distinct ["reqid"] values for
- * that case. Though LLSD::UUID is guaranteed to work, it might be overkill:
- * the "namespace" of unique ["reqid"] values is simply the set of requests
- * specifying the same ["reply"] LLEventPump name.
- *
- * Making a given event API echo the request's ["reqid"] into the response is
- * nearly trivial. This helper is mostly for mnemonic purposes, to serve as a
- * place to put these comments. We hope that each time a coder implements a
- * new event API based on some existing one, s/he will say, "Huh, what's an
- * LLReqID?" and look up this material.
- *
- * The hardest part about the convention is deciding where to store the
- * ["reqid"] value. Ironically, LLReqID can't help with that: you must store
- * an LLReqID instance in whatever storage will persist until the reply is
- * sent. For example, if the request ultimately ends up using a Responder
- * subclass, storing an LLReqID instance in the Responder works.
+ * LLEventTrackable wraps boost::signals2::trackable, which resembles
+ * boost::trackable. Derive your listener class from LLEventTrackable instead,
+ * and use something like
+ * <tt>LLEventPump::listen(boost::bind(&YourTrackableSubclass::method,
+ * instance, _1))</tt>. This will implicitly disconnect when the object
+ * referenced by @c instance is destroyed.
*
* @note
- * The @em implementer of an event API must honor the ["reqid"] convention.
- * However, the @em caller of an event API need only use it if s/he is sharing
- * the same ["reply"] LLEventPump for two or more asynchronous event API
- * requests.
- *
- * In most cases, it's far easier for the caller to instantiate a local
- * LLEventStream and pass its name to the event API in question. Then it's
- * perfectly reasonable not to set a ["reqid"] key in the request, ignoring
- * the @c isUndefined() ["reqid"] value in the response.
+ * LLEventTrackable doesn't address a couple of cases:
+ * * Object destroyed during call
+ * - You enter a slot call in thread A.
+ * - Thread B destroys the object, which of course disconnects it from any
+ * future slot calls.
+ * - Thread A's call uses 'this', which now refers to a defunct object.
+ * Undefined behavior results.
+ * * Call during destruction
+ * - @c MySubclass is derived from LLEventTrackable.
+ * - @c MySubclass registers one of its own methods using
+ * <tt>LLEventPump::listen()</tt>.
+ * - The @c MySubclass object begins destruction. <tt>~MySubclass()</tt>
+ * runs, destroying state specific to the subclass. (For instance, a
+ * <tt>Foo*</tt> data member is <tt>delete</tt>d but not zeroed.)
+ * - The listening method will not be disconnected until
+ * <tt>~LLEventTrackable()</tt> runs.
+ * - Before we get there, another thread posts data to the @c LLEventPump
+ * instance, calling the @c MySubclass method.
+ * - The method in question relies on valid @c MySubclass state. (For
+ * instance, it attempts to dereference the <tt>Foo*</tt> pointer that was
+ * <tt>delete</tt>d but not zeroed.)
+ * - Undefined behavior results.
+ * If you suspect you may encounter any such scenario, you're better off
+ * managing the lifespan of your object with <tt>boost::shared_ptr</tt>.
+ * Passing <tt>LLEventPump::listen()</tt> a <tt>boost::bind()</tt> expression
+ * involving a <tt>boost::weak_ptr<Foo></tt> is recognized specially, engaging
+ * thread-safe Boost.Signals2 machinery.
*/
-class LLReqID
-{
-public:
- /**
- * If you have the request in hand at the time you instantiate the
- * LLReqID, pass that request to extract its ["reqid"].
- */
- LLReqID(const LLSD& request):
- mReqid(request["reqid"])
- {}
- /// If you don't yet have the request, use setFrom() later.
- LLReqID() {}
-
- /// Extract and store the ["reqid"] value from an incoming request.
- void setFrom(const LLSD& request)
- {
- mReqid = request["reqid"];
- }
-
- /// Set ["reqid"] key into a pending response LLSD object.
- void stamp(LLSD& response) const;
-
- /// Make a whole new response LLSD object with our ["reqid"].
- LLSD makeResponse() const
- {
- LLSD response;
- stamp(response);
- return response;
- }
-
- /// Not really sure of a use case for this accessor...
- LLSD getReqID() const { return mReqid; }
-
-private:
- LLSD mReqid;
-};
+typedef boost::signals2::trackable LLEventTrackable;
-/*****************************************************************************
-* Underpinnings
-*****************************************************************************/
/**
* We originally provided a suite of overloaded
* LLEventTrackable::listenTo(LLEventPump&, ...) methods that would call