llevents.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682
  1. /**
  2. * @file llevents.cpp
  3. * @author Nat Goodspeed
  4. * @date 2008-09-12
  5. * @brief Implementation for llevents.
  6. *
  7. * $LicenseInfo:firstyear=2008&license=viewergpl$
  8. *
  9. * Copyright (c) 2010, Linden Research, Inc.
  10. *
  11. * Second Life Viewer Source Code
  12. * The source code in this file ("Source Code") is provided by Linden Lab
  13. * to you under the terms of the GNU General Public License, version 2.0
  14. * ("GPL"), unless you have obtained a separate licensing agreement
  15. * ("Other License"), formally executed by you and Linden Lab. Terms of
  16. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  17. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  18. *
  19. * There are special exceptions to the terms and conditions of the GPL as
  20. * it is applied to this Source Code. View the full text of the exception
  21. * in the file doc/FLOSS-exception.txt in this software distribution, or
  22. * online at
  23. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  24. *
  25. * By copying, modifying or distributing this software, you acknowledge
  26. * that you have read and understood your obligations described above,
  27. * and agree to abide by those obligations.
  28. *
  29. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  30. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  31. * COMPLETENESS OR PERFORMANCE.
  32. * $/LicenseInfo$
  33. */
  34. #include "linden_common.h"
  35. #if LL_WINDOWS
  36. #pragma warning (disable : 4675) // "resolved by ADL" -- just as I want!
  37. #endif
  38. #include <algorithm>
  39. #include <cctype>
  40. #include <sstream>
  41. #include <typeinfo>
  42. #include "boost/fiber/exceptions.hpp"
  43. #include "boost/lexical_cast.hpp"
  44. #include "boost/ref.hpp"
  45. #include "boost/range/iterator_range.hpp"
  46. #include "llevents.h"
  47. #include "llsdutil.h"
  48. /*****************************************************************************
  49. * LLEventPumps
  50. *****************************************************************************/
  51. // Global
  52. LLEventPumps gEventPumps;
  53. //static
  54. bool LLEventPumps::sInstanceDestroyed = false;
  55. const std::string LLEventPump::ANONYMOUS = std::string();
  56. LLEventPump& LLEventPumps::obtain(const std::string& name)
  57. {
  58. PumpMap::iterator it = mPumpMap.find(name);
  59. if (it != mPumpMap.end())
  60. {
  61. // Here we already have an LLEventPump instance with the requested
  62. // name.
  63. return *it->second;
  64. }
  65. // Here we must instantiate an LLEventPump subclass.
  66. LLEventPump* new_instance = new LLEventStream(name);
  67. // LLEventPump's constructor implicitly registers each new instance in
  68. // mPumpMap. But remember that we instantiated it (in mOurPumps) so we'll
  69. // delete it later.
  70. mOurPumps.insert(new_instance);
  71. return *new_instance;
  72. }
  73. LLEventPump& LLEventPumps::make(const std::string& name, bool tweak,
  74. const std::string& type)
  75. {
  76. if (!type.empty() && type != "LLEventStream")
  77. {
  78. throw BadType(type);
  79. }
  80. // Here we must instantiate an LLEventPump subclass.
  81. LLEventPump* new_instance = new LLEventStream(name, tweak);
  82. // LLEventPump's constructor implicitly registers each new instance in
  83. // mPumpMap. But remember that we instantiated it (in mOurPumps) so we'll
  84. // delete it later.
  85. mOurPumps.insert(new_instance);
  86. return *new_instance;
  87. }
  88. bool LLEventPumps::post(const std::string& name, const LLSD& message)
  89. {
  90. PumpMap::iterator it = mPumpMap.find(name);
  91. if (it == mPumpMap.end())
  92. {
  93. return false;
  94. }
  95. return it->second->post(message);
  96. }
  97. void LLEventPumps::flush()
  98. {
  99. // Flush every known LLEventPump instance. Leave it up to each instance to
  100. // decide what to do with the flush() call.
  101. for (PumpMap::iterator it = mPumpMap.begin(), end = mPumpMap.end();
  102. it != end; ++it)
  103. {
  104. it->second->flush();
  105. }
  106. }
  107. void LLEventPumps::clear()
  108. {
  109. // Clear every known LLEventPump instance. Leave it up to each instance to
  110. // decide what to do with the clear() call.
  111. for (PumpMap::iterator it = mPumpMap.begin(), end = mPumpMap.end();
  112. it != end; ++it)
  113. {
  114. it->second->clear();
  115. }
  116. }
  117. void LLEventPumps::reset()
  118. {
  119. // Reset every known LLEventPump instance. Leave it up to each instance to
  120. // decide what to do with the reset() call.
  121. for (PumpMap::iterator it = mPumpMap.begin(), end = mPumpMap.end();
  122. it != end; ++it)
  123. {
  124. it->second->reset();
  125. }
  126. }
  127. std::string LLEventPumps::registerNew(const LLEventPump& pump,
  128. const std::string& name, bool tweak)
  129. {
  130. std::pair<PumpMap::iterator, bool> inserted =
  131. mPumpMap.emplace(name, const_cast<LLEventPump*>(&pump));
  132. // If the insert worked, then the name is unique; return that.
  133. if (inserted.second)
  134. {
  135. return name;
  136. }
  137. // Here the new entry was NOT inserted, and therefore name is not unique.
  138. // Unless we are permitted to tweak it, that's Bad.
  139. if (!tweak)
  140. {
  141. throw LLEventPump::DupPumpName("Duplicate LLEventPump name '" + name +
  142. "'");
  143. }
  144. // The passed name is not unique, but we are permitted to tweak it. Find
  145. // the first decimal-integer suffix not already taken. The insert() attempt
  146. // above will have set inserted.first to the iterator of the existing
  147. // entry by that name. Starting there, walk forward until we reach an
  148. // entry that does not start with 'name'. For each entry consisting of name
  149. // + integer suffix, capture the integer suffix in a set. Use a set
  150. // because we are going to encounter string suffixes in the order: name1,
  151. // name10, name11, name2, ... Walking those possibilities in that order
  152. // is not convenient to detect the first available "hole."
  153. std::set<int> suffixes;
  154. PumpMap::iterator pmi(inserted.first), pmend(mPumpMap.end());
  155. // We already know inserted.first references the existing entry with
  156. // 'name' as the key; skip that one and start with the next.
  157. while (++pmi != pmend)
  158. {
  159. if (pmi->first.substr(0, name.length()) != name)
  160. {
  161. // Found the first entry beyond the entries starting with 'name':
  162. // stop looping.
  163. break;
  164. }
  165. // Here we are looking at an entry that starts with 'name'. Is the rest
  166. // of it an integer?
  167. // Dubious (?) assumption: in the local character set, decimal digits
  168. // are in increasing order such that '9' is the last of them. This
  169. // test deals with 'name' values such as 'a', where there might be a
  170. // very large number of entries starting with 'a' whose suffixes
  171. // are not integers. A secondary assumption is that digit characters
  172. // precede most common name characters (true in ASCII, false in
  173. // EBCDIC). The test below is correct either way, but it is worth more
  174. // if the assumption holds.
  175. if (pmi->first[name.length()] > '9')
  176. {
  177. break;
  178. }
  179. // It should be cheaper to detect that we're not looking at a digit
  180. // character -- and therefore the suffix can't possibly be an integer
  181. // -- than to attempt the lexical_cast and catch the exception.
  182. if (!std::isdigit(pmi->first[name.length()]))
  183. {
  184. continue;
  185. }
  186. // Okay, the first character of the suffix is a digit, it's worth at
  187. // least attempting to convert to int.
  188. try
  189. {
  190. suffixes.insert(boost::lexical_cast<int>(pmi->first.substr(name.length())));
  191. }
  192. catch (const boost::bad_lexical_cast&)
  193. {
  194. // If the rest of pmi->first is not an int, just ignore it.
  195. }
  196. }
  197. // Here we have accumulated in 'suffixes' all existing int suffixes of the
  198. // entries starting with 'name'. Find the first unused one.
  199. int suffix = 1;
  200. for ( ; suffixes.find(suffix) != suffixes.end(); ++suffix) ;
  201. // Here 'suffix' is not in 'suffixes'. Construct a new name based on that
  202. // suffix, insert it and return it.
  203. std::ostringstream out;
  204. out << name << suffix;
  205. return registerNew(pump, out.str(), tweak);
  206. }
  207. void LLEventPumps::unregister(const LLEventPump& pump)
  208. {
  209. // Remove this instance from mPumpMap
  210. PumpMap::iterator it = mPumpMap.find(pump.getName());
  211. if (it != mPumpMap.end())
  212. {
  213. mPumpMap.erase(it);
  214. }
  215. // If this instance is one we created, also remove it from mOurPumps so we
  216. // would not try again to delete it later !
  217. PumpSet::iterator it2 = mOurPumps.find(const_cast<LLEventPump*>(&pump));
  218. if (it2 != mOurPumps.end())
  219. {
  220. mOurPumps.erase(it2);
  221. }
  222. }
  223. LLEventPumps::~LLEventPumps()
  224. {
  225. // On destruction, delete every LLEventPump we instantiated (via obtain()).
  226. // CAREFUL: deleting an LLEventPump calls its destructor, which calls
  227. // unregister(), which removes that LLEventPump instance from mOurPumps.
  228. // So an iterator loop over mOurPumps to delete contained LLEventPump
  229. // instances is dangerous ! Instead, delete them one at a time until
  230. // mOurPumps is empty.
  231. while (!mOurPumps.empty())
  232. {
  233. delete *mOurPumps.begin();
  234. }
  235. // Reset every remaining registered LLEventPump subclass instance: those
  236. // we did not instantiate using either make() or obtain().
  237. reset();
  238. sInstanceDestroyed = true; // Flag as gone forever. HB
  239. }
  240. bool LLEventPumps::sendReply(const LLSD& reply, const LLSD& request,
  241. const std::string& reply_key)
  242. {
  243. // If the original request has no value for reply_key, it is pointless to
  244. // construct or send a reply event: on which LLEventPump should we send
  245. // it ? Allow that to be optional: if the caller wants to require
  246. // reply_key, it can so specify when registering the operation method.
  247. if (!request.has(reply_key))
  248. {
  249. return false;
  250. }
  251. // Here the request definitely contains reply_key; reasonable to proceed.
  252. // Copy 'reply' to modify it.
  253. LLSD newreply(reply);
  254. // Get the ["reqid"] element from request
  255. LLReqID req_id(request);
  256. // And copy it to 'newreply'.
  257. req_id.stamp(newreply);
  258. // Send reply on LLEventPump named in request[reply_key]. Do not forget to
  259. // send the modified 'newreply' instead of the original 'reply'.
  260. return obtain(request[reply_key]).post(newreply);
  261. }
  262. /*****************************************************************************
  263. * LLEventPump
  264. *****************************************************************************/
  265. #if LL_WINDOWS
  266. # pragma warning (push)
  267. // 'this' is intentionally used in initializer list:
  268. # pragma warning (disable : 4355)
  269. #endif
  270. LLEventPump::LLEventPump(const std::string& name, bool tweak)
  271. // Register every new instance with LLEventPumps
  272. : mName(gEventPumps.registerNew(*this, name, tweak)),
  273. mSignal(std::make_shared<LLStandardSignal>()),
  274. mEnabled(true)
  275. {
  276. }
  277. #if LL_WINDOWS
  278. # pragma warning (pop)
  279. #endif
  280. LLEventPump::~LLEventPump()
  281. {
  282. // Unregister this doomed instance from LLEventPumps, but only when the
  283. // latter is still around !
  284. if (!LLEventPumps::destroyed())
  285. {
  286. gEventPumps.unregister(*this);
  287. }
  288. }
  289. // Static data member
  290. const LLEventPump::NameList LLEventPump::empty;
  291. //static
  292. std::string LLEventPump::inventName(const std::string& pfx)
  293. {
  294. static S32 suffix = 0;
  295. return llformat("%s%d", pfx.c_str(), suffix++);
  296. }
  297. void LLEventPump::clear()
  298. {
  299. mConnectionListMutex.lock();
  300. // Destroy the original LLStandardSignal instance, replacing it with a
  301. // whole new one.
  302. mSignal = std::make_shared<LLStandardSignal>();
  303. mConnections.clear();
  304. mConnectionListMutex.unlock();
  305. }
  306. void LLEventPump::reset()
  307. {
  308. mConnectionListMutex.lock();
  309. mSignal.reset();
  310. mConnections.clear();
  311. #if 0
  312. mDeps.clear();
  313. #endif
  314. mConnectionListMutex.unlock();
  315. }
  316. LLBoundListener LLEventPump::listen_impl(const std::string& name,
  317. const LLEventListener& listener,
  318. const NameList& after,
  319. const NameList& before)
  320. {
  321. if (!mSignal)
  322. {
  323. llwarns << "Cannot connect listener to: "
  324. << (name.empty() ? std::string("unnamed") : name) << " event."
  325. << llendl;
  326. return LLBoundListener();
  327. }
  328. LLMutexLock lock(&mConnectionListMutex);
  329. float node_position = 1.f;
  330. // If the supplied name is empty we are not interested in the ordering
  331. // mechanism and can bypass attempting to find the optimal location to
  332. // insert the new listener. We will just tack it on to the end.
  333. bool named = !name.empty();
  334. if (named)
  335. {
  336. // Check for duplicate name before connecting listener to mSignal
  337. connect_map_t::const_iterator it = mConnections.find(name);
  338. // In some cases the user might disconnect a connection explicitly and
  339. // we can end up retaining in mConnections a zombie connection object
  340. // that has already been disconnected. Such a connection object cannot
  341. // be reconnected since disconnection happens with the destruction of
  342. // the listener object. That means it is safe to overwrite a
  343. // disconnected connection object with the new one we are attempting.
  344. // The case we want to prevent is only when the existing connection
  345. // object is still connected.
  346. if (it != mConnections.end() && it->second.connected())
  347. {
  348. throw DupListenerName("Attempt to register duplicate listener name '" +
  349. name + "' on " + typeid(*this).name() +
  350. " '" + getName() + "'");
  351. }
  352. // Okay, name is unique, try to reconcile its dependencies. Specify a
  353. // new "node" value that we never use for an mSignal placement; we will
  354. // fix it later.
  355. depend_map_t::node_type& new_node = mDeps.add(name, -1.f, after,
  356. before);
  357. // What if this listener has been added, removed and re-added ? In
  358. // that case new_node already has a non-negative value because we never
  359. // remove a listener from mDeps. But keep processing uniformly anyway
  360. // in case the listener was added back with different dependencies.
  361. // Then mDeps.sort() would put it in a different position, and the old
  362. // new_node placement value would be wrong, so we would have to
  363. // reassign it anyway. Trust that re-adding a listener with the same
  364. // dependencies is the trivial case for mDeps.sort(): it can just
  365. // replay its cache.
  366. depend_map_t::sorted_range sorted_range;
  367. try
  368. {
  369. // Can we pick an order that works including this new entry ?
  370. sorted_range = mDeps.sort();
  371. }
  372. catch (const depend_map_t::Cycle& e)
  373. {
  374. // No: the new node's after/before dependencies have made mDeps
  375. // unsortable. If we leave the new node in mDeps, it will continue
  376. // to screw up all future attempts to sort()! Pull it out.
  377. mDeps.remove(name);
  378. throw Cycle("New listener '" + name + "' on " +
  379. typeid(*this).name() + " '" + getName() +
  380. "' would cause cycle: " + e.what());
  381. }
  382. // Walk the list to verify that we have not changed the order.
  383. float previous = 0.f, myprev = 0.f;
  384. // need this visible after loop:
  385. depend_map_t::sorted_iterator mydmi = sorted_range.end();
  386. for (depend_map_t::sorted_iterator dmi = sorted_range.begin();
  387. dmi != sorted_range.end(); ++dmi)
  388. {
  389. // Since we have added the new entry with an invalid placement,
  390. // recognize it and skip it.
  391. if (dmi->first == name)
  392. {
  393. // Remember the iterator belonging to our new node, and which
  394. // placement value was 'previous' at that point.
  395. mydmi = dmi;
  396. myprev = previous;
  397. continue;
  398. }
  399. // If the new node has rearranged the existing nodes, we will find
  400. // that their placement values are no longer in increasing order.
  401. if (dmi->second < previous)
  402. {
  403. // This is another scenario in which we'd better back out the
  404. // newly-added node from mDeps, but do not do it yet, we want
  405. // to traverse the existing mDeps to report on it !
  406. // Describe the change to the order of our listeners. Copy
  407. // everything but the newest listener to a vector we can sort
  408. // to obtain the old order.
  409. typedef std::vector<std::pair<float, std::string> > SortNameList;
  410. SortNameList sortnames;
  411. for (depend_map_t::sorted_iterator cdmi = sorted_range.begin(),
  412. cdmend = sorted_range.end();
  413. cdmi != cdmend; ++cdmi)
  414. {
  415. if (cdmi->first != name)
  416. {
  417. sortnames.push_back(SortNameList::value_type(cdmi->second,
  418. cdmi->first));
  419. }
  420. }
  421. std::sort(sortnames.begin(), sortnames.end());
  422. std::ostringstream out;
  423. out << "New listener '" << name << "' on "
  424. << typeid(*this).name() << " '" << getName()
  425. << "' would move previous listener '" << dmi->first
  426. << "'\nwas: ";
  427. SortNameList::const_iterator sni(sortnames.begin()),
  428. snend(sortnames.end());
  429. if (sni != snend)
  430. {
  431. out << sni->second;
  432. while (++sni != snend)
  433. {
  434. out << ", " << sni->second;
  435. }
  436. }
  437. out << "\nnow: ";
  438. depend_map_t::sorted_iterator ddmi(sorted_range.begin());
  439. depend_map_t::sorted_iterator ddmend(sorted_range.end());
  440. if (ddmi != ddmend)
  441. {
  442. out << ddmi->first;
  443. while (++ddmi != ddmend)
  444. {
  445. out << ", " << ddmi->first;
  446. }
  447. }
  448. // NOW remove the offending listener node.
  449. mDeps.remove(name);
  450. // Having constructed a description of the order change, inform
  451. // caller.
  452. throw OrderChange(out.str());
  453. }
  454. // This node becomes the previous one.
  455. previous = dmi->second;
  456. }
  457. // We just got done with a successful mDeps.add(name, ...) call. We had
  458. // better have found 'name' somewhere in that sorted list !
  459. assert(mydmi != sorted_range.end());
  460. // Four cases:
  461. // 0. name is the only entry: placement 1.0
  462. // 1. name is the first of several entries: placement (next placement)/2
  463. // 2. name is between two other entries: placement (myprev + (next placement))/2
  464. // 3. name is the last entry: placement ceil(myprev) + 1.0
  465. // Since we have cleverly arranged for myprev to be 0.0 if name is the
  466. // first entry, this folds down to two cases. Case 1 is subsumed by
  467. // case 2, and case 0 is subsumed by case 3. So we need only handle
  468. // cases 2 and 3, which means we need only detect whether name is the
  469. // last entry. Increment mydmi to see if there's anything beyond.
  470. if (++mydmi != sorted_range.end())
  471. {
  472. // The new node is not last. Place it between the previous node and
  473. // the successor.
  474. new_node = (myprev + mydmi->second) * 0.5f;
  475. }
  476. else
  477. {
  478. // The new node is last. Bump myprev up to the next integer, add
  479. // 1.0 and use that.
  480. new_node = std::ceil(myprev) + 1.f;
  481. }
  482. node_position = new_node;
  483. }
  484. // Now that new_node has a value that places it appropriately in mSignal,
  485. // connect it.
  486. LLBoundListener bound = mSignal->connect(node_position, listener);
  487. if (named)
  488. {
  489. // Note that we are not tracking anonymous listeners here either.
  490. // This means that it is the caller's responsibility to either assign
  491. // to a TempBoundListerer (scoped_connection) or manually disconnect
  492. // when done.
  493. mConnections[name] = bound;
  494. }
  495. return bound;
  496. }
  497. LLBoundListener LLEventPump::getListener(const std::string& name) const
  498. {
  499. LLMutexLock lock(&mConnectionListMutex);
  500. connect_map_t::const_iterator it = mConnections.find(name);
  501. if (it != mConnections.end())
  502. {
  503. return it->second;
  504. }
  505. // Not found, return dummy LLBoundListener
  506. return LLBoundListener();
  507. }
  508. void LLEventPump::stopListening(const std::string& name)
  509. {
  510. mConnectionListMutex.lock();
  511. connect_map_t::iterator it = mConnections.find(name);
  512. if (it != mConnections.end())
  513. {
  514. it->second.disconnect();
  515. mConnections.erase(it);
  516. }
  517. // We intentionally do NOT remove this name from mDeps. It may happen that
  518. // the same listener with the same name and dependencies will jump on and
  519. // off this LLEventPump repeatedly. Keeping a cache of dependencies will
  520. // avoid a new dependency sort in such cases.
  521. mConnectionListMutex.unlock();
  522. }
  523. void LLEventPump::removeFromDeps(const std::string& name)
  524. {
  525. mDeps.remove(name);
  526. mDeps.clearCache();
  527. }
  528. /*****************************************************************************
  529. * LLEventStream
  530. *****************************************************************************/
  531. bool LLEventStream::post(const LLSD& event)
  532. {
  533. if (!mEnabled || !mSignal)
  534. {
  535. return false;
  536. }
  537. // NOTE NOTE NOTE: Any new access to member data beyond this point should
  538. // cause us to move our LLStandardSignal object to a pimpl class along
  539. // with said member data. Then the local shared_ptr will preserve both.
  540. // DEV-43463: capture a local copy of mSignal. We have turned up a cross-
  541. // coroutine scenario (described in the JIRA) in which this post() call
  542. // could end up destroying 'this', the LLEventPump subclass instance
  543. // containing mSignal, during the call through *mSignal. So capture a
  544. // *stack* instance of the shared_ptr, ensuring that our heap
  545. // LLStandardSignal object will live at least until post() returns, even
  546. // if 'this' gets destroyed during the call.
  547. std::shared_ptr<LLStandardSignal> signal(mSignal);
  548. // Let caller know if any one listener handled the event. This is mostly
  549. // useful when using LLEventStream as a listener for an upstream
  550. // LLEventPump.
  551. bool res = false;
  552. if (signal)
  553. {
  554. try
  555. {
  556. res = (*signal)(event);
  557. }
  558. catch (boost::fibers::fiber_error& e)
  559. {
  560. // Ignore these
  561. llwarns << "Event stream: " << getName() << " - Caught exception: "
  562. << e.what() << llendl;
  563. }
  564. }
  565. return res;
  566. }
  567. /*****************************************************************************
  568. * LLListenerOrPumpName
  569. *****************************************************************************/
  570. LLListenerOrPumpName::LLListenerOrPumpName(const std::string& pumpname)
  571. // Look up the specified pumpname, and bind its post() method as our
  572. // listener
  573. : mListener(boost::bind(&LLEventPump::post,
  574. boost::ref(gEventPumps.obtain(pumpname)), _1))
  575. {
  576. }
  577. LLListenerOrPumpName::LLListenerOrPumpName(const char* pumpname)
  578. // Look up the specified pumpname, and bind its post() method as our
  579. // listener
  580. : mListener(boost::bind(&LLEventPump::post,
  581. boost::ref(gEventPumps.obtain(pumpname)), _1))
  582. {
  583. }
  584. bool LLListenerOrPumpName::operator()(const LLSD& event) const
  585. {
  586. if (!mListener)
  587. {
  588. throw Empty("attempting to call uninitialized");
  589. }
  590. return (*mListener)(event);
  591. }
  592. void LLReqID::stamp(LLSD& response) const
  593. {
  594. if (!(response.isUndefined() || response.isMap()))
  595. {
  596. // If 'response' was previously completely empty, it is OK to turn it
  597. // into a map. If it was already a map, then it should be OK to add a
  598. // key. But if it was anything else (e.g. a scalar), assigning a
  599. // ["reqid"] key will DISCARD the previous value, replacing it with a
  600. // map. That would be bad.
  601. llinfos << "stamp(" << mReqid
  602. << ") leaving non-map response unmodified: " << response
  603. << llendl;
  604. return;
  605. }
  606. LLSD old_reqid(response["reqid"]);
  607. if (!(old_reqid.isUndefined() || llsd_equals(old_reqid, mReqid)))
  608. {
  609. llinfos << "stamp(" << mReqid
  610. << ") preserving existing [\"reqid\"] value " << old_reqid
  611. << " in response: " << response << llendl;
  612. return;
  613. }
  614. response["reqid"] = mReqid;
  615. }