summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
authorNat Goodspeed <nat@lindenlab.com>2016-09-03 11:39:17 -0400
committerNat Goodspeed <nat@lindenlab.com>2016-09-03 11:39:17 -0400
commitf931f6ef521527a929ceddf1354c7e2d85b35b63 (patch)
tree71a7f2cb79156983efd04940315921cfaeca66f9 /indra
parentc71e6222295a1fb183436b5d67c21bffddfaefa6 (diff)
MAINT-5232: Add LLCoros::get_id() to identify the running coroutine.
Change the module-static thread_specific_ptr to a function-static thread_specific_ptr so it will be initialized on demand -- since LLSingleton will need to rely on get_id(). Note that since LLCoros isa LLSingleton, we must take great care to avoid circularity. Introduce a private helper class LLCoros::Current to obtain and bind that thread_specific_ptr. Change all existing internal references from the static thread_specific_ptr to the new Current helper class.
Diffstat (limited to 'indra')
-rw-r--r--indra/llcommon/llcoros.cpp58
-rw-r--r--indra/llcommon/llcoros.h24
2 files changed, 56 insertions, 26 deletions
diff --git a/indra/llcommon/llcoros.cpp b/indra/llcommon/llcoros.cpp
index d16bf0160b..e84fa6aea0 100644
--- a/indra/llcommon/llcoros.cpp
+++ b/indra/llcommon/llcoros.cpp
@@ -44,16 +44,25 @@ void LLCoros::no_cleanup(CoroData*) {}
// CoroData for the currently-running coroutine. Use a thread_specific_ptr
// because each thread potentially has its own distinct pool of coroutines.
-// This thread_specific_ptr does NOT own the CoroData object! That's owned by
-// LLCoros::mCoros. It merely identifies it. For this reason we instantiate
-// it with a no-op cleanup function.
-boost::thread_specific_ptr<LLCoros::CoroData>
-LLCoros::sCurrentCoro(LLCoros::no_cleanup);
+LLCoros::Current::Current()
+{
+ // Use a function-static instance so this thread_specific_ptr is
+ // instantiated on demand. Since we happen to know it's consumed by
+ // LLSingleton, this is likely to happen before the runtime has finished
+ // initializing module-static data. For the same reason, we can't package
+ // this pointer in an LLSingleton.
+
+ // This thread_specific_ptr does NOT own the CoroData object! That's owned
+ // by LLCoros::mCoros. It merely identifies it. For this reason we
+ // instantiate it with a no-op cleanup function.
+ static boost::thread_specific_ptr<LLCoros::CoroData> sCurrent(LLCoros::no_cleanup);
+ mCurrent = &sCurrent;
+}
//static
LLCoros::CoroData& LLCoros::get_CoroData(const std::string& caller)
{
- CoroData* current = sCurrentCoro.get();
+ CoroData* current = Current();
if (! current)
{
LL_ERRS("LLCoros") << "Calling " << caller << " from non-coroutine context!" << LL_ENDL;
@@ -79,20 +88,23 @@ bool LLCoros::get_consuming()
return get_CoroData("get_consuming()").mConsuming;
}
-llcoro::Suspending::Suspending():
- mSuspended(LLCoros::sCurrentCoro.get())
+llcoro::Suspending::Suspending()
{
- // Revert mCurrentCoro to the value it had at the moment we last switched
+ LLCoros::Current current;
+ // Remember currently-running coroutine: we're about to suspend it.
+ mSuspended = current;
+ // Revert Current to the value it had at the moment we last switched
// into this coroutine.
- LLCoros::sCurrentCoro.reset(mSuspended->mPrev);
+ current.reset(mSuspended->mPrev);
}
llcoro::Suspending::~Suspending()
{
+ LLCoros::Current current;
// Okay, we're back, update our mPrev
- mSuspended->mPrev = LLCoros::sCurrentCoro.get();
- // and reinstate our sCurrentCoro.
- LLCoros::sCurrentCoro.reset(mSuspended);
+ mSuspended->mPrev = current;
+ // and reinstate our Current.
+ current.reset(mSuspended);
}
LLCoros::LLCoros():
@@ -212,7 +224,7 @@ bool LLCoros::kill(const std::string& name)
std::string LLCoros::getName() const
{
- CoroData* current = sCurrentCoro.get();
+ CoroData* current = Current();
if (! current)
{
// not in a coroutine
@@ -228,8 +240,8 @@ void LLCoros::setStackSize(S32 stacksize)
}
// Top-level wrapper around caller's coroutine callable. This function accepts
-// the coroutine library's implicit coro::self& parameter and sets sCurrentSelf
-// but does not pass it down to the caller's callable.
+// the coroutine library's implicit coro::self& parameter and saves it, but
+// does not pass it down to the caller's callable.
void LLCoros::toplevel(coro::self& self, CoroData* data, const callable_t& callable)
{
// capture the 'self' param in CoroData
@@ -237,8 +249,8 @@ void LLCoros::toplevel(coro::self& self, CoroData* data, const callable_t& calla
// run the code the caller actually wants in the coroutine
callable();
// This cleanup isn't perfectly symmetrical with the way we initially set
- // data->mPrev, but this is our last chance to reset mCurrentCoro.
- sCurrentCoro.reset(data->mPrev);
+ // data->mPrev, but this is our last chance to reset Current.
+ Current().reset(data->mPrev);
}
/*****************************************************************************
@@ -261,7 +273,7 @@ LLCoros::CoroData::CoroData(CoroData* prev, const std::string& name,
mPrev(prev),
mName(name),
// Wrap the caller's callable in our toplevel() function so we can manage
- // sCurrentCoro appropriately at startup and shutdown of each coroutine.
+ // Current appropriately at startup and shutdown of each coroutine.
mCoro(boost::bind(toplevel, _1, this, callable), stacksize),
// don't consume events unless specifically directed
mConsuming(false),
@@ -272,13 +284,13 @@ LLCoros::CoroData::CoroData(CoroData* prev, const std::string& name,
std::string LLCoros::launch(const std::string& prefix, const callable_t& callable)
{
std::string name(generateDistinctName(prefix));
- // pass the current value of sCurrentCoro as previous context
- CoroData* newCoro = new CoroData(sCurrentCoro.get(), name,
- callable, mStackSize);
+ Current current;
+ // pass the current value of Current as previous context
+ CoroData* newCoro = new CoroData(current, name, callable, mStackSize);
// Store it in our pointer map
mCoros.insert(name, newCoro);
// also set it as current
- sCurrentCoro.reset(newCoro);
+ current.reset(newCoro);
/* Run the coroutine until its first wait, then return here */
(newCoro->mCoro)(std::nothrow);
return name;
diff --git a/indra/llcommon/llcoros.h b/indra/llcommon/llcoros.h
index 39316ed0e6..93e5ea8b9f 100644
--- a/indra/llcommon/llcoros.h
+++ b/indra/llcommon/llcoros.h
@@ -35,6 +35,7 @@
#include <boost/ptr_container/ptr_map.hpp>
#include <boost/function.hpp>
#include <boost/thread/tss.hpp>
+#include <boost/noncopyable.hpp>
#include <string>
#include <stdexcept>
@@ -145,6 +146,10 @@ public:
*/
std::string getName() const;
+ /// Get an opaque, distinct token for the running coroutine (or main).
+ typedef void* id;
+ static id get_id() { return Current(); }
+
/// for delayed initialization
void setStackSize(S32 stacksize);
@@ -222,8 +227,21 @@ private:
typedef boost::ptr_map<std::string, CoroData> CoroMap;
CoroMap mCoros;
- // identify the current coroutine's CoroData
- static boost::thread_specific_ptr<LLCoros::CoroData> sCurrentCoro;
+ // Identify the current coroutine's CoroData. Use a little helper class so
+ // a caller can either use a temporary instance, or instantiate a named
+ // variable and access it multiple times.
+ class Current
+ {
+ public:
+ Current();
+
+ operator LLCoros::CoroData*() { return get(); }
+ LLCoros::CoroData* get() { return mCurrent->get(); }
+ void reset(LLCoros::CoroData* ptr) { mCurrent->reset(ptr); }
+
+ private:
+ boost::thread_specific_ptr<LLCoros::CoroData>* mCurrent;
+ };
};
namespace llcoro
@@ -231,7 +249,7 @@ namespace llcoro
/// Instantiate one of these in a block surrounding any leaf point when
/// control literally switches away from this coroutine.
-class Suspending
+class Suspending: boost::noncopyable
{
public:
Suspending();