PageRenderTime 40ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/indra/llcommon/llcoros.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 154 lines | 80 code | 12 blank | 62 comment | 13 complexity | 92708b72549f814f4af1749062bf10cf MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llcoros.cpp
  3. * @author Nat Goodspeed
  4. * @date 2009-06-03
  5. * @brief Implementation for llcoros.
  6. *
  7. * $LicenseInfo:firstyear=2009&license=viewerlgpl$
  8. * Second Life Viewer Source Code
  9. * Copyright (C) 2010, Linden Research, Inc.
  10. *
  11. * This library is free software; you can redistribute it and/or
  12. * modify it under the terms of the GNU Lesser General Public
  13. * License as published by the Free Software Foundation;
  14. * version 2.1 of the License only.
  15. *
  16. * This library is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  19. * Lesser General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU Lesser General Public
  22. * License along with this library; if not, write to the Free Software
  23. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  24. *
  25. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  26. * $/LicenseInfo$
  27. */
  28. // Precompiled header
  29. #include "linden_common.h"
  30. // associated header
  31. #include "llcoros.h"
  32. // STL headers
  33. // std headers
  34. // external library headers
  35. #include <boost/bind.hpp>
  36. // other Linden headers
  37. #include "llevents.h"
  38. #include "llerror.h"
  39. #include "stringize.h"
  40. LLCoros::LLCoros()
  41. {
  42. // Register our cleanup() method for "mainloop" ticks
  43. LLEventPumps::instance().obtain("mainloop").listen(
  44. "LLCoros", boost::bind(&LLCoros::cleanup, this, _1));
  45. }
  46. bool LLCoros::cleanup(const LLSD&)
  47. {
  48. // Walk the mCoros map, checking and removing completed coroutines.
  49. for (CoroMap::iterator mi(mCoros.begin()), mend(mCoros.end()); mi != mend; )
  50. {
  51. // Has this coroutine exited (normal return, exception, exit() call)
  52. // since last tick?
  53. if (mi->second->exited())
  54. {
  55. LL_INFOS("LLCoros") << "LLCoros: cleaning up coroutine " << mi->first << LL_ENDL;
  56. // The erase() call will invalidate its passed iterator value --
  57. // so increment mi FIRST -- but pass its original value to
  58. // erase(). This is what postincrement is all about.
  59. mCoros.erase(mi++);
  60. }
  61. else
  62. {
  63. // Still live, just skip this entry as if incrementing at the top
  64. // of the loop as usual.
  65. ++mi;
  66. }
  67. }
  68. return false;
  69. }
  70. std::string LLCoros::generateDistinctName(const std::string& prefix) const
  71. {
  72. // Allowing empty name would make getName()'s not-found return ambiguous.
  73. if (prefix.empty())
  74. {
  75. LL_ERRS("LLCoros") << "LLCoros::launch(): pass non-empty name string" << LL_ENDL;
  76. }
  77. // If the specified name isn't already in the map, just use that.
  78. std::string name(prefix);
  79. // Find the lowest numeric suffix that doesn't collide with an existing
  80. // entry. Start with 2 just to make it more intuitive for any interested
  81. // parties: e.g. "joe", "joe2", "joe3"...
  82. for (int i = 2; ; name = STRINGIZE(prefix << i++))
  83. {
  84. if (mCoros.find(name) == mCoros.end())
  85. {
  86. LL_INFOS("LLCoros") << "LLCoros: launching coroutine " << name << LL_ENDL;
  87. return name;
  88. }
  89. }
  90. }
  91. bool LLCoros::kill(const std::string& name)
  92. {
  93. CoroMap::iterator found = mCoros.find(name);
  94. if (found == mCoros.end())
  95. {
  96. return false;
  97. }
  98. // Because this is a boost::ptr_map, erasing the map entry also destroys
  99. // the referenced heap object, in this case the boost::coroutine object,
  100. // which will terminate the coroutine.
  101. mCoros.erase(found);
  102. return true;
  103. }
  104. std::string LLCoros::getNameByID(const void* self_id) const
  105. {
  106. // Walk the existing coroutines, looking for one from which the 'self_id'
  107. // passed to us comes.
  108. for (CoroMap::const_iterator mi(mCoros.begin()), mend(mCoros.end()); mi != mend; ++mi)
  109. {
  110. namespace coro_private = boost::coroutines::detail;
  111. if (static_cast<void*>(coro_private::coroutine_accessor::get_impl(const_cast<coro&>(*mi->second)).get())
  112. == self_id)
  113. {
  114. return mi->first;
  115. }
  116. }
  117. return "";
  118. }
  119. /*****************************************************************************
  120. * MUST BE LAST
  121. *****************************************************************************/
  122. // Turn off MSVC optimizations for just LLCoros::launchImpl() -- see
  123. // DEV-32777. But MSVC doesn't support push/pop for optimization flags as it
  124. // does for warning suppression, and we really don't want to force
  125. // optimization ON for other code even in Debug or RelWithDebInfo builds.
  126. #if LL_MSVC
  127. // work around broken optimizations
  128. #pragma warning(disable: 4748)
  129. #pragma optimize("", off)
  130. #endif // LL_MSVC
  131. std::string LLCoros::launchImpl(const std::string& prefix, coro* newCoro)
  132. {
  133. std::string name(generateDistinctName(prefix));
  134. mCoros.insert(name, newCoro);
  135. /* Run the coroutine until its first wait, then return here */
  136. (*newCoro)(std::nothrow);
  137. return name;
  138. }
  139. #if LL_MSVC
  140. // reenable optimizations
  141. #pragma optimize("", on)
  142. #endif // LL_MSVC