Make AIRegisteredStateMachines more robust.

Now that a call to cont() can schedule a run of the statemachine, we
need this change to make it robust (the comment that cont() does never
access mRegisteredStateMachines no longer holds).
This commit is contained in:
Aleric Inglewood
2013-03-23 22:17:27 +01:00
parent 712c46a74e
commit d526d388ef

View File

@@ -36,26 +36,52 @@
// Additional information stored per registered statemachine in AIRegisteredStateMachines std::map. // Additional information stored per registered statemachine in AIRegisteredStateMachines std::map.
struct AIRSData { struct AIRSData {
bool mOneShot; bool mOneShot;
AIRSData(void) { } bool mRunning;
AIRSData(bool one_shot) : mOneShot(one_shot) { } AIRSData(void) : mRunning(false) { }
AIRSData(bool one_shot) : mOneShot(one_shot), mRunning(false) { }
void operator=(bool one_shot) { mOneShot = one_shot; }
}; };
// A list of all statemachines registered for a particular event, and an API to work on it. // A list of all statemachines registered for a particular event, and an API to work on it.
struct AIRegisteredStateMachines { struct AIRegisteredStateMachines {
typedef std::map<AIStateMachine*, AIRSData> rsm_type; typedef std::map<AIStateMachine*, AIRSData> rsm_type;
rsm_type mRegisteredStateMachines; rsm_type mRegisteredStateMachines;
void Register(AIStateMachine* statemachine, bool one_shot) { mRegisteredStateMachines[statemachine] = one_shot; } void Register(AIStateMachine* statemachine, bool one_shot);
void Unregister(AIStateMachine* statemachine) { mRegisteredStateMachines.erase(statemachine); } void Unregister(AIStateMachine* statemachine);
void trigger(void); void trigger(void);
}; };
// Inline this, because it's only called from one place. // Inline these, because they are only called from one place.
inline void AIRegisteredStateMachines::Register(AIStateMachine* statemachine, bool one_shot)
{
mRegisteredStateMachines[statemachine] = one_shot;
}
inline void AIRegisteredStateMachines::Unregister(AIStateMachine* statemachine)
{
rsm_type::iterator sm = mRegisteredStateMachines.find(statemachine);
if (sm != mRegisteredStateMachines.end())
{
if (!sm->second.mRunning)
{
mRegisteredStateMachines.erase(sm);
}
else
{
sm->second.mOneShot = true; // Delay the erase till we return to trigger().
}
}
}
inline void AIRegisteredStateMachines::trigger(void) inline void AIRegisteredStateMachines::trigger(void)
{ {
rsm_type::iterator sm = mRegisteredStateMachines.begin(); rsm_type::iterator sm = mRegisteredStateMachines.begin();
while(sm != mRegisteredStateMachines.end()) while(sm != mRegisteredStateMachines.end())
{ {
sm->first->cont(); // This is safe, cont() does never access mRegisteredStateMachines. sm->second.mRunning = true;
sm->first->cont(); // This is safe, cont() doesn't invalidates sm while mRunning is set.
sm->second.mRunning = false;
if (sm->second.mOneShot) if (sm->second.mOneShot)
mRegisteredStateMachines.erase(sm++); mRegisteredStateMachines.erase(sm++);
else else