summaryrefslogtreecommitdiff
path: root/indra/llcommon
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llcommon')
-rw-r--r--indra/llcommon/lleventfilter.cpp13
-rw-r--r--indra/llcommon/lleventfilter.h7
-rw-r--r--indra/llcommon/llevents.cpp11
-rw-r--r--indra/llcommon/llevents.h115
4 files changed, 80 insertions, 66 deletions
diff --git a/indra/llcommon/lleventfilter.cpp b/indra/llcommon/lleventfilter.cpp
index da19946e3b..2b5401e9f7 100644
--- a/indra/llcommon/lleventfilter.cpp
+++ b/indra/llcommon/lleventfilter.cpp
@@ -365,21 +365,22 @@ bool LLEventLogProxy::post(const LLSD& event) /* override */
}
LLBoundListener LLEventLogProxy::listen_impl(const std::string& name,
- const LLEventListener& target,
+ const LLAwareListener& target,
const NameList& after,
const NameList& before)
{
LL_DEBUGS("LogProxy") << "LLEventLogProxy('" << getName() << "').listen('"
<< name << "')" << LL_ENDL;
return mPump.listen(name,
- [this, name, target](const LLSD& event)->bool
- { return listener(name, target, event); },
+ [this, name, target](const LLBoundListener& conn, const LLSD& event)
+ { return listener(conn, name, target, event); },
after,
before);
}
-bool LLEventLogProxy::listener(const std::string& name,
- const LLEventListener& target,
+bool LLEventLogProxy::listener(const LLBoundListener& conn,
+ const std::string& name,
+ const LLAwareListener& target,
const LLSD& event) const
{
auto eventminus = event;
@@ -391,7 +392,7 @@ bool LLEventLogProxy::listener(const std::string& name,
}
std::string hdr{STRINGIZE(getName() << " to " << name << " " << counter)};
LL_INFOS("LogProxy") << hdr << ": " << eventminus << LL_ENDL;
- bool result = target(eventminus);
+ bool result = target(conn, eventminus);
LL_INFOS("LogProxy") << hdr << " => " << result << LL_ENDL;
return result;
}
diff --git a/indra/llcommon/lleventfilter.h b/indra/llcommon/lleventfilter.h
index 9988459aae..de706d72eb 100644
--- a/indra/llcommon/lleventfilter.h
+++ b/indra/llcommon/lleventfilter.h
@@ -459,7 +459,7 @@ public:
LLEventLogProxy(LLEventPump& source, const std::string& name, bool tweak=false);
/// register a new listener
- LLBoundListener listen_impl(const std::string& name, const LLEventListener& target,
+ LLBoundListener listen_impl(const std::string& name, const LLAwareListener& target,
const NameList& after, const NameList& before);
/// Post an event to all listeners
@@ -469,8 +469,9 @@ private:
/// This method intercepts each call to any target listener. We pass it
/// the listener name and the caller's intended target listener plus the
/// posted LLSD event.
- bool listener(const std::string& name,
- const LLEventListener& target,
+ bool listener(const LLBoundListener& conn,
+ const std::string& name,
+ const LLAwareListener& target,
const LLSD& event) const;
LLEventPump& mPump;
diff --git a/indra/llcommon/llevents.cpp b/indra/llcommon/llevents.cpp
index 5a6e13cb7d..98bd990f31 100644
--- a/indra/llcommon/llevents.cpp
+++ b/indra/llcommon/llevents.cpp
@@ -415,7 +415,7 @@ void LLEventPump::reset()
//mDeps.clear();
}
-LLBoundListener LLEventPump::listen_impl(const std::string& name, const LLEventListener& listener,
+LLBoundListener LLEventPump::listen_impl(const std::string& name, const LLAwareListener& listener,
const NameList& after,
const NameList& before)
{
@@ -575,7 +575,7 @@ LLBoundListener LLEventPump::listen_impl(const std::string& name, const LLEventL
}
// Now that newNode has a value that places it appropriately in mSignal,
// connect it.
- LLBoundListener bound = mSignal->connect(nodePosition, listener);
+ LLBoundListener bound = mSignal->connect_extended(nodePosition, listener);
if (!name.empty())
{ // note that we are not tracking anonymous listeners here either.
@@ -659,7 +659,7 @@ bool LLEventMailDrop::post(const LLSD& event)
}
LLBoundListener LLEventMailDrop::listen_impl(const std::string& name,
- const LLEventListener& listener,
+ const LLAwareListener& listener,
const NameList& after,
const NameList& before)
{
@@ -668,7 +668,10 @@ LLBoundListener LLEventMailDrop::listen_impl(const std::string& name,
// Remove any that this listener consumes -- Effective STL, Item 9.
for (auto hi(mEventHistory.begin()), hend(mEventHistory.end()); hi != hend; )
{
- if (listener(*hi))
+ // We don't actually have an LLBoundListener in hand, and we won't
+ // until the base-class listen_impl() call below. Pass an empty
+ // instance.
+ if (listener({}, *hi))
{
// new listener consumed this event, erase it
hi = mEventHistory.erase(hi);
diff --git a/indra/llcommon/llevents.h b/indra/llcommon/llevents.h
index d0686bd8b5..abc25ba400 100644
--- a/indra/llcommon/llevents.h
+++ b/indra/llcommon/llevents.h
@@ -32,12 +32,13 @@
#if ! defined(LL_LLEVENTS_H)
#define LL_LLEVENTS_H
-#include <string>
+#include <deque>
+#include <functional>
#include <map>
#include <set>
+#include <string>
+#include <type_traits>
#include <vector>
-#include <deque>
-#include <functional>
#if LL_WINDOWS
#pragma warning (push)
#pragma warning (disable : 4263) // boost::signals2::expired_slot::what() has const mismatch
@@ -137,6 +138,10 @@ typedef boost::signals2::signal<bool(const LLSD&), LLStopWhenHandled, float> LL
/// Methods that forward listeners (e.g. constructed with
/// <tt>boost::bind()</tt>) should accept (const LLEventListener&)
typedef LLStandardSignal::slot_type LLEventListener;
+/// Support a listener accepting (const LLBoundListener&, const LLSD&).
+/// Note that LLBoundListener::disconnect() is a const method: this feature is
+/// specifically intended to allow a listener to disconnect itself when done.
+typedef LLStandardSignal::extended_slot_type LLAwareListener;
/// Accept a void listener too
typedef std::function<void(const LLSD&)> LLVoidListener;
/// Result of registering a listener, supports <tt>connected()</tt>,
@@ -359,56 +364,13 @@ testable:
};
/*****************************************************************************
-* 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.
- */
-typedef boost::signals2::trackable LLEventTrackable;
-
-/*****************************************************************************
* LLEventPump
*****************************************************************************/
/**
* LLEventPump is the base class interface through which we access the
* concrete subclasses such as LLEventStream.
- *
- * @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 LL_COMMON_API LLEventPump
{
public:
static const std::string ANONYMOUS; // constant for anonymous listeners.
@@ -522,18 +484,37 @@ public:
* call, allows us to optimize away the second and subsequent dependency
* sorts.
*
- * If name is set to LLEventPump::ANONYMOUS listen will bypass the entire
+ * If name is set to LLEventPump::ANONYMOUS, listen() will bypass the entire
* dependency and ordering calculation. In this case, it is critical that
* the result be assigned to a LLTempBoundListener or the listener is
- * manually disconnected when no longer needed since there will be no
+ * manually disconnected when no longer needed, since there will be no
* way to later find and disconnect this listener manually.
*/
+ template <typename LISTENER>
LLBoundListener listen(const std::string& name,
- const LLEventListener& listener,
+ LISTENER&& listener,
const NameList& after=NameList(),
const NameList& before=NameList())
{
- return listen_impl(name, listener, after, before);
+ if constexpr (std::is_invocable_v<LISTENER, const LLSD&>)
+ {
+ // wrap classic LLEventListener in LLAwareListener lambda
+ return listenb(
+ name,
+ [listener=std::move(listener)]
+ (const LLBoundListener&, const LLSD& event)
+ {
+ return listener(event);
+ },
+ after,
+ before);
+ }
+ else
+ {
+ static_assert(std::is_invocable_v<LISTENER, LLBoundListener, const LLSD&>,
+ "LLEventPump::listen() listener has bad parameter signature");
+ return listenb(name, std::forward<LISTENER>(listener), after, before);
+ }
}
/// Get the LLBoundListener associated with the passed name (dummy
@@ -579,7 +560,35 @@ private:
LLMutex mConnectionListMutex;
protected:
- virtual LLBoundListener listen_impl(const std::string& name, const LLEventListener&,
+ template <typename LISTENER>
+ LLBoundListener listenb(const std::string& name,
+ LISTENER&& listener,
+ const NameList& after=NameList(),
+ const NameList& before=NameList())
+ {
+ using result_t = std::decay_t<decltype(listener(LLBoundListener(), LLSD()))>;
+ if constexpr (std::is_same_v<bool, result_t>)
+ {
+ return listen_impl(name, std::forward<LISTENER>(listener), after, before);
+ }
+ else
+ {
+ static_assert(std::is_same_v<void, result_t>,
+ "LLEventPump::listen() listener has bad return type");
+ // wrap void listener in one that returns bool
+ return listen_impl(
+ name,
+ [listener=std::move(listener)]
+ (const LLBoundListener& conn, const LLSD& event)
+ {
+ listener(conn, event);
+ return false;
+ },
+ after,
+ before);
+ }
+ }
+ virtual LLBoundListener listen_impl(const std::string& name, const LLAwareListener&,
const NameList& after,
const NameList& before);
@@ -654,7 +663,7 @@ public:
void discard();
protected:
- virtual LLBoundListener listen_impl(const std::string& name, const LLEventListener&,
+ virtual LLBoundListener listen_impl(const std::string& name, const LLAwareListener&,
const NameList& after,
const NameList& before) override;