llevents.h 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606
  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=viewergpl$
  11. *
  12. * Copyright (c) 2010, Linden Research, Inc.
  13. *
  14. * Second Life Viewer Source Code
  15. * The source code in this file ("Source Code") is provided by Linden Lab
  16. * to you under the terms of the GNU General Public License, version 2.0
  17. * ("GPL"), unless you have obtained a separate licensing agreement
  18. * ("Other License"), formally executed by you and Linden Lab. Terms of
  19. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  20. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  21. *
  22. * There are special exceptions to the terms and conditions of the GPL as
  23. * it is applied to this Source Code. View the full text of the exception
  24. * in the file doc/FLOSS-exception.txt in this software distribution, or
  25. * online at
  26. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  27. *
  28. * By copying, modifying or distributing this software, you acknowledge
  29. * that you have read and understood your obligations described above,
  30. * and agree to abide by those obligations.
  31. *
  32. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  33. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  34. * COMPLETENESS OR PERFORMANCE.
  35. * $/LicenseInfo$
  36. */
  37. #ifndef LL_LLEVENTS_H
  38. #define LL_LLEVENTS_H
  39. #include "llpreprocessor.h"
  40. #include <deque>
  41. #include <map>
  42. #include <memory>
  43. #include <set>
  44. #include <stdexcept>
  45. #include <string>
  46. #include <vector>
  47. #include "boost/optional/optional.hpp"
  48. #include "boost/signals2.hpp"
  49. #include "lldependencies.h"
  50. #include "llmutex.h"
  51. #include "llsd.h"
  52. #include "llstl.h"
  53. // Signal and handler declarations.
  54. // Using a single handler signature means that we can have a common handler
  55. // type, rather than needing a distinct one for each different handler.
  56. // A boost::signals Combiner that stops the first time a handler returns true
  57. // We need this because we want to have our handlers return bool, so that
  58. // we have the option to cause a handler to stop further processing. The
  59. // default handler fails when the signal returns a value but has no slots.
  60. struct LLStopWhenHandled
  61. {
  62. typedef bool result_type;
  63. template<typename InputIterator>
  64. result_type operator()(InputIterator first, InputIterator last) const
  65. {
  66. for (InputIterator si = first; si != last; ++si)
  67. {
  68. try
  69. {
  70. if (*si)
  71. {
  72. return true;
  73. }
  74. }
  75. catch (...)
  76. {
  77. }
  78. }
  79. return false;
  80. }
  81. };
  82. // We want to have a standard signature for all signals; this way, we can
  83. // easily document a protocol for communicating across DLLs and into scripting
  84. // languages someday.
  85. //
  86. // We want to return a bool to indicate whether the signal has been handled and
  87. // should NOT be passed on to other listeners. Returns true to stop further
  88. // handling of the signal, and false to continue.
  89. //
  90. // We take an LLSD because this way the contents of the signal are independent
  91. // of the API used to communicate it. It is const ref because then there's low
  92. // cost to pass it; if you only need to inspect it, it's very cheap.
  93. //
  94. // NOTE: the float template parameter indicates that we will internally use
  95. // float to indicate relative listener order on a given LLStandardSignal. Do
  96. // not worry, the float values are strictly internal ! They are not part of
  97. // the interface, for the excellent reason that requiring the caller to specify
  98. // a numeric key to establish order means that the caller must know the
  99. // universe of possible values. We use LLDependencies for that instead.
  100. typedef boost::signals2::signal<bool(const LLSD&), LLStopWhenHandled,
  101. float> LLStandardSignal;
  102. // Methods that forward listeners (e.g. constructed with boost::bind()) should
  103. // accept (const LLEventListener&)
  104. typedef LLStandardSignal::slot_type LLEventListener;
  105. // Result of registering a listener, supports connected(), disconnect() and
  106. // blocked()
  107. typedef boost::signals2::connection LLBoundListener;
  108. // Storing an LLBoundListener in LLTempBoundListener will disconnect the
  109. // referenced listener when the LLTempBoundListener instance is destroyed.
  110. typedef boost::signals2::scoped_connection LLTempBoundListener;
  111. // A common idiom for event-based code is to accept either a callable, directly
  112. // called on completion, or the string name of an LLEventPump on which to post
  113. // the completion event. Specifying a parameter as const LLListenerOrPumpName&
  114. // allows either.
  115. //
  116. // Calling a validly-constructed LLListenerOrPumpName, passing the LLSD 'event'
  117. // object, either calls the callable or posts the event to the named
  118. // LLEventPump.
  119. //
  120. // A default-constructed LLListenerOrPumpName is 'empty'. (This is useful as
  121. // the default value of an optional method parameter.) Calling it throws
  122. // LLListenerOrPumpName::Empty. Test for this condition beforehand using either
  123. // if (param) or if (! param).
  124. class LLListenerOrPumpName
  125. {
  126. public:
  127. // Passing string name of LLEventPump
  128. LLListenerOrPumpName(const std::string& pumpname);
  129. // Passing string literal (overload so compiler isn't forced to infer
  130. // double conversion)
  131. LLListenerOrPumpName(const char* pumpname);
  132. // Passing listener: the "anything else" catch-all case. The type of an
  133. // object constructed by boost::bind() is not intended to be written out.
  134. // Normally we would just accept 'const LLEventListener&', but that would
  135. // require double implicit conversion: boost::bind() object to
  136. // LLEventListener, LLEventListener to LLListenerOrPumpName. So use a
  137. // template to forward anything.
  138. template<typename T>
  139. LLListenerOrPumpName(const T& listener)
  140. : mListener(listener)
  141. {
  142. }
  143. // For omitted method parameter: uninitialized mListener
  144. LLListenerOrPumpName() = default;
  145. // Tests for validity
  146. LL_INLINE operator bool() const { return bool(mListener); }
  147. LL_INLINE bool operator!() const { return !mListener; }
  148. // Explicit accessor
  149. LL_INLINE const LLEventListener& getListener() const
  150. {
  151. return *mListener;
  152. }
  153. // Implicit conversion to LLEventListener
  154. LL_INLINE operator LLEventListener() const { return *mListener; }
  155. // Allows calling directly
  156. bool operator()(const LLSD& event) const;
  157. // Exception if you try to call when empty
  158. struct Empty : public std::runtime_error
  159. {
  160. Empty(const std::string& what)
  161. : std::runtime_error(std::string("LLListenerOrPumpName::Empty: ") +
  162. what)
  163. {
  164. }
  165. };
  166. private:
  167. boost::optional<LLEventListener> mListener;
  168. };
  169. ///////////////////////////////////////////////////////////////////////////////
  170. // LLEventPumps
  171. ///////////////////////////////////////////////////////////////////////////////
  172. class LLEventPump;
  173. class LLEventPumps final
  174. {
  175. friend class LLEventPump;
  176. protected:
  177. LOG_CLASS(LLEventPumps);
  178. public:
  179. LLEventPumps() = default;
  180. ~LLEventPumps();
  181. // Finds or creates an LLEventPump instance with a specific name. We return
  182. // a reference so there is no question about ownership. obtain() finds
  183. // an instance without conferring ownership.
  184. LLEventPump& obtain(const std::string& name);
  185. // Creates an LLEventPump instance with suggested name. We return
  186. // a reference so there is no question about ownership. When type is
  187. // invalid, BadType is thrown.
  188. // Note: type only accepts an empty string or "LLEventStream", i.e. there
  189. // is not support for the unimplemented "LLEventMailDrop" type. HB
  190. LLEventPump& make(const std::string& name, bool tweak = false,
  191. const std::string& type = std::string());
  192. struct BadType : public std::runtime_error
  193. {
  194. BadType(const std::string& what)
  195. : std::runtime_error(std::string("BadType: ") + what)
  196. {
  197. }
  198. };
  199. // Finds the named LLEventPump instance. If it exists post the message to
  200. // it. If the pump does not exist, do nothing. Returns the result of the
  201. // LLEventPump::post. If no pump exists returns false.
  202. // This is syntactically similar to: gEventPumps.post(name, message)
  203. // however if the pump does not already exist it will not be created.
  204. bool post(const std::string& name, const LLSD& message);
  205. // Flushes all known LLEventPump instances
  206. void flush();
  207. // Disconnects listeners from all known LLEventPump instances
  208. void clear();
  209. // Resets all known LLEventPump instances (workaround for DEV-35406 crash
  210. // on shutdown).
  211. void reset();
  212. LL_INLINE static bool destroyed() { return sInstanceDestroyed; }
  213. // Conventionally sends a reply to a request event.
  214. //
  215. // 'reply' is the LLSD reply event to send
  216. // 'request' is the corresponding LLSD request event
  217. // 'reply_key' is the key in the @a request event, conventionally ["reply"],
  218. // whose value is the name of the LLEventPump on which to send the reply.
  219. //
  220. // Before sending the reply event, sendReply() copies the ["reqid"] item
  221. // from the request to the reply.
  222. bool sendReply(const LLSD& reply, const LLSD& request,
  223. const std::string& reply_key = "reply");
  224. private:
  225. // Registers a new LLEventPump instance (internal)
  226. std::string registerNew(const LLEventPump&, const std::string& name,
  227. bool tweak);
  228. // Unregisters a doomed LLEventPump instance (internal)
  229. void unregister(const LLEventPump&);
  230. private:
  231. // Map of all known LLEventPump instances, whether or not we instantiated
  232. // them. We store a plain old LLEventPump* because this map does not claim
  233. // ownership of the instances. Though the common usage pattern is to
  234. // request an instance using obtain(), it is fair to instantiate an
  235. // LLEventPump subclass statically, as a class member, on the stack or on
  236. // the heap. In such cases, the instantiating party is responsible for its
  237. // lifespan.
  238. typedef std::map<std::string, LLEventPump*> PumpMap;
  239. PumpMap mPumpMap;
  240. // Set of all LLEventPumps we instantiated. Membership in this set means
  241. // we claim ownership, and will delete them when this LLEventPumps is
  242. // destroyed.
  243. typedef std::set<LLEventPump*> PumpSet;
  244. PumpSet mOurPumps;
  245. // Flag to indicate that the gEventPumps instance got destroyed already.
  246. static bool sInstanceDestroyed;
  247. };
  248. extern LLEventPumps gEventPumps;
  249. ///////////////////////////////////////////////////////////////////////////////
  250. // LLEventPump
  251. ///////////////////////////////////////////////////////////////////////////////
  252. // LLEventPump is the base class interface through which we access the concrete
  253. // subclass LLEventStream.
  254. class LLEventPump
  255. {
  256. friend class LLEventPumps;
  257. protected:
  258. LOG_CLASS(LLEventPump);
  259. public:
  260. static const std::string ANONYMOUS; // constant for anonymous listeners.
  261. // Exception thrown by LLEventPump(). You are trying to instantiate an
  262. // LLEventPump (subclass) using the same name as some other instance, and
  263. // you did not pass tweak=true to permit it to generate a unique variant.
  264. struct DupPumpName : public std::runtime_error
  265. {
  266. DupPumpName(const std::string& what)
  267. : std::runtime_error(std::string("DupPumpName: ") + what)
  268. {
  269. }
  270. };
  271. // Instantiates an LLEventPump (subclass) with the string name by which it
  272. // can be found using LLEventPumps::obtain().
  273. //
  274. // If you pass (or default) tweak to false, then a duplicate name will
  275. // throw DupPumpName. This would not happen if LLEventPumps::obtain()
  276. // instantiates the LLEventPump, because obtain() uses find-or-create
  277. // logic. It can only happen if you instantiate an LLEventPump in your own
  278. // code, and a collision with the name of some other LLEventPump is likely
  279. // to cause much more subtle problems !
  280. //
  281. // When you hand-instantiate an LLEventPump, consider passing tweak as
  282. // true. This directs LLEventPump() to append a suffix to the passed name
  283. // to make it unique. You can retrieve the adjusted name by calling
  284. // getName() on your new instance.
  285. LLEventPump(const std::string& name, bool tweak = false);
  286. virtual ~LLEventPump();
  287. // Group exceptions thrown by listen(). We use exceptions because these
  288. // particular errors are likely to be coding errors, found and fixed by
  289. // the developer even before preliminary checkin.
  290. struct ListenError : public std::runtime_error
  291. {
  292. ListenError(const std::string& what)
  293. : std::runtime_error(what)
  294. {
  295. }
  296. };
  297. // Exception thrown by listen(). You are attempting to register a listener
  298. // on this LLEventPump using the same listener name as an already
  299. // registered listener.
  300. struct DupListenerName : public ListenError
  301. {
  302. DupListenerName(const std::string& what)
  303. : ListenError(std::string("DupListenerName: ") + what)
  304. {
  305. }
  306. };
  307. // Exception thrown by listen(). The order dependencies specified for your
  308. // listener are incompatible with existing listeners.
  309. //
  310. // Consider listener "a" which specifies before "b" and "b" which specifies
  311. // before "c". You are now attempting to register "c" before "a". There is
  312. // no order that can satisfy all constraints.
  313. struct Cycle : public ListenError
  314. {
  315. Cycle(const std::string& what)
  316. : ListenError(std::string("Cycle: ") + what)
  317. {
  318. }
  319. };
  320. // Exception thrown by listen(). This one means that your new listener
  321. // would force a change to the order of previously-registered listeners,
  322. // and we do not have a good way to implement that.
  323. //
  324. // Consider listeners "some", "other" and "third". "some" and "other" are
  325. // registered earlier without specifying relative order, so "other" happens
  326. // to be first. Now you attempt to register "third" after "some" and before
  327. // "other". Whoops, that would require swapping "some" and "other", which
  328. // we cannot do. Instead we throw this exception.
  329. //
  330. // It may not be possible to change the registration order so we already
  331. // know "third"s order requirement by the time we register the second of
  332. // "some" and "other". A solution would be to specify that "some" must come
  333. // before "other", or equivalently that "other" must come after "some".
  334. struct OrderChange : public ListenError
  335. {
  336. OrderChange(const std::string& what)
  337. : ListenError(std::string("OrderChange: ") + what)
  338. {
  339. }
  340. };
  341. // Used by listen()
  342. typedef std::vector<std::string> NameList;
  343. // Convenience placeholder for when you explicitly want to pass an empty
  344. // NameList
  345. const static NameList empty;
  346. // Get this LLEventPump's name
  347. LL_INLINE std::string getName() const { return mName; }
  348. // Register a new listener with a unique name. Specify an optional list of
  349. // other listener names after which this one must be called, likewise an
  350. // optional list of other listener names before which this one must be
  351. // called. The other listeners mentioned need not yet be registered
  352. // themselves. listen() can throw any ListenError; see ListenError sub-
  353. // classes.
  354. //
  355. // The listener name must be unique among active listeners for this
  356. // LLEventPump, else you get DupListenerName. If you do not care to invent
  357. // a name yourself, use inventName(). I was tempted to recognize e.g. ""
  358. // and internally generate a distinct name for that case. But that would
  359. // handle badly the scenario in which you want to add, remove, re-add,
  360. // etc. the same listener: each new listen() call would necessarily
  361. // perform a new dependency sort. Assuming you specify the same after/
  362. // before lists each time, using inventName() when you first instantiate
  363. // your listener, then passing the same name on each listen() call, allows
  364. // us to optimize away the second and subsequent dependency sorts.
  365. //
  366. // If name is set to LLEventPump::ANONYMOUS listen will bypass the entire
  367. // dependency and ordering calculation. In this case, it is critical that
  368. // the result be assigned to a LLTempBoundListener or the listener is
  369. // manually disconnected when no longer needed since there will be no way
  370. // to later find and disconnect this listener manually.
  371. LLBoundListener listen(const std::string& name,
  372. const LLEventListener& listener,
  373. const NameList& after = NameList(),
  374. const NameList& before = NameList())
  375. {
  376. return listen_impl(name, listener, after, before);
  377. }
  378. // Get the LLBoundListener associated with the passed name (dummy
  379. // LLBoundListener if not found)
  380. virtual LLBoundListener getListener(const std::string& name) const;
  381. // Instantiate one of these to block an existing connection:
  382. // { // in some local scope
  383. // LLEventPump::Blocker block(someLLBoundListener);
  384. // // code that needs the connection blocked
  385. // } // unblock the connection again
  386. typedef boost::signals2::shared_connection_block Blocker;
  387. // Unregisters a listener by name. Prefer this to
  388. // getListener(name).disconnect() because stopListening() also forgets
  389. // this name.
  390. virtual void stopListening(const std::string& name);
  391. void removeFromDeps(const std::string& name);
  392. // Post an event to all listeners. The bool return is only meaningful
  393. // if the underlying leaf class is LLEventStream: beware of relying on
  394. // it too much ! Truthfully, we return bool mostly to permit chaining
  395. // one LLEventPump as a listener on another.
  396. virtual bool post(const LLSD&) = 0;
  397. // Enable/disable: while disabled, silently ignore all post() calls
  398. LL_INLINE virtual void enable(bool enabled = true)
  399. {
  400. mEnabled = enabled;
  401. }
  402. // Query
  403. LL_INLINE virtual bool enabled() const { return mEnabled; }
  404. // Generate a distinct name for a listener -- see listen()
  405. static std::string inventName(const std::string& pfx = "listener");
  406. protected:
  407. virtual LLBoundListener listen_impl(const std::string& name,
  408. const LLEventListener&,
  409. const NameList& after,
  410. const NameList& before);
  411. private:
  412. // Flushes queued events
  413. LL_INLINE virtual void flush() {}
  414. virtual void clear();
  415. virtual void reset();
  416. private:
  417. mutable LLMutex mConnectionListMutex;
  418. std::string mName;
  419. protected:
  420. // Implements the dispatching
  421. std::shared_ptr<LLStandardSignal> mSignal;
  422. // Map of named listeners. This tracks the listeners that actually exist
  423. // at this moment. When we stopListening(), we discard the entry from
  424. // this map.
  425. typedef std::map<std::string, boost::signals2::connection> connect_map_t;
  426. connect_map_t mConnections;
  427. // Dependencies between listeners. For each listener, track the float
  428. // used to establish its place in mSignal's order. This caches all the
  429. // listeners that have ever registered; stopListening() does not discard
  430. // the entry from this map. This is to avoid a new dependency sort if the
  431. // same listener with the same dependencies keeps hopping on and off this
  432. // LLEventPump.
  433. typedef LLDependencies<std::string, float> depend_map_t;
  434. depend_map_t mDeps;
  435. // Valve open ?
  436. bool mEnabled;
  437. };
  438. ///////////////////////////////////////////////////////////////////////////////
  439. // LLEventStream
  440. ///////////////////////////////////////////////////////////////////////////////
  441. // LLEventStream is a thin wrapper around LLStandardSignal. Posting an event
  442. // immediately calls all registered listeners.
  443. class LLEventStream : public LLEventPump
  444. {
  445. protected:
  446. LOG_CLASS(LLEventStream);
  447. public:
  448. LLEventStream(const std::string& name, bool tweak = false)
  449. : LLEventPump(name, tweak)
  450. {
  451. }
  452. // Posts an event to all listeners
  453. virtual bool post(const LLSD& event);
  454. };
  455. ///////////////////////////////////////////////////////////////////////////////
  456. // LLReqID
  457. ///////////////////////////////////////////////////////////////////////////////
  458. // This class helps the implementer of a given event API to honor the ["reqid"]
  459. // convention. By this convention, each event API stamps into its response LLSD
  460. // a ["reqid"] key whose value echoes the ["reqid"] value, if any, from the
  461. // corresponding request.
  462. //
  463. // This supports an (atypical, but occasionally necessary) use case in which
  464. // two or more asynchronous requests are multiplexed onto the same ["reply"]
  465. // LLEventPump. Since the response events could arrive in arbitrary order, the
  466. // caller must be able to demux them. It does so by matching the ["reqid"]
  467. // value in each response with the ["reqid"] value in the corresponding
  468. // request.
  469. //
  470. // It is the caller's responsibility to ensure distinct ["reqid"] values for
  471. // that case. Though LLSD::UUID is guaranteed to work, it might be overkill:
  472. // the "namespace" of unique ["reqid"] values is simply the set of requests
  473. // specifying the same ["reply"] LLEventPump name.
  474. //
  475. // Making a given event API echo the request's ["reqid"] into the response is
  476. // nearly trivial. This helper is mostly for mnemonic purposes, to serve as a
  477. // place to put these comments. We hope that each time a coder implements a
  478. // new event API based on some existing one, they will say, "Huh, what is an
  479. // LLReqID ?" and look up this material.
  480. //
  481. // The hardest part about the convention is deciding where to store the
  482. // ["reqid"] value. Ironically, LLReqID cannot help with that: you must store
  483. // an LLReqID instance in whatever storage will persist until the reply is
  484. // sent. For example, if the request ultimately ends up using a Responder
  485. // subclass, storing an LLReqID instance in the Responder works.
  486. //
  487. // NOTE: the implementer of an event API must honor the ["reqid"] convention.
  488. // However, the caller of an event API need only use it if s/he is sharing the
  489. // same ["reply"] LLEventPump for two or more asynchronous event API requests.
  490. //
  491. // In most cases, it is far easier for the caller to instantiate a local
  492. // LLEventStream and pass its name to the event API in question. Then it is
  493. // perfectly reasonable not to set a ["reqid"] key in the request, ignoring
  494. // the isUndefined() ["reqid"] value in the response.
  495. class LLReqID
  496. {
  497. protected:
  498. LOG_CLASS(LLReqID);
  499. public:
  500. // If you have the request in hand at the time you instantiate the LLReqID,
  501. // pass that request to extract its ["reqid"].
  502. LLReqID(const LLSD& request)
  503. : mReqid(request["reqid"])
  504. {
  505. }
  506. // If you do not yet have the request, use setFrom() later.
  507. LLReqID() = default;
  508. // Extracts and stores the ["reqid"] value from an incoming request.
  509. LL_INLINE void setFrom(const LLSD& req) { mReqid = req["reqid"]; }
  510. // Sets ["reqid"] key into a pending response LLSD object.
  511. void stamp(LLSD& response) const;
  512. // Makes a whole new response LLSD object with our ["reqid"].
  513. LL_INLINE LLSD makeResponse() const
  514. {
  515. LLSD response;
  516. stamp(response);
  517. return response;
  518. }
  519. // Not really sure of a use case for this accessor...
  520. LL_INLINE LLSD getReqID() const { return mReqid; }
  521. private:
  522. LLSD mReqid;
  523. };
  524. #endif // LL_LLEVENTS_H