From 516f5a40d0c2810cc66655fec5c07443d841f665 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Wed, 25 Jul 2012 21:24:40 +0200 Subject: [PATCH] Change mainloop to no longer use gIdleCallbacks --- indra/aistatemachine/aistatemachine.cpp | 59 +++++++++++-------------- indra/aistatemachine/aistatemachine.h | 27 ++++++++++- indra/llcommon/aithreadsafe.h | 6 +-- indra/llcrashlogger/llcrashlogger.cpp | 1 + indra/newview/llappviewer.cpp | 11 +++++ 5 files changed, 66 insertions(+), 38 deletions(-) diff --git a/indra/aistatemachine/aistatemachine.cpp b/indra/aistatemachine/aistatemachine.cpp index 71a8ac47f..622eeb7f5 100644 --- a/indra/aistatemachine/aistatemachine.cpp +++ b/indra/aistatemachine/aistatemachine.cpp @@ -32,7 +32,6 @@ #include -#include "llcallbacklist.h" #include "llcontrol.h" #include "llfasttimer.h" #include "aithreadsafe.h" @@ -66,17 +65,11 @@ namespace { typedef std::vector active_statemachines_type; active_statemachines_type active_statemachines; - typedef std::vector continued_statemachines_type; - struct cscm_type - { - continued_statemachines_type continued_statemachines; - bool calling_mainloop; - }; - AIThreadSafeDC continued_statemachines_and_calling_mainloop; } // static AIThreadSafeSimpleDC AIStateMachine::sMaxCount; +AIThreadSafeDC 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_w(continued_statemachines_and_calling_mainloop); + AIWriteAccess 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_r) { - AIReadAccess 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_r)->continued_statemachines.clear(); + AIWriteAccess(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_r(continued_statemachines_and_calling_mainloop); - if (cscm_r->continued_statemachines.empty() && cscm_r->calling_mainloop) + AIReadAccess csme_r(sContinuedStateMachinesAndMainloopEnabled, true); + if (csme_r->continued_statemachines.empty() && csme_r->mainloop_enabled) { - Dout(dc::statemachine, "Removing AIStateMachine::mainloop from gIdleCallbacks"); - AIWriteAccess(cscm_r)->calling_mainloop = false; - gIdleCallbacks.deleteFunction(&AIStateMachine::mainloop); + Dout(dc::statemachine, "Deactivating AIStateMachine::mainloop: no active state machines left."); + AIWriteAccess(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_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_r(continued_statemachines_and_calling_mainloop); - if (!cscm_r->calling_mainloop) + AIReadAccess csme_r(sContinuedStateMachinesAndMainloopEnabled); + if (!csme_r->mainloop_enabled) break; } - mainloop(NULL); + mainloop(); } if (batch == 1) break; - add_continued_statemachines(); + { + AIReadAccess 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) { diff --git a/indra/aistatemachine/aistatemachine.h b/indra/aistatemachine/aistatemachine.h index 13da6fd3d..abdd46e31 100644 --- a/indra/aistatemachine/aistatemachine.h +++ b/indra/aistatemachine/aistatemachine.h @@ -192,6 +192,15 @@ class AIStateMachine { as_active // State machine is on active_statemachines list. }; + //! Type of continued_statemachines. + typedef std::vector 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 sMaxCount; //!< Number of cpu clocks below which we start a new state machine within the same frame. + static AIThreadSafeDC 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_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_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); diff --git a/indra/llcommon/aithreadsafe.h b/indra/llcommon/aithreadsafe.h index b7d0045cb..df4de5ead 100644 --- a/indra/llcommon/aithreadsafe.h +++ b/indra/llcommon/aithreadsafe.h @@ -329,14 +329,14 @@ struct AIReadAccessConst }; //! Construct a AIReadAccessConst from a constant AIThreadSafe. - AIReadAccessConst(AIThreadSafe const& wrapper) + AIReadAccessConst(AIThreadSafe const& wrapper, bool high_priority = false) : mWrapper(const_cast&>(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 using AIReadAccessConst::readlocked; //! Construct a AIReadAccess from a non-constant AIThreadSafe. - AIReadAccess(AIThreadSafe& wrapper) : AIReadAccessConst(wrapper, readlocked) { this->mWrapper.mRWLock.rdlock(); } + AIReadAccess(AIThreadSafe& wrapper, bool high_priority = false) : AIReadAccessConst(wrapper, readlocked) { this->mWrapper.mRWLock.rdlock(high_priority); } protected: //! Constructor used by AIWriteAccess. diff --git a/indra/llcrashlogger/llcrashlogger.cpp b/indra/llcrashlogger/llcrashlogger.cpp index c42697ad9..030128b76 100644 --- a/indra/llcrashlogger/llcrashlogger.cpp +++ b/indra/llcrashlogger/llcrashlogger.cpp @@ -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() diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 96b6166e4..f0985f2b5 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -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();