Don't return from abort() until the current execution, if any, finished.

This commit is contained in:
Aleric Inglewood
2013-03-07 04:20:17 +01:00
parent 380eec10fb
commit 58c07f8054
2 changed files with 21 additions and 1 deletions

View File

@@ -459,7 +459,6 @@ void AIStateMachine::multiplex(event_type event)
mDebugLastState = state;
if (state == bs_multiplex)
{
llassert(!mDebugAborted);
// set_state is only called from multiplex_impl and therefore synced with mMultiplexMutex.
mDebugShouldRun |= mDebugSetStatePending;
// Should we run at all?
@@ -476,6 +475,15 @@ void AIStateMachine::multiplex(event_type event)
}
#endif
mRunMutex.lock();
// Now we are actually running a single state.
// If abort() was called at any moment before, we execute that state instead.
bool const late_abort = (state == bs_multiplex || state == bs_initialize) && sub_state_type_rat(mSubState)->aborted;
if (LL_UNLIKELY(late_abort))
{
// abort() was called from a child state machine, from another thread, while we were already scheduled to run normally from an engine.
state = bs_abort;
}
switch(state)
{
case bs_reset:
@@ -486,6 +494,7 @@ void AIStateMachine::multiplex(event_type event)
initialize_impl();
break;
case bs_multiplex:
llassert(!mDebugAborted);
multiplex_impl(run_state);
break;
case bs_abort:
@@ -499,6 +508,7 @@ void AIStateMachine::multiplex(event_type event)
callback();
break;
case bs_killed:
mRunMutex.unlock();
// bs_killed is handled when it is set. So, this must be a re-entry.
// We can only get here when being called by an engine that we were added to before we were killed.
// This should already be have been set to NULL to indicate that we want to be removed from that engine.
@@ -506,6 +516,7 @@ void AIStateMachine::multiplex(event_type event)
// Do not call unref() twice.
return;
}
mRunMutex.unlock();
}
{
@@ -1035,6 +1046,13 @@ void AIStateMachine::abort(void)
{
multiplex(insert_abort);
}
// Block until the current run finished.
if (!mRunMutex.tryLock())
{
llwarns << "AIStateMachine::abort() blocks because the statemachine is still executing code in another thread." << llendl;
mRunMutex.lock();
}
mRunMutex.unlock();
#ifdef SHOW_ASSERT
// When abort() returns, it may never run again.
mDebugAborted = true;

View File

@@ -156,6 +156,8 @@ class AIStateMachine : public LLThreadSafeRefCount
// Mutex protecting everything below and making sure only one thread runs the state machine at a time.
LLMutex mMultiplexMutex;
// Mutex that is locked while calling *_impl() functions and the call back.
LLMutex mRunMutex;
S64 mSleep; //!< Non-zero while the state machine is sleeping.