DRTVWR-494: LLParamSingleton::initParamSingleton() on main thread.

When calling LLParamSingleton::initParamSingleton() on a secondary thread, use
LLMainThreadTask::dispatch() to construct the instance on the main thread --
as with LLSingleton::getInstance().
master
Nat Goodspeed 2019-12-12 17:17:06 -05:00
parent 68505edf25
commit 7e9c5dd0a3
1 changed files with 43 additions and 4 deletions

View File

@ -59,6 +59,7 @@ protected:
typedef enum e_init_state
{
UNINITIALIZED = 0, // must be default-initialized state
QUEUED, // construction queued, not yet executing
CONSTRUCTING, // within DERIVED_TYPE constructor
INITIALIZING, // within DERIVED_TYPE::initSingleton()
INITIALIZED, // normal case
@ -552,6 +553,11 @@ public:
" -- creating new instance");
// fall through
case UNINITIALIZED:
case QUEUED:
// QUEUED means some secondary thread has already requested an
// instance, but for present purposes that's semantically
// identical to UNINITIALIZED: either way, we must ourselves
// request an instance.
break;
}
@ -564,10 +570,13 @@ public:
capture_dependency(lk->mInstance);
return lk->mInstance;
}
// Here we need to construct a new instance, but we're on a secondary
// thread.
lk->mInitState = QUEUED;
} // unlock 'lk'
// Here we need to construct a new instance, but we're on a secondary
// thread. Per the comment block above, dispatch to the main thread.
// Per the comment block above, dispatch to the main thread.
loginfos(classname<DERIVED_TYPE>().c_str(),
"::getInstance() dispatching to main thread");
auto instance = LLMainThreadTask::dispatch(
@ -588,7 +597,7 @@ public:
// suppresses dep tracking when dispatched to the main thread)
capture_dependency(instance);
loginfos(classname<DERIVED_TYPE>().c_str(),
"::getInstance() returning on invoking thread");
"::getInstance() returning on requesting thread");
return instance;
}
@ -672,11 +681,40 @@ public:
" twice!");
return nullptr;
}
else
else if (on_main_thread())
{
// on the main thread, simply construct instance while holding lock
super::constructSingleton(lk, std::forward<Args>(args)...);
return lk->mInstance;
}
else
{
// on secondary thread, dispatch to main thread --
// set state so we catch any other calls before the main thread
// picks up the task
lk->mInitState = super::QUEUED;
// very important to unlock here so main thread can actually process
lk.unlock();
super::loginfos(super::template classname<DERIVED_TYPE>().c_str(),
"::initParamSingleton() dispatching to main thread");
// Normally it would be the height of folly to reference-bind
// 'args' into a lambda to be executed on some other thread! By
// the time that thread executed the lambda, the references would
// all be dangling, and Bad Things would result. But
// LLMainThreadTask::dispatch() promises to block until the passed
// task has completed. So in this case we know the references will
// remain valid until the lambda has run, so we dare to bind
// references.
auto instance = LLMainThreadTask::dispatch(
[&](){
super::loginfos(super::template classname<DERIVED_TYPE>().c_str(),
"::initParamSingleton() on main thread");
return initParamSingleton(std::forward<Args>(args)...);
});
super::loginfos(super::template classname<DERIVED_TYPE>().c_str(),
"::initParamSingleton() returning on requesting thread");
return instance;
}
}
static DERIVED_TYPE* getInstance()
@ -688,6 +726,7 @@ public:
switch (lk->mInitState)
{
case super::UNINITIALIZED:
case super::QUEUED:
super::logerrs("Uninitialized param singleton ",
super::template classname<DERIVED_TYPE>().c_str());
break;