PageRenderTime 166ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/llcommon/llevents.h

https://bitbucket.org/lindenlab/viewer-beta/
C++ Header | 1049 lines | 345 code | 79 blank | 625 comment | 5 complexity | 8c14d0499fa3a953471326baeef53bcc MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llevents.h
  3. * @author Kent Quirk, Nat Goodspeed
  4. * @date 2008-09-11
  5. * @brief This is an implementation of the event system described at
  6. * https://wiki.lindenlab.com/wiki/Viewer:Messaging/Event_System,
  7. * originally introduced in llnotifications.h. It has nothing
  8. * whatsoever to do with the older system in llevent.h.
  9. *
  10. * $LicenseInfo:firstyear=2008&license=viewerlgpl$
  11. * Second Life Viewer Source Code
  12. * Copyright (C) 2010, Linden Research, Inc.
  13. *
  14. * This library is free software; you can redistribute it and/or
  15. * modify it under the terms of the GNU Lesser General Public
  16. * License as published by the Free Software Foundation;
  17. * version 2.1 of the License only.
  18. *
  19. * This library is distributed in the hope that it will be useful,
  20. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  22. * Lesser General Public License for more details.
  23. *
  24. * You should have received a copy of the GNU Lesser General Public
  25. * License along with this library; if not, write to the Free Software
  26. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  27. *
  28. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  29. * $/LicenseInfo$
  30. */
  31. #if ! defined(LL_LLEVENTS_H)
  32. #define LL_LLEVENTS_H
  33. #include <string>
  34. #include <map>
  35. #include <set>
  36. #include <vector>
  37. #include <deque>
  38. #include <stdexcept>
  39. #if LL_WINDOWS
  40. #pragma warning (push)
  41. #pragma warning (disable : 4263) // boost::signals2::expired_slot::what() has const mismatch
  42. #pragma warning (disable : 4264)
  43. #endif
  44. #include <boost/signals2.hpp>
  45. #if LL_WINDOWS
  46. #pragma warning (pop)
  47. #endif
  48. #include <boost/bind.hpp>
  49. #include <boost/shared_ptr.hpp>
  50. #include <boost/enable_shared_from_this.hpp>
  51. #include <boost/utility.hpp> // noncopyable
  52. #include <boost/optional/optional.hpp>
  53. #include <boost/visit_each.hpp>
  54. #include <boost/ref.hpp> // reference_wrapper
  55. #include <boost/type_traits/is_pointer.hpp>
  56. #include <boost/function.hpp>
  57. #include <boost/static_assert.hpp>
  58. #include "llsd.h"
  59. #include "llsingleton.h"
  60. #include "lldependencies.h"
  61. #include "ll_template_cast.h"
  62. /*==========================================================================*|
  63. // override this to allow binding free functions with more parameters
  64. #ifndef LLEVENTS_LISTENER_ARITY
  65. #define LLEVENTS_LISTENER_ARITY 10
  66. #endif
  67. |*==========================================================================*/
  68. // hack for testing
  69. #ifndef testable
  70. #define testable private
  71. #endif
  72. /*****************************************************************************
  73. * Signal and handler declarations
  74. * Using a single handler signature means that we can have a common handler
  75. * type, rather than needing a distinct one for each different handler.
  76. *****************************************************************************/
  77. /**
  78. * A boost::signals Combiner that stops the first time a handler returns true
  79. * We need this because we want to have our handlers return bool, so that
  80. * we have the option to cause a handler to stop further processing. The
  81. * default handler fails when the signal returns a value but has no slots.
  82. */
  83. struct LLStopWhenHandled
  84. {
  85. typedef bool result_type;
  86. template<typename InputIterator>
  87. result_type operator()(InputIterator first, InputIterator last) const
  88. {
  89. for (InputIterator si = first; si != last; ++si)
  90. {
  91. if (*si)
  92. {
  93. return true;
  94. }
  95. }
  96. return false;
  97. }
  98. };
  99. /**
  100. * We want to have a standard signature for all signals; this way,
  101. * we can easily document a protocol for communicating across
  102. * dlls and into scripting languages someday.
  103. *
  104. * We want to return a bool to indicate whether the signal has been
  105. * handled and should NOT be passed on to other listeners.
  106. * Return true to stop further handling of the signal, and false
  107. * to continue.
  108. *
  109. * We take an LLSD because this way the contents of the signal
  110. * are independent of the API used to communicate it.
  111. * It is const ref because then there's low cost to pass it;
  112. * if you only need to inspect it, it's very cheap.
  113. *
  114. * @internal
  115. * The @c float template parameter indicates that we will internally use @c
  116. * float to indicate relative listener order on a given LLStandardSignal.
  117. * Don't worry, the @c float values are strictly internal! They are not part
  118. * of the interface, for the excellent reason that requiring the caller to
  119. * specify a numeric key to establish order means that the caller must know
  120. * the universe of possible values. We use LLDependencies for that instead.
  121. */
  122. typedef boost::signals2::signal<bool(const LLSD&), LLStopWhenHandled, float> LLStandardSignal;
  123. /// Methods that forward listeners (e.g. constructed with
  124. /// <tt>boost::bind()</tt>) should accept (const LLEventListener&)
  125. typedef LLStandardSignal::slot_type LLEventListener;
  126. /// Result of registering a listener, supports <tt>connected()</tt>,
  127. /// <tt>disconnect()</tt> and <tt>blocked()</tt>
  128. typedef boost::signals2::connection LLBoundListener;
  129. /// Storing an LLBoundListener in LLTempBoundListener will disconnect the
  130. /// referenced listener when the LLTempBoundListener instance is destroyed.
  131. typedef boost::signals2::scoped_connection LLTempBoundListener;
  132. /**
  133. * A common idiom for event-based code is to accept either a callable --
  134. * directly called on completion -- or the string name of an LLEventPump on
  135. * which to post the completion event. Specifying a parameter as <tt>const
  136. * LLListenerOrPumpName&</tt> allows either.
  137. *
  138. * Calling a validly-constructed LLListenerOrPumpName, passing the LLSD
  139. * 'event' object, either calls the callable or posts the event to the named
  140. * LLEventPump.
  141. *
  142. * A default-constructed LLListenerOrPumpName is 'empty'. (This is useful as
  143. * the default value of an optional method parameter.) Calling it throws
  144. * LLListenerOrPumpName::Empty. Test for this condition beforehand using
  145. * either <tt>if (param)</tt> or <tt>if (! param)</tt>.
  146. */
  147. class LL_COMMON_API LLListenerOrPumpName
  148. {
  149. public:
  150. /// passing string name of LLEventPump
  151. LLListenerOrPumpName(const std::string& pumpname);
  152. /// passing string literal (overload so compiler isn't forced to infer
  153. /// double conversion)
  154. LLListenerOrPumpName(const char* pumpname);
  155. /// passing listener -- the "anything else" catch-all case. The type of an
  156. /// object constructed by boost::bind() isn't intended to be written out.
  157. /// Normally we'd just accept 'const LLEventListener&', but that would
  158. /// require double implicit conversion: boost::bind() object to
  159. /// LLEventListener, LLEventListener to LLListenerOrPumpName. So use a
  160. /// template to forward anything.
  161. template<typename T>
  162. LLListenerOrPumpName(const T& listener): mListener(listener) {}
  163. /// for omitted method parameter: uninitialized mListener
  164. LLListenerOrPumpName() {}
  165. /// test for validity
  166. operator bool() const { return bool(mListener); }
  167. bool operator! () const { return ! mListener; }
  168. /// explicit accessor
  169. const LLEventListener& getListener() const { return *mListener; }
  170. /// implicit conversion to LLEventListener
  171. operator LLEventListener() const { return *mListener; }
  172. /// allow calling directly
  173. bool operator()(const LLSD& event) const;
  174. /// exception if you try to call when empty
  175. struct Empty: public std::runtime_error
  176. {
  177. Empty(const std::string& what):
  178. std::runtime_error(std::string("LLListenerOrPumpName::Empty: ") + what) {}
  179. };
  180. private:
  181. boost::optional<LLEventListener> mListener;
  182. };
  183. /*****************************************************************************
  184. * LLEventPumps
  185. *****************************************************************************/
  186. class LLEventPump;
  187. /**
  188. * LLEventPumps is a Singleton manager through which one typically accesses
  189. * this subsystem.
  190. */
  191. class LL_COMMON_API LLEventPumps: public LLSingleton<LLEventPumps>
  192. {
  193. friend class LLSingleton<LLEventPumps>;
  194. public:
  195. /**
  196. * Find or create an LLEventPump instance with a specific name. We return
  197. * a reference so there's no question about ownership. obtain() @em finds
  198. * an instance without conferring @em ownership.
  199. */
  200. LLEventPump& obtain(const std::string& name);
  201. /**
  202. * Flush all known LLEventPump instances
  203. */
  204. void flush();
  205. /**
  206. * Reset all known LLEventPump instances
  207. * workaround for DEV-35406 crash on shutdown
  208. */
  209. void reset();
  210. private:
  211. friend class LLEventPump;
  212. /**
  213. * Register a new LLEventPump instance (internal)
  214. */
  215. std::string registerNew(const LLEventPump&, const std::string& name, bool tweak);
  216. /**
  217. * Unregister a doomed LLEventPump instance (internal)
  218. */
  219. void unregister(const LLEventPump&);
  220. private:
  221. LLEventPumps();
  222. ~LLEventPumps();
  223. testable:
  224. // Map of all known LLEventPump instances, whether or not we instantiated
  225. // them. We store a plain old LLEventPump* because this map doesn't claim
  226. // ownership of the instances. Though the common usage pattern is to
  227. // request an instance using obtain(), it's fair to instantiate an
  228. // LLEventPump subclass statically, as a class member, on the stack or on
  229. // the heap. In such cases, the instantiating party is responsible for its
  230. // lifespan.
  231. typedef std::map<std::string, LLEventPump*> PumpMap;
  232. PumpMap mPumpMap;
  233. // Set of all LLEventPumps we instantiated. Membership in this set means
  234. // we claim ownership, and will delete them when this LLEventPumps is
  235. // destroyed.
  236. typedef std::set<LLEventPump*> PumpSet;
  237. PumpSet mOurPumps;
  238. // LLEventPump names that should be instantiated as LLEventQueue rather
  239. // than as LLEventStream
  240. typedef std::set<std::string> PumpNames;
  241. PumpNames mQueueNames;
  242. };
  243. /*****************************************************************************
  244. * details
  245. *****************************************************************************/
  246. namespace LLEventDetail
  247. {
  248. /// Any callable capable of connecting an LLEventListener to an
  249. /// LLStandardSignal to produce an LLBoundListener can be mapped to this
  250. /// signature.
  251. typedef boost::function<LLBoundListener(const LLEventListener&)> ConnectFunc;
  252. /// overload of visit_and_connect() when we have a string identifier available
  253. template <typename LISTENER>
  254. LLBoundListener visit_and_connect(const std::string& name,
  255. const LISTENER& listener,
  256. const ConnectFunc& connect_func);
  257. /**
  258. * Utility template function to use Visitor appropriately
  259. *
  260. * @param listener Callable to connect, typically a boost::bind()
  261. * expression. This will be visited by Visitor using boost::visit_each().
  262. * @param connect_func Callable that will connect() @a listener to an
  263. * LLStandardSignal, returning LLBoundListener.
  264. */
  265. template <typename LISTENER>
  266. LLBoundListener visit_and_connect(const LISTENER& listener,
  267. const ConnectFunc& connect_func)
  268. {
  269. return visit_and_connect("", listener, connect_func);
  270. }
  271. } // namespace LLEventDetail
  272. /*****************************************************************************
  273. * LLEventTrackable
  274. *****************************************************************************/
  275. /**
  276. * LLEventTrackable wraps boost::signals2::trackable, which resembles
  277. * boost::trackable. Derive your listener class from LLEventTrackable instead,
  278. * and use something like
  279. * <tt>LLEventPump::listen(boost::bind(&YourTrackableSubclass::method,
  280. * instance, _1))</tt>. This will implicitly disconnect when the object
  281. * referenced by @c instance is destroyed.
  282. *
  283. * @note
  284. * LLEventTrackable doesn't address a couple of cases:
  285. * * Object destroyed during call
  286. * - You enter a slot call in thread A.
  287. * - Thread B destroys the object, which of course disconnects it from any
  288. * future slot calls.
  289. * - Thread A's call uses 'this', which now refers to a defunct object.
  290. * Undefined behavior results.
  291. * * Call during destruction
  292. * - @c MySubclass is derived from LLEventTrackable.
  293. * - @c MySubclass registers one of its own methods using
  294. * <tt>LLEventPump::listen()</tt>.
  295. * - The @c MySubclass object begins destruction. <tt>~MySubclass()</tt>
  296. * runs, destroying state specific to the subclass. (For instance, a
  297. * <tt>Foo*</tt> data member is <tt>delete</tt>d but not zeroed.)
  298. * - The listening method will not be disconnected until
  299. * <tt>~LLEventTrackable()</tt> runs.
  300. * - Before we get there, another thread posts data to the @c LLEventPump
  301. * instance, calling the @c MySubclass method.
  302. * - The method in question relies on valid @c MySubclass state. (For
  303. * instance, it attempts to dereference the <tt>Foo*</tt> pointer that was
  304. * <tt>delete</tt>d but not zeroed.)
  305. * - Undefined behavior results.
  306. * If you suspect you may encounter any such scenario, you're better off
  307. * managing the lifespan of your object with <tt>boost::shared_ptr</tt>.
  308. * Passing <tt>LLEventPump::listen()</tt> a <tt>boost::bind()</tt> expression
  309. * involving a <tt>boost::weak_ptr<Foo></tt> is recognized specially, engaging
  310. * thread-safe Boost.Signals2 machinery.
  311. */
  312. typedef boost::signals2::trackable LLEventTrackable;
  313. /*****************************************************************************
  314. * LLEventPump
  315. *****************************************************************************/
  316. /**
  317. * LLEventPump is the base class interface through which we access the
  318. * concrete subclasses LLEventStream and LLEventQueue.
  319. *
  320. * @NOTE
  321. * LLEventPump derives from LLEventTrackable so that when you "chain"
  322. * LLEventPump instances together, they will automatically disconnect on
  323. * destruction. Please see LLEventTrackable documentation for situations in
  324. * which this may be perilous across threads.
  325. */
  326. class LL_COMMON_API LLEventPump: public LLEventTrackable
  327. {
  328. public:
  329. /**
  330. * Exception thrown by LLEventPump(). You are trying to instantiate an
  331. * LLEventPump (subclass) using the same name as some other instance, and
  332. * you didn't pass <tt>tweak=true</tt> to permit it to generate a unique
  333. * variant.
  334. */
  335. struct DupPumpName: public std::runtime_error
  336. {
  337. DupPumpName(const std::string& what):
  338. std::runtime_error(std::string("DupPumpName: ") + what) {}
  339. };
  340. /**
  341. * Instantiate an LLEventPump (subclass) with the string name by which it
  342. * can be found using LLEventPumps::obtain().
  343. *
  344. * If you pass (or default) @a tweak to @c false, then a duplicate name
  345. * will throw DupPumpName. This won't happen if LLEventPumps::obtain()
  346. * instantiates the LLEventPump, because obtain() uses find-or-create
  347. * logic. It can only happen if you instantiate an LLEventPump in your own
  348. * code -- and a collision with the name of some other LLEventPump is
  349. * likely to cause much more subtle problems!
  350. *
  351. * When you hand-instantiate an LLEventPump, consider passing @a tweak as
  352. * @c true. This directs LLEventPump() to append a suffix to the passed @a
  353. * name to make it unique. You can retrieve the adjusted name by calling
  354. * getName() on your new instance.
  355. */
  356. LLEventPump(const std::string& name, bool tweak=false);
  357. virtual ~LLEventPump();
  358. /// group exceptions thrown by listen(). We use exceptions because these
  359. /// particular errors are likely to be coding errors, found and fixed by
  360. /// the developer even before preliminary checkin.
  361. struct ListenError: public std::runtime_error
  362. {
  363. ListenError(const std::string& what): std::runtime_error(what) {}
  364. };
  365. /**
  366. * exception thrown by listen(). You are attempting to register a
  367. * listener on this LLEventPump using the same listener name as an
  368. * already-registered listener.
  369. */
  370. struct DupListenerName: public ListenError
  371. {
  372. DupListenerName(const std::string& what):
  373. ListenError(std::string("DupListenerName: ") + what)
  374. {}
  375. };
  376. /**
  377. * exception thrown by listen(). The order dependencies specified for your
  378. * listener are incompatible with existing listeners.
  379. *
  380. * Consider listener "a" which specifies before "b" and "b" which
  381. * specifies before "c". You are now attempting to register "c" before
  382. * "a". There is no order that can satisfy all constraints.
  383. */
  384. struct Cycle: public ListenError
  385. {
  386. Cycle(const std::string& what): ListenError(std::string("Cycle: ") + what) {}
  387. };
  388. /**
  389. * exception thrown by listen(). This one means that your new listener
  390. * would force a change to the order of previously-registered listeners,
  391. * and we don't have a good way to implement that.
  392. *
  393. * Consider listeners "some", "other" and "third". "some" and "other" are
  394. * registered earlier without specifying relative order, so "other"
  395. * happens to be first. Now you attempt to register "third" after "some"
  396. * and before "other". Whoops, that would require swapping "some" and
  397. * "other", which we can't do. Instead we throw this exception.
  398. *
  399. * It may not be possible to change the registration order so we already
  400. * know "third"s order requirement by the time we register the second of
  401. * "some" and "other". A solution would be to specify that "some" must
  402. * come before "other", or equivalently that "other" must come after
  403. * "some".
  404. */
  405. struct OrderChange: public ListenError
  406. {
  407. OrderChange(const std::string& what): ListenError(std::string("OrderChange: ") + what) {}
  408. };
  409. /// used by listen()
  410. typedef std::vector<std::string> NameList;
  411. /// convenience placeholder for when you explicitly want to pass an empty
  412. /// NameList
  413. const static NameList empty;
  414. /// Get this LLEventPump's name
  415. std::string getName() const { return mName; }
  416. /**
  417. * Register a new listener with a unique name. Specify an optional list
  418. * of other listener names after which this one must be called, likewise
  419. * an optional list of other listener names before which this one must be
  420. * called. The other listeners mentioned need not yet be registered
  421. * themselves. listen() can throw any ListenError; see ListenError
  422. * subclasses.
  423. *
  424. * The listener name must be unique among active listeners for this
  425. * LLEventPump, else you get DupListenerName. If you don't care to invent
  426. * a name yourself, use inventName(). (I was tempted to recognize e.g. ""
  427. * and internally generate a distinct name for that case. But that would
  428. * handle badly the scenario in which you want to add, remove, re-add,
  429. * etc. the same listener: each new listen() call would necessarily
  430. * perform a new dependency sort. Assuming you specify the same
  431. * after/before lists each time, using inventName() when you first
  432. * instantiate your listener, then passing the same name on each listen()
  433. * call, allows us to optimize away the second and subsequent dependency
  434. * sorts.
  435. *
  436. * If (as is typical) you pass a <tt>boost::bind()</tt> expression as @a
  437. * listener, listen() will inspect the components of that expression. If a
  438. * bound object matches any of several cases, the connection will
  439. * automatically be disconnected when that object is destroyed.
  440. *
  441. * * You bind a <tt>boost::weak_ptr</tt>.
  442. * * Binding a <tt>boost::shared_ptr</tt> that way would ensure that the
  443. * referenced object would @em never be destroyed, since the @c
  444. * shared_ptr stored in the LLEventPump would remain an outstanding
  445. * reference. Use the weaken() function to convert your @c shared_ptr to
  446. * @c weak_ptr. Because this is easy to forget, binding a @c shared_ptr
  447. * will produce a compile error (@c BOOST_STATIC_ASSERT failure).
  448. * * You bind a simple pointer or reference to an object derived from
  449. * <tt>boost::enable_shared_from_this</tt>. (UNDER CONSTRUCTION)
  450. * * You bind a simple pointer or reference to an object derived from
  451. * LLEventTrackable. Unlike the cases described above, though, this is
  452. * vulnerable to a couple of cross-thread race conditions, as described
  453. * in the LLEventTrackable documentation.
  454. */
  455. template <typename LISTENER>
  456. LLBoundListener listen(const std::string& name, const LISTENER& listener,
  457. const NameList& after=NameList(),
  458. const NameList& before=NameList())
  459. {
  460. // Examine listener, using our listen_impl() method to make the
  461. // actual connection.
  462. // This is why listen() is a template. Conversion from boost::bind()
  463. // to LLEventListener performs type erasure, so it's important to look
  464. // at the boost::bind object itself before that happens.
  465. return LLEventDetail::visit_and_connect(name,
  466. listener,
  467. boost::bind(&LLEventPump::listen_impl,
  468. this,
  469. name,
  470. _1,
  471. after,
  472. before));
  473. }
  474. /// Get the LLBoundListener associated with the passed name (dummy
  475. /// LLBoundListener if not found)
  476. virtual LLBoundListener getListener(const std::string& name) const;
  477. /**
  478. * Instantiate one of these to block an existing connection:
  479. * @code
  480. * { // in some local scope
  481. * LLEventPump::Blocker block(someLLBoundListener);
  482. * // code that needs the connection blocked
  483. * } // unblock the connection again
  484. * @endcode
  485. */
  486. typedef boost::signals2::shared_connection_block Blocker;
  487. /// Unregister a listener by name. Prefer this to
  488. /// <tt>getListener(name).disconnect()</tt> because stopListening() also
  489. /// forgets this name.
  490. virtual void stopListening(const std::string& name);
  491. /// Post an event to all listeners. The @c bool return is only meaningful
  492. /// if the underlying leaf class is LLEventStream -- beware of relying on
  493. /// it too much! Truthfully, we return @c bool mostly to permit chaining
  494. /// one LLEventPump as a listener on another.
  495. virtual bool post(const LLSD&) = 0;
  496. /// Enable/disable: while disabled, silently ignore all post() calls
  497. virtual void enable(bool enabled=true) { mEnabled = enabled; }
  498. /// query
  499. virtual bool enabled() const { return mEnabled; }
  500. /// Generate a distinct name for a listener -- see listen()
  501. static std::string inventName(const std::string& pfx="listener");
  502. private:
  503. friend class LLEventPumps;
  504. /// flush queued events
  505. virtual void flush() {}
  506. virtual void reset();
  507. private:
  508. virtual LLBoundListener listen_impl(const std::string& name, const LLEventListener&,
  509. const NameList& after,
  510. const NameList& before);
  511. std::string mName;
  512. protected:
  513. /// implement the dispatching
  514. boost::shared_ptr<LLStandardSignal> mSignal;
  515. /// valve open?
  516. bool mEnabled;
  517. /// Map of named listeners. This tracks the listeners that actually exist
  518. /// at this moment. When we stopListening(), we discard the entry from
  519. /// this map.
  520. typedef std::map<std::string, boost::signals2::connection> ConnectionMap;
  521. ConnectionMap mConnections;
  522. typedef LLDependencies<std::string, float> DependencyMap;
  523. /// Dependencies between listeners. For each listener, track the float
  524. /// used to establish its place in mSignal's order. This caches all the
  525. /// listeners that have ever registered; stopListening() does not discard
  526. /// the entry from this map. This is to avoid a new dependency sort if the
  527. /// same listener with the same dependencies keeps hopping on and off this
  528. /// LLEventPump.
  529. DependencyMap mDeps;
  530. };
  531. /*****************************************************************************
  532. * LLEventStream
  533. *****************************************************************************/
  534. /**
  535. * LLEventStream is a thin wrapper around LLStandardSignal. Posting an
  536. * event immediately calls all registered listeners.
  537. */
  538. class LL_COMMON_API LLEventStream: public LLEventPump
  539. {
  540. public:
  541. LLEventStream(const std::string& name, bool tweak=false): LLEventPump(name, tweak) {}
  542. virtual ~LLEventStream() {}
  543. /// Post an event to all listeners
  544. virtual bool post(const LLSD& event);
  545. };
  546. /*****************************************************************************
  547. * LLEventQueue
  548. *****************************************************************************/
  549. /**
  550. * LLEventQueue isa LLEventPump whose post() method defers calling registered
  551. * listeners until flush() is called.
  552. */
  553. class LL_COMMON_API LLEventQueue: public LLEventPump
  554. {
  555. public:
  556. LLEventQueue(const std::string& name, bool tweak=false): LLEventPump(name, tweak) {}
  557. virtual ~LLEventQueue() {}
  558. /// Post an event to all listeners
  559. virtual bool post(const LLSD& event);
  560. private:
  561. /// flush queued events
  562. virtual void flush();
  563. private:
  564. typedef std::deque<LLSD> EventQueue;
  565. EventQueue mEventQueue;
  566. };
  567. /*****************************************************************************
  568. * LLReqID
  569. *****************************************************************************/
  570. /**
  571. * This class helps the implementer of a given event API to honor the
  572. * ["reqid"] convention. By this convention, each event API stamps into its
  573. * response LLSD a ["reqid"] key whose value echoes the ["reqid"] value, if
  574. * any, from the corresponding request.
  575. *
  576. * This supports an (atypical, but occasionally necessary) use case in which
  577. * two or more asynchronous requests are multiplexed onto the same ["reply"]
  578. * LLEventPump. Since the response events could arrive in arbitrary order, the
  579. * caller must be able to demux them. It does so by matching the ["reqid"]
  580. * value in each response with the ["reqid"] value in the corresponding
  581. * request.
  582. *
  583. * It is the caller's responsibility to ensure distinct ["reqid"] values for
  584. * that case. Though LLSD::UUID is guaranteed to work, it might be overkill:
  585. * the "namespace" of unique ["reqid"] values is simply the set of requests
  586. * specifying the same ["reply"] LLEventPump name.
  587. *
  588. * Making a given event API echo the request's ["reqid"] into the response is
  589. * nearly trivial. This helper is mostly for mnemonic purposes, to serve as a
  590. * place to put these comments. We hope that each time a coder implements a
  591. * new event API based on some existing one, s/he will say, "Huh, what's an
  592. * LLReqID?" and look up this material.
  593. *
  594. * The hardest part about the convention is deciding where to store the
  595. * ["reqid"] value. Ironically, LLReqID can't help with that: you must store
  596. * an LLReqID instance in whatever storage will persist until the reply is
  597. * sent. For example, if the request ultimately ends up using a Responder
  598. * subclass, storing an LLReqID instance in the Responder works.
  599. *
  600. * @note
  601. * The @em implementer of an event API must honor the ["reqid"] convention.
  602. * However, the @em caller of an event API need only use it if s/he is sharing
  603. * the same ["reply"] LLEventPump for two or more asynchronous event API
  604. * requests.
  605. *
  606. * In most cases, it's far easier for the caller to instantiate a local
  607. * LLEventStream and pass its name to the event API in question. Then it's
  608. * perfectly reasonable not to set a ["reqid"] key in the request, ignoring
  609. * the @c isUndefined() ["reqid"] value in the response.
  610. */
  611. class LL_COMMON_API LLReqID
  612. {
  613. public:
  614. /**
  615. * If you have the request in hand at the time you instantiate the
  616. * LLReqID, pass that request to extract its ["reqid"].
  617. */
  618. LLReqID(const LLSD& request):
  619. mReqid(request["reqid"])
  620. {}
  621. /// If you don't yet have the request, use setFrom() later.
  622. LLReqID() {}
  623. /// Extract and store the ["reqid"] value from an incoming request.
  624. void setFrom(const LLSD& request)
  625. {
  626. mReqid = request["reqid"];
  627. }
  628. /// Set ["reqid"] key into a pending response LLSD object.
  629. void stamp(LLSD& response) const;
  630. /// Make a whole new response LLSD object with our ["reqid"].
  631. LLSD makeResponse() const
  632. {
  633. LLSD response;
  634. stamp(response);
  635. return response;
  636. }
  637. /// Not really sure of a use case for this accessor...
  638. LLSD getReqID() const { return mReqid; }
  639. private:
  640. LLSD mReqid;
  641. };
  642. /**
  643. * Conventionally send a reply to a request event.
  644. *
  645. * @a reply is the LLSD reply event to send
  646. * @a request is the corresponding LLSD request event
  647. * @a replyKey is the key in the @a request event, conventionally ["reply"],
  648. * whose value is the name of the LLEventPump on which to send the reply.
  649. *
  650. * Before sending the reply event, sendReply() copies the ["reqid"] item from
  651. * the request to the reply.
  652. */
  653. LL_COMMON_API bool sendReply(const LLSD& reply, const LLSD& request,
  654. const std::string& replyKey="reply");
  655. /**
  656. * Base class for LLListenerWrapper. See visit_and_connect() and llwrap(). We
  657. * provide virtual @c accept_xxx() methods, customization points allowing a
  658. * subclass access to certain data visible at LLEventPump::listen() time.
  659. * Example subclass usage:
  660. *
  661. * @code
  662. * myEventPump.listen("somename",
  663. * llwrap<MyListenerWrapper>(boost::bind(&MyClass::method, instance, _1)));
  664. * @endcode
  665. *
  666. * Because of the anticipated usage (note the anonymous temporary
  667. * MyListenerWrapper instance in the example above), the @c accept_xxx()
  668. * methods must be @c const.
  669. */
  670. class LL_COMMON_API LLListenerWrapperBase
  671. {
  672. public:
  673. /// New instance. The accept_xxx() machinery makes it important to use
  674. /// shared_ptrs for our data. Many copies of this object are made before
  675. /// the instance that actually ends up in the signal, yet accept_xxx()
  676. /// will later be called on the @em original instance. All copies of the
  677. /// same original instance must share the same data.
  678. LLListenerWrapperBase():
  679. mName(new std::string),
  680. mConnection(new LLBoundListener)
  681. {
  682. }
  683. /// Copy constructor. Copy shared_ptrs to original instance data.
  684. LLListenerWrapperBase(const LLListenerWrapperBase& that):
  685. mName(that.mName),
  686. mConnection(that.mConnection)
  687. {
  688. }
  689. virtual ~LLListenerWrapperBase() {}
  690. /// Ask LLEventPump::listen() for the listener name
  691. virtual void accept_name(const std::string& name) const
  692. {
  693. *mName = name;
  694. }
  695. /// Ask LLEventPump::listen() for the new connection
  696. virtual void accept_connection(const LLBoundListener& connection) const
  697. {
  698. *mConnection = connection;
  699. }
  700. protected:
  701. /// Listener name.
  702. boost::shared_ptr<std::string> mName;
  703. /// Connection.
  704. boost::shared_ptr<LLBoundListener> mConnection;
  705. };
  706. /*****************************************************************************
  707. * Underpinnings
  708. *****************************************************************************/
  709. /**
  710. * We originally provided a suite of overloaded
  711. * LLEventTrackable::listenTo(LLEventPump&, ...) methods that would call
  712. * LLEventPump::listen(...) and then pass the returned LLBoundListener to
  713. * LLEventTrackable::track(). This was workable but error-prone: the coder
  714. * must remember to call listenTo() rather than the more straightforward
  715. * listen() method.
  716. *
  717. * Now we publish only the single canonical listen() method, so there's a
  718. * uniform mechanism. Having a single way to do this is good, in that there's
  719. * no question in the coder's mind which of several alternatives to choose.
  720. *
  721. * To support automatic connection management, we use boost::visit_each
  722. * (http://www.boost.org/doc/libs/1_37_0/doc/html/boost/visit_each.html) to
  723. * inspect each argument of a boost::bind expression. (Although the visit_each
  724. * mechanism was first introduced with the original Boost.Signals library, it
  725. * was only later documented.)
  726. *
  727. * Cases:
  728. * * At least one of the function's arguments is a boost::weak_ptr<T>. Pass
  729. * the corresponding shared_ptr to slot_type::track(). Ideally that would be
  730. * the object whose method we want to call, but in fact we do the same for
  731. * any weak_ptr we might find among the bound arguments. If we're passing
  732. * our bound method a weak_ptr to some object, wouldn't the destruction of
  733. * that object invalidate the call? So we disconnect automatically when any
  734. * such object is destroyed. This is the mechanism preferred by boost::
  735. * signals2.
  736. * * One of the functions's arguments is a boost::shared_ptr<T>. This produces
  737. * a compile error: the bound copy of the shared_ptr stored in the
  738. * boost_bind object stored in the signal object would make the referenced
  739. * T object immortal. We provide a weaken() function. Pass
  740. * weaken(your_shared_ptr) instead. (We can inspect, but not modify, the
  741. * boost::bind object. Otherwise we'd replace the shared_ptr with weak_ptr
  742. * implicitly and just proceed.)
  743. * * One of the function's arguments is a plain pointer/reference to an object
  744. * derived from boost::enable_shared_from_this. We assume that this object
  745. * is managed using boost::shared_ptr, so we implicitly extract a shared_ptr
  746. * and track that. (UNDER CONSTRUCTION)
  747. * * One of the function's arguments is derived from LLEventTrackable. Pass
  748. * the LLBoundListener to its LLEventTrackable::track(). This is vulnerable
  749. * to a couple different race conditions, as described in LLEventTrackable
  750. * documentation. (NOTE: Now that LLEventTrackable is a typedef for
  751. * boost::signals2::trackable, the Signals2 library handles this itself, so
  752. * our visitor needs no special logic for this case.)
  753. * * Any other argument type is irrelevant to automatic connection management.
  754. */
  755. namespace LLEventDetail
  756. {
  757. template <typename F>
  758. const F& unwrap(const F& f) { return f; }
  759. template <typename F>
  760. const F& unwrap(const boost::reference_wrapper<F>& f) { return f.get(); }
  761. // Most of the following is lifted from the Boost.Signals use of
  762. // visit_each.
  763. template<bool Cond> struct truth {};
  764. /**
  765. * boost::visit_each() Visitor, used on a template argument <tt>const F&
  766. * f</tt> as follows (see visit_and_connect()):
  767. * @code
  768. * LLEventListener listener(f);
  769. * Visitor visitor(listener); // bind listener so it can track() shared_ptrs
  770. * using boost::visit_each; // allow unqualified visit_each() call for ADL
  771. * visit_each(visitor, unwrap(f));
  772. * @endcode
  773. */
  774. class Visitor
  775. {
  776. public:
  777. /**
  778. * Visitor binds a reference to LLEventListener so we can track() any
  779. * shared_ptrs we find in the argument list.
  780. */
  781. Visitor(LLEventListener& listener):
  782. mListener(listener)
  783. {
  784. }
  785. /**
  786. * boost::visit_each() calls this method for each component of a
  787. * boost::bind() expression.
  788. */
  789. template <typename T>
  790. void operator()(const T& t) const
  791. {
  792. decode(t, 0);
  793. }
  794. private:
  795. // decode() decides between a reference wrapper and anything else
  796. // boost::ref() variant
  797. template<typename T>
  798. void decode(const boost::reference_wrapper<T>& t, int) const
  799. {
  800. // add_if_trackable(t.get_pointer());
  801. }
  802. // decode() anything else
  803. template<typename T>
  804. void decode(const T& t, long) const
  805. {
  806. typedef truth<(boost::is_pointer<T>::value)> is_a_pointer;
  807. maybe_get_pointer(t, is_a_pointer());
  808. }
  809. // maybe_get_pointer() decides between a pointer and a non-pointer
  810. // plain pointer variant
  811. template<typename T>
  812. void maybe_get_pointer(const T& t, truth<true>) const
  813. {
  814. // add_if_trackable(t);
  815. }
  816. // shared_ptr variant
  817. template<typename T>
  818. void maybe_get_pointer(const boost::shared_ptr<T>& t, truth<false>) const
  819. {
  820. // If we have a shared_ptr to this object, it doesn't matter
  821. // whether the object is derived from LLEventTrackable, so no
  822. // further analysis of T is needed.
  823. // mListener.track(t);
  824. // Make this case illegal. Passing a bound shared_ptr to
  825. // slot_type::track() is useless, since the bound shared_ptr will
  826. // keep the object alive anyway! Force the coder to cast to weak_ptr.
  827. // Trivial as it is, make the BOOST_STATIC_ASSERT() condition
  828. // dependent on template param so the macro is only evaluated if
  829. // this method is in fact instantiated, as described here:
  830. // http://www.boost.org/doc/libs/1_34_1/doc/html/boost_staticassert.html
  831. // ATTENTION: Don't bind a shared_ptr<anything> using
  832. // LLEventPump::listen(boost::bind()). Doing so captures a copy of
  833. // the shared_ptr, making the referenced object effectively
  834. // immortal. Use the weaken() function, e.g.:
  835. // somepump.listen(boost::bind(...weaken(my_shared_ptr)...));
  836. // This lets us automatically disconnect when the referenced
  837. // object is destroyed.
  838. BOOST_STATIC_ASSERT(sizeof(T) == 0);
  839. }
  840. // weak_ptr variant
  841. template<typename T>
  842. void maybe_get_pointer(const boost::weak_ptr<T>& t, truth<false>) const
  843. {
  844. // If we have a weak_ptr to this object, it doesn't matter
  845. // whether the object is derived from LLEventTrackable, so no
  846. // further analysis of T is needed.
  847. mListener.track(t);
  848. // std::cout << "Found weak_ptr<" << typeid(T).name() << ">!\n";
  849. }
  850. #if 0
  851. // reference to anything derived from boost::enable_shared_from_this
  852. template <typename T>
  853. inline void maybe_get_pointer(const boost::enable_shared_from_this<T>& ct,
  854. truth<false>) const
  855. {
  856. // Use the slot_type::track(shared_ptr) mechanism. Cast away
  857. // const-ness because (in our code base anyway) it's unusual
  858. // to find shared_ptr<const T>.
  859. boost::enable_shared_from_this<T>&
  860. t(const_cast<boost::enable_shared_from_this<T>&>(ct));
  861. std::cout << "Capturing shared_from_this()" << std::endl;
  862. boost::shared_ptr<T> sp(t.shared_from_this());
  863. /*==========================================================================*|
  864. std::cout << "Capturing weak_ptr" << std::endl;
  865. boost::weak_ptr<T> wp(sp);
  866. |*==========================================================================*/
  867. std::cout << "Tracking shared__ptr" << std::endl;
  868. mListener.track(sp);
  869. }
  870. #endif
  871. // non-pointer variant
  872. template<typename T>
  873. void maybe_get_pointer(const T& t, truth<false>) const
  874. {
  875. // Take the address of this object, because the object itself may be
  876. // trackable
  877. // add_if_trackable(boost::addressof(t));
  878. }
  879. /*==========================================================================*|
  880. // add_if_trackable() adds LLEventTrackable objects to mTrackables
  881. inline void add_if_trackable(const LLEventTrackable* t) const
  882. {
  883. if (t)
  884. {
  885. }
  886. }
  887. // pointer to anything not an LLEventTrackable subclass
  888. inline void add_if_trackable(const void*) const
  889. {
  890. }
  891. // pointer to free function
  892. // The following construct uses the preprocessor to generate
  893. // add_if_trackable() overloads accepting pointer-to-function taking
  894. // 0, 1, ..., LLEVENTS_LISTENER_ARITY parameters of arbitrary type.
  895. #define BOOST_PP_LOCAL_MACRO(n) \
  896. template <typename R \
  897. BOOST_PP_COMMA_IF(n) \
  898. BOOST_PP_ENUM_PARAMS(n, typename T)> \
  899. inline void \
  900. add_if_trackable(R (*)(BOOST_PP_ENUM_PARAMS(n, T))) const \
  901. { \
  902. }
  903. #define BOOST_PP_LOCAL_LIMITS (0, LLEVENTS_LISTENER_ARITY)
  904. #include BOOST_PP_LOCAL_ITERATE()
  905. #undef BOOST_PP_LOCAL_MACRO
  906. #undef BOOST_PP_LOCAL_LIMITS
  907. |*==========================================================================*/
  908. /// Bind a reference to the LLEventListener to call its track() method.
  909. LLEventListener& mListener;
  910. };
  911. /**
  912. * Utility template function to use Visitor appropriately
  913. *
  914. * @param raw_listener Callable to connect, typically a boost::bind()
  915. * expression. This will be visited by Visitor using boost::visit_each().
  916. * @param connect_funct Callable that will connect() @a raw_listener to an
  917. * LLStandardSignal, returning LLBoundListener.
  918. */
  919. template <typename LISTENER>
  920. LLBoundListener visit_and_connect(const std::string& name,
  921. const LISTENER& raw_listener,
  922. const ConnectFunc& connect_func)
  923. {
  924. // Capture the listener
  925. LLEventListener listener(raw_listener);
  926. // Define our Visitor, binding the listener so we can call
  927. // listener.track() if we discover any shared_ptr<Foo>.
  928. LLEventDetail::Visitor visitor(listener);
  929. // Allow unqualified visit_each() call for ADL
  930. using boost::visit_each;
  931. // Visit each component of a boost::bind() expression. Pass
  932. // 'raw_listener', our template argument, rather than 'listener' from
  933. // which type details have been erased. unwrap() comes from
  934. // Boost.Signals, in case we were passed a boost::ref().
  935. visit_each(visitor, LLEventDetail::unwrap(raw_listener));
  936. // Make the connection using passed function.
  937. LLBoundListener connection(connect_func(listener));
  938. // If the LISTENER is an LLListenerWrapperBase subclass, pass it the
  939. // desired information. It's important that we pass the raw_listener
  940. // so the compiler can make decisions based on its original type.
  941. const LLListenerWrapperBase* lwb =
  942. ll_template_cast<const LLListenerWrapperBase*>(&raw_listener);
  943. if (lwb)
  944. {
  945. lwb->accept_name(name);
  946. lwb->accept_connection(connection);
  947. }
  948. // In any case, show new connection to caller.
  949. return connection;
  950. }
  951. } // namespace LLEventDetail
  952. // Somewhat to my surprise, passing boost::bind(...boost::weak_ptr<T>...) to
  953. // listen() fails in Boost code trying to instantiate LLEventListener (i.e.
  954. // LLStandardSignal::slot_type) because the boost::get_pointer() utility function isn't
  955. // specialized for boost::weak_ptr. This remedies that omission.
  956. namespace boost
  957. {
  958. template <typename T>
  959. T* get_pointer(const weak_ptr<T>& ptr) { return shared_ptr<T>(ptr).get(); }
  960. }
  961. /// Since we forbid use of listen(boost::bind(...shared_ptr<T>...)), provide an
  962. /// easy way to cast to the corresponding weak_ptr.
  963. template <typename T>
  964. boost::weak_ptr<T> weaken(const boost::shared_ptr<T>& ptr)
  965. {
  966. return boost::weak_ptr<T>(ptr);
  967. }
  968. #endif /* ! defined(LL_LLEVENTS_H) */