Change mainloop to no longer use gIdleCallbacks
This commit is contained in:
@@ -32,7 +32,6 @@
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "llcallbacklist.h"
|
||||
#include "llcontrol.h"
|
||||
#include "llfasttimer.h"
|
||||
#include "aithreadsafe.h"
|
||||
@@ -66,17 +65,11 @@ namespace {
|
||||
|
||||
typedef std::vector<QueueElement> active_statemachines_type;
|
||||
active_statemachines_type active_statemachines;
|
||||
typedef std::vector<AIStateMachine*> continued_statemachines_type;
|
||||
struct cscm_type
|
||||
{
|
||||
continued_statemachines_type continued_statemachines;
|
||||
bool calling_mainloop;
|
||||
};
|
||||
AIThreadSafeDC<cscm_type> continued_statemachines_and_calling_mainloop;
|
||||
}
|
||||
|
||||
// static
|
||||
AIThreadSafeSimpleDC<U64> AIStateMachine::sMaxCount;
|
||||
AIThreadSafeDC<AIStateMachine::csme_type> AIStateMachine::sContinuedStateMachinesAndMainloopEnabled;
|
||||
|
||||
void AIStateMachine::updateSettings(void)
|
||||
{
|
||||
@@ -221,24 +214,23 @@ void AIStateMachine::locked_cont(void)
|
||||
// If not_active is true then main-thread is not running this statemachine.
|
||||
// It might call cont() (or set_state()) but never locked_cont(), and will never
|
||||
// start actually running until we are done here and release the lock on
|
||||
// continued_statemachines_and_calling_mainloop again. It is therefore safe
|
||||
// sContinuedStateMachinesAndMainloopEnabled again. It is therefore safe
|
||||
// to release mSetStateLock here, with as advantage that if we're not the main-
|
||||
// thread and not_active is true, then the main-thread won't block when it has
|
||||
// a timer running that times out and calls set_state().
|
||||
mSetStateLock.unlock();
|
||||
if (not_active)
|
||||
{
|
||||
AIWriteAccess<cscm_type> cscm_w(continued_statemachines_and_calling_mainloop);
|
||||
AIWriteAccess<csme_type> csme_w(sContinuedStateMachinesAndMainloopEnabled);
|
||||
// See above: it is not possible that mActive was changed since not_active
|
||||
// was set to true above.
|
||||
llassert_always(mActive == as_idle);
|
||||
Dout(dc::statemachine, "Adding " << (void*)this << " to continued_statemachines");
|
||||
cscm_w->continued_statemachines.push_back(this);
|
||||
if (!cscm_w->calling_mainloop)
|
||||
csme_w->continued_statemachines.push_back(this);
|
||||
if (!csme_w->mainloop_enabled)
|
||||
{
|
||||
Dout(dc::statemachine, "Adding AIStateMachine::mainloop to gIdleCallbacks");
|
||||
cscm_w->calling_mainloop = true;
|
||||
gIdleCallbacks.addFunction(&AIStateMachine::mainloop);
|
||||
Dout(dc::statemachine, "Activating AIStateMachine::mainloop.");
|
||||
csme_w->mainloop_enabled = true;
|
||||
}
|
||||
mActive = as_queued;
|
||||
llassert_always(!mIdle); // It should never happen that the main thread calls idle(), while another thread calls cont() concurrently.
|
||||
@@ -499,11 +491,10 @@ void AIStateMachine::multiplex(U64 current_time)
|
||||
}
|
||||
|
||||
//static
|
||||
void AIStateMachine::add_continued_statemachines(void)
|
||||
void AIStateMachine::add_continued_statemachines(AIReadAccess<csme_type>& csme_r)
|
||||
{
|
||||
AIReadAccess<cscm_type> cscm_r(continued_statemachines_and_calling_mainloop);
|
||||
bool nonempty = false;
|
||||
for (continued_statemachines_type::const_iterator iter = cscm_r->continued_statemachines.begin(); iter != cscm_r->continued_statemachines.end(); ++iter)
|
||||
for (continued_statemachines_type::const_iterator iter = csme_r->continued_statemachines.begin(); iter != csme_r->continued_statemachines.end(); ++iter)
|
||||
{
|
||||
nonempty = true;
|
||||
active_statemachines.push_back(QueueElement(*iter));
|
||||
@@ -511,15 +502,12 @@ void AIStateMachine::add_continued_statemachines(void)
|
||||
(*iter)->mActive = as_active;
|
||||
}
|
||||
if (nonempty)
|
||||
AIWriteAccess<cscm_type>(cscm_r)->continued_statemachines.clear();
|
||||
AIWriteAccess<csme_type>(csme_r)->continued_statemachines.clear();
|
||||
}
|
||||
|
||||
static LLFastTimer::DeclareTimer FTM_STATEMACHINE("State Machine");
|
||||
// static
|
||||
void AIStateMachine::mainloop(void*)
|
||||
void AIStateMachine::dowork(void)
|
||||
{
|
||||
LLFastTimer t(FTM_STATEMACHINE);
|
||||
add_continued_statemachines();
|
||||
llassert(!active_statemachines.empty());
|
||||
// Run one or more state machines.
|
||||
U64 total_clocks = 0;
|
||||
@@ -590,12 +578,11 @@ void AIStateMachine::mainloop(void*)
|
||||
if (active_statemachines.empty())
|
||||
{
|
||||
// If this was the last state machine, remove mainloop from the IdleCallbacks.
|
||||
AIReadAccess<cscm_type> cscm_r(continued_statemachines_and_calling_mainloop);
|
||||
if (cscm_r->continued_statemachines.empty() && cscm_r->calling_mainloop)
|
||||
AIReadAccess<csme_type> csme_r(sContinuedStateMachinesAndMainloopEnabled, true);
|
||||
if (csme_r->continued_statemachines.empty() && csme_r->mainloop_enabled)
|
||||
{
|
||||
Dout(dc::statemachine, "Removing AIStateMachine::mainloop from gIdleCallbacks");
|
||||
AIWriteAccess<cscm_type>(cscm_r)->calling_mainloop = false;
|
||||
gIdleCallbacks.deleteFunction(&AIStateMachine::mainloop);
|
||||
Dout(dc::statemachine, "Deactivating AIStateMachine::mainloop: no active state machines left.");
|
||||
AIWriteAccess<csme_type>(csme_r)->mainloop_enabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -604,7 +591,10 @@ void AIStateMachine::mainloop(void*)
|
||||
void AIStateMachine::flush(void)
|
||||
{
|
||||
DoutEntering(dc::curl, "AIStateMachine::flush(void)");
|
||||
add_continued_statemachines();
|
||||
{
|
||||
AIReadAccess<csme_type> csme_r(sContinuedStateMachinesAndMainloopEnabled);
|
||||
add_continued_statemachines(csme_r);
|
||||
}
|
||||
// Abort all state machines.
|
||||
for (active_statemachines_type::iterator iter = active_statemachines.begin(); iter != active_statemachines.end(); ++iter)
|
||||
{
|
||||
@@ -618,15 +608,18 @@ void AIStateMachine::flush(void)
|
||||
for(;;)
|
||||
{
|
||||
{
|
||||
AIReadAccess<cscm_type> cscm_r(continued_statemachines_and_calling_mainloop);
|
||||
if (!cscm_r->calling_mainloop)
|
||||
AIReadAccess<csme_type> csme_r(sContinuedStateMachinesAndMainloopEnabled);
|
||||
if (!csme_r->mainloop_enabled)
|
||||
break;
|
||||
}
|
||||
mainloop(NULL);
|
||||
mainloop();
|
||||
}
|
||||
if (batch == 1)
|
||||
break;
|
||||
add_continued_statemachines();
|
||||
{
|
||||
AIReadAccess<csme_type> csme_r(sContinuedStateMachinesAndMainloopEnabled);
|
||||
add_continued_statemachines(csme_r);
|
||||
}
|
||||
// Kill all state machines.
|
||||
for (active_statemachines_type::iterator iter = active_statemachines.begin(); iter != active_statemachines.end(); ++iter)
|
||||
{
|
||||
|
||||
@@ -192,6 +192,15 @@ class AIStateMachine {
|
||||
as_active // State machine is on active_statemachines list.
|
||||
};
|
||||
|
||||
//! Type of continued_statemachines.
|
||||
typedef std::vector<AIStateMachine*> continued_statemachines_type;
|
||||
//! Type of sContinuedStateMachinesAndMainloopEnabled.
|
||||
struct csme_type
|
||||
{
|
||||
continued_statemachines_type continued_statemachines;
|
||||
bool mainloop_enabled;
|
||||
};
|
||||
|
||||
public:
|
||||
typedef U32 state_type; //!< The type of mRunState
|
||||
|
||||
@@ -231,6 +240,7 @@ class AIStateMachine {
|
||||
callback_type* mCallback; //!< Pointer to signal/connection, or NULL when not connected.
|
||||
|
||||
static AIThreadSafeSimpleDC<U64> sMaxCount; //!< Number of cpu clocks below which we start a new state machine within the same frame.
|
||||
static AIThreadSafeDC<csme_type> sContinuedStateMachinesAndMainloopEnabled; //!< Read/write locked variable pair.
|
||||
|
||||
protected:
|
||||
LLMutex mSetStateLock; //!< For critical areas in set_state() and locked_cont().
|
||||
@@ -365,11 +375,24 @@ class AIStateMachine {
|
||||
char const* state_str(state_type state);
|
||||
|
||||
private:
|
||||
static void add_continued_statemachines(void);
|
||||
static void mainloop(void*);
|
||||
static void add_continued_statemachines(AIReadAccess<csme_type>& csme_r);
|
||||
static void dowork(void);
|
||||
void multiplex(U64 current_time);
|
||||
|
||||
public:
|
||||
//! Call this once per frame to give the statemachines CPU cycles.
|
||||
static void mainloop(void)
|
||||
{
|
||||
{
|
||||
AIReadAccess<csme_type> csme_r(sContinuedStateMachinesAndMainloopEnabled, true);
|
||||
if (!csme_r->mainloop_enabled)
|
||||
return;
|
||||
if (!csme_r->continued_statemachines.empty())
|
||||
add_continued_statemachines(csme_r);
|
||||
}
|
||||
dowork();
|
||||
}
|
||||
|
||||
//! Abort all running state machines and then run mainloop until all state machines are idle (called when application is exiting).
|
||||
static void flush(void);
|
||||
|
||||
|
||||
@@ -329,14 +329,14 @@ struct AIReadAccessConst
|
||||
};
|
||||
|
||||
//! Construct a AIReadAccessConst from a constant AIThreadSafe.
|
||||
AIReadAccessConst(AIThreadSafe<T> const& wrapper)
|
||||
AIReadAccessConst(AIThreadSafe<T> const& wrapper, bool high_priority = false)
|
||||
: mWrapper(const_cast<AIThreadSafe<T>&>(wrapper)),
|
||||
mState(readlocked)
|
||||
#if AI_NEED_ACCESS_CC
|
||||
, mIsCopyConstructed(false)
|
||||
#endif
|
||||
{
|
||||
mWrapper.mRWLock.rdlock();
|
||||
mWrapper.mRWLock.rdlock(high_priority);
|
||||
}
|
||||
|
||||
//! Destruct the AI*Access object.
|
||||
@@ -393,7 +393,7 @@ struct AIReadAccess : public AIReadAccessConst<T>
|
||||
using AIReadAccessConst<T>::readlocked;
|
||||
|
||||
//! Construct a AIReadAccess from a non-constant AIThreadSafe.
|
||||
AIReadAccess(AIThreadSafe<T>& wrapper) : AIReadAccessConst<T>(wrapper, readlocked) { this->mWrapper.mRWLock.rdlock(); }
|
||||
AIReadAccess(AIThreadSafe<T>& wrapper, bool high_priority = false) : AIReadAccessConst<T>(wrapper, readlocked) { this->mWrapper.mRWLock.rdlock(high_priority); }
|
||||
|
||||
protected:
|
||||
//! Constructor used by AIWriteAccess.
|
||||
|
||||
@@ -367,6 +367,7 @@ void LLCrashLogger::updateApplication(const std::string& message)
|
||||
{
|
||||
gServicePump->pump();
|
||||
gServicePump->callback();
|
||||
//FIXME: AIStateMachine::mainloop(); needs CPU cycles. Can't call it from here though, because it uses gSavedSettings which is part of newview.
|
||||
}
|
||||
|
||||
bool LLCrashLogger::init()
|
||||
|
||||
@@ -1034,6 +1034,7 @@ static LLFastTimer::DeclareTimer FTM_PUMP_SERVICE("Service");
|
||||
static LLFastTimer::DeclareTimer FTM_SERVICE_CALLBACK("Callback");
|
||||
static LLFastTimer::DeclareTimer FTM_AGENT_AUTOPILOT("Autopilot");
|
||||
static LLFastTimer::DeclareTimer FTM_AGENT_UPDATE("Update");
|
||||
static LLFastTimer::DeclareTimer FTM_STATEMACHINE("State Machine");
|
||||
|
||||
bool LLAppViewer::mainLoop()
|
||||
{
|
||||
@@ -3772,6 +3773,16 @@ void LLAppViewer::idle()
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////
|
||||
//
|
||||
// Run state machines
|
||||
//
|
||||
|
||||
{
|
||||
LLFastTimer t(FTM_STATEMACHINE);
|
||||
AIStateMachine::mainloop();
|
||||
}
|
||||
|
||||
// Must wait until both have avatar object and mute list, so poll
|
||||
// here.
|
||||
request_initial_instant_messages();
|
||||
|
||||
Reference in New Issue
Block a user