void AIStateMachine::yield_frame(unsigned int frames) { DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::yield_frame(" << frames << ") [" << (void*)this << "]"); mSleep = -(S64)frames; // Sleeping is always done from the main thread. yield(&gMainThreadEngine); }
void AIStateMachine::yield_ms(unsigned int ms) { DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::yield_ms(" << ms << ") [" << (void*)this << "]"); mSleep = get_clock_count() + calc_clock_frequency() * ms / 1000; // Sleeping is always done from the main thread. yield(&gMainThreadEngine); }
// This function is very much like cont(), except that it has no effect when we are not in a blocked state. // Returns true if the state machine was unblocked, false if it was already unblocked. bool AIStateMachine::signalled(void) { DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::signalled() [" << (void*)this << "]"); { sub_state_type_wat sub_state_w(mSubState); // Test if we are blocked or not. if (sub_state_w->blocked) { Dout(dc::statemachine(mSMDebug), "Removing statemachine from condition " << (void*)sub_state_w->blocked); sub_state_w->blocked->remove(this); sub_state_w->blocked = NULL; } else { return false; } // Void last call to wait(). sub_state_w->idle = false; // Mark that a re-entry of multiplex() is necessary. sub_state_w->need_run = true; #ifdef SHOW_ASSERT // From this moment. mDebugContPending = true; #endif } if (!mMultiplexMutex.isSelfLocked()) { multiplex(schedule_run); } return true; }
void AIStateMachine::run(callback_type::signal_type::slot_type const& slot, AIEngine* default_engine) { DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::run(<slot>, default_engine = " << default_engine->name() << ") [" << (void*)this << "]"); #ifdef SHOW_ASSERT { multiplex_state_type_rat state_r(mState); // Can only be run when in one of these states. llassert(state_r->base_state == bs_reset || state_r->base_state == bs_finish || state_r->base_state == bs_callback); // Must be the first time we're being run, or we must be called from finish_impl or a callback function. llassert(!(state_r->base_state == bs_reset && (mParent || mCallback))); } #endif // Store the requested default engine. mDefaultEngine = default_engine; // Initialize sleep timer. mSleep = 0; // Clean up any old callbacks. mParent = NULL; if (mCallback) { delete mCallback; mCallback = NULL; } // Create new call back. mCallback = new callback_type(slot); // Start from the beginning. reset(); }
void AIStateMachine::multiplex(U64 current_time) { // Return immediately when this state machine is sleeping. // A negative value of mSleep means we're counting frames, // a positive value means we're waiting till a certain // amount of time has passed. if (mSleep != 0) { if (mSleep < 0) { if (++mSleep) return; } else { if (current_time < (U64)mSleep) return; mSleep = 0; } } DoutEntering(dc::statemachine, "AIStateMachine::multiplex() [" << (void*)this << "] [with state: " << state_str(mState == bs_run ? mRunState : mState) << "]"); llassert(mState == bs_initialize || mState == bs_run); // Real state machine starts here. if (mState == bs_initialize) { mAborted = false; mState = bs_run; initialize_impl(); if (mAborted || mState != bs_run) return; } multiplex_impl(); }
// This function is very much like idle(). void AIStateMachine::wait(AIConditionBase& condition) { DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::wait(" << (void*)&condition << ") [" << (void*)this << "]"); #ifdef SHOW_ASSERT { multiplex_state_type_rat state_r(mState); // wait() may only be called multiplex_impl(). llassert(state_r->base_state == bs_multiplex); // May only be called by the thread that is holding mMultiplexMutex. llassert(mThreadId.equals_current_thread()); } // wait() following set_state() cancels the reason to run because of the call to set_state. mDebugSetStatePending = false; #endif sub_state_type_wat sub_state_w(mSubState); // As wait() may only be called from within the state machine, it should never happen that the state machine is already idle. llassert(!sub_state_w->idle); // Ignore call to wait() when advance_state() was called since last call to set_state(). if (sub_state_w->skip_idle) { Dout(dc::statemachine(mSMDebug), "Ignored, because skip_idle is true (advance_state() was called last)."); return; } // Register ourselves with the condition object. condition.wait(this); // Mark that we are idle. sub_state_w->idle = true; // Mark that we are waiting for a condition. sub_state_w->blocked = &condition; // Not sleeping (anymore). mSleep = 0; }
void AIStateMachine::cont(void) { DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::cont() [" << (void*)this << "]"); { sub_state_type_wat sub_state_w(mSubState); // Void last call to idle(), if any. sub_state_w->idle = false; // No longer say we woke up when signalled() is called. if (sub_state_w->blocked) { Dout(dc::statemachine(mSMDebug), "Removing statemachine from condition " << (void*)sub_state_w->blocked); sub_state_w->blocked->remove(this); sub_state_w->blocked = NULL; } // Mark that a re-entry of multiplex() is necessary. sub_state_w->need_run = true; #ifdef SHOW_ASSERT // From this moment. mDebugContPending = true; #endif } if (!mMultiplexMutex.isSelfLocked()) { multiplex(schedule_run); } }
void AIStateMachine::idle(void) { DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::idle() [" << (void*)this << "]"); #ifdef SHOW_ASSERT { multiplex_state_type_rat state_r(mState); // idle() may only be called from initialize_impl() or multiplex_impl(). llassert(state_r->base_state == bs_multiplex || state_r->base_state == bs_initialize); // May only be called by the thread that is holding mMultiplexMutex. llassert(mThreadId.equals_current_thread()); } // idle() following set_state() cancels the reason to run because of the call to set_state. mDebugSetStatePending = false; #endif sub_state_type_wat sub_state_w(mSubState); // As idle may only be called from within the state machine, it should never happen that the state machine is already idle. llassert(!sub_state_w->idle); // Ignore call to idle() when advance_state() was called since last call to set_state(). if (sub_state_w->skip_idle) { Dout(dc::statemachine(mSMDebug), "Ignored, because skip_idle is true (advance_state() was called last)."); return; } // Mark that we are idle. sub_state_w->idle = true; // Not sleeping (anymore). mSleep = 0; }
void AIStateMachine::set_state(state_type new_state) { DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::set_state(" << state_str_impl(new_state) << ") [" << (void*)this << "]"); #ifdef SHOW_ASSERT { multiplex_state_type_rat state_r(mState); // set_state() may only be called from initialize_impl() or multiplex_impl(). llassert(state_r->base_state == bs_initialize || state_r->base_state == bs_multiplex); // May only be called by the thread that is holding mMultiplexMutex. If this fails, you probably called set_state() by accident instead of advance_state(). llassert(mThreadId.equals_current_thread()); } #endif sub_state_type_wat sub_state_w(mSubState); // It should never happen that set_state() is called while we're blocked. llassert(!sub_state_w->blocked); // Force current state to the requested state. sub_state_w->run_state = new_state; // Void last call to advance_state. sub_state_w->advance_state = 0; // Void last call to idle(), if any. sub_state_w->idle = false; // Honor a subsequent call to idle(). sub_state_w->skip_idle = false; #ifdef SHOW_ASSERT // We should run. This can only be cancelled by a call to idle(). mDebugSetStatePending = true; #endif }
void AIStateMachine::run(callback_type::signal_type::slot_type const& slot) { DoutEntering(dc::statemachine, "AIStateMachine::run(<slot>) [" << (void*)this << "]"); // Must be the first time we're being run, or we must be called from a callback function. llassert(!mParent || mState == bs_callback); llassert(!mCallback || mState == bs_callback); // Can only be run when in this state. llassert(mState == bs_initialize || mState == bs_callback); // Clean up any old callbacks. mParent = NULL; if (mCallback) { delete mCallback; mCallback = NULL; } mCallback = new callback_type(slot); // Mark that run() has been called, in case we're being called from a callback function. mState = bs_initialize; // Set mIdle to false and add statemachine to continued_statemachines. mSetStateLock.lock(); locked_cont(); }
// This is called when the server expired and we're the only client on it. /*virtual*/ void deregistered(void) { #ifdef DEBUG_SYNCOUTPUT DoutEntering(dc::notice, "TestsuiteClient<" << synckeytype << ">::deregistered(), with this = " << this); #endif mRequestedRegistered = false; mRequestedReady = 0; mActualReady1 = false; this->mReadyEvents = 0; }
void AIStateMachine::advance_state(state_type new_state) { DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::advance_state(" << state_str_impl(new_state) << ") [" << (void*)this << "]"); { sub_state_type_wat sub_state_w(mSubState); // Ignore call to advance_state when the currently queued state is already greater or equal to the requested state. if (sub_state_w->advance_state >= new_state) { Dout(dc::statemachine(mSMDebug), "Ignored, because " << state_str_impl(sub_state_w->advance_state) << " >= " << state_str_impl(new_state) << "."); return; } // Ignore call to advance_state when the current state is greater than the requested state: the new state would be // ignored in begin_loop(), as is already remarked there: an advanced state that is not honored is not a reason to run. // This call might as well not have happened. Not returning here is a bug because that is effectively a cont(), while // the state change is and should be being ignored: the statemachine would start running it's current state (again). if (sub_state_w->run_state > new_state) { Dout(dc::statemachine(mSMDebug), "Ignored, because " << state_str_impl(sub_state_w->run_state) << " > " << state_str_impl(new_state) << " (current state)."); return; } // Increment state. sub_state_w->advance_state = new_state; // Void last call to idle(), if any. sub_state_w->idle = false; // Ignore a call to idle if it occurs before we leave multiplex_impl(). sub_state_w->skip_idle = true; // No longer say we woke up when signalled() is called. if (sub_state_w->blocked) { Dout(dc::statemachine(mSMDebug), "Removing statemachine from condition " << (void*)sub_state_w->blocked); sub_state_w->blocked->remove(this); sub_state_w->blocked = NULL; } // Mark that a re-entry of multiplex() is necessary. sub_state_w->need_run = true; #ifdef SHOW_ASSERT // From this moment on. mDebugAdvanceStatePending = true; // If the new state is equal to the current state, then this should be considered to be a cont() // because also equal states are ignored in begin_loop(). However, unlike a cont() we ignore a call // to idle() when the statemachine is already running in this state (because that is a race condition // and ignoring the idle() is the most logical thing to do then). Hence we treated this as a full // fletched advance_state but need to tell the debug code that it's really also a cont(). if (sub_state_w->run_state == new_state) { // From this moment. mDebugContPending = true; } #endif } if (!mMultiplexMutex.isSelfLocked()) { multiplex(schedule_run); } }
void AIStateMachine::idle(void) { DoutEntering(dc::statemachine, "AIStateMachine::idle() [" << (void*)this << "]"); llassert(is_main_thread()); llassert(!mIdle); mIdle = true; mSleep = 0; #ifdef SHOW_ASSERT mCalledThreadUnsafeIdle = true; #endif }
void AIEngine::flush(void) { engine_state_type_wat engine_state_w(mEngineState); DoutEntering(dc::statemachine, "AIEngine::flush [" << mName << "]: calling force_killed() on " << engine_state_w->list.size() << " state machines."); for (queued_type::iterator iter = engine_state_w->list.begin(); iter != engine_state_w->list.end(); ++iter) { // To avoid an assertion in ~AIStateMachine. iter->statemachine().force_killed(); } engine_state_w->list.clear(); }
void AIStateMachine::yield(void) { DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::yield() [" << (void*)this << "]"); multiplex_state_type_rat state_r(mState); // yield() may only be called from multiplex_impl(). llassert(state_r->base_state == bs_multiplex); // May only be called by the thread that is holding mMultiplexMutex. llassert(mThreadId.equals_current_thread()); // Set mYieldEngine to the best non-NUL value. mYieldEngine = state_r->current_engine ? state_r->current_engine : (mDefaultEngine ? mDefaultEngine : &gStateMachineThreadEngine); }
void JackOutput::create_allocated_buffer() { DoutEntering(dc::notice, "JackOutput::create_allocated_buffer() with this = " << (void*)this << " [" << m_name << "]."); // We should not try to allocate a buffer when we're already providing one. ASSERT(!has_provided_output_buffer(type())); // Makes no sense to allocate a buffer when we already have one. ASSERT(!m_allocated); m_chunk = static_cast<jack_default_audio_sample_t*>(JackChunkAllocator::instance().allocate()); m_chunk_size = JackChunkAllocator::instance().chunk_size(); m_allocated = true; }
void JackOutput::release_allocated_buffer(void) { DoutEntering(dc::notice, "JackOutput::release_allocated_buffer() with this = " << (void*)this << " [" << m_name << "]."); if (m_allocated) { ASSERT(m_chunk); JackChunkAllocator::instance().release(m_chunk); m_chunk = NULL; m_chunk_size = 0; m_allocated = false; } }
void AICurlEasyRequestStateMachine::abort_impl(void) { DoutEntering(dc::curl, "AICurlEasyRequestStateMachine::abort_impl() [" << (void*)this << "] [" << (void*)mCurlEasyRequest.get() << "]"); // Revert call to addRequest() if that was already called (and the request wasn't removed again already). if (mAdded) { // Note that it's safe to call this even if the curl thread already removed it, or will remove it // after we called this, before processing the remove command; only the curl thread calls // MultiHandle::remove_easy_request, which is a no-op when called twice for the same easy request. mAdded = false; mCurlEasyRequest.removeRequest(); } }
void AIStateMachine::kill(void) { DoutEntering(dc::statemachine, "AIStateMachine::kill() [" << (void*)this << "]"); // Should only be called from finish() (or when not running (bs_initialize)). // However, also allow multiple calls to kill() on a row (bs_killed) (which effectively don't do anything). llassert(mIdle && (mState == bs_callback || mState == bs_finish || mState == bs_initialize || mState == bs_killed)); base_state_type prev_state = mState; mState = bs_killed; if (prev_state == bs_initialize && mActive == as_idle) { // We're not running (ie being deleted by a parent statemachine), delete it immediately. delete this; } }
void AIStateMachine::run(AIStateMachine* parent, state_type new_parent_state, bool abort_parent, bool on_abort_signal_parent, AIEngine* default_engine) { DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::run(" << (void*)parent << ", " << (parent ? parent->state_str_impl(new_parent_state) : "NA") << ", abort_parent = " << (abort_parent ? "true" : "false") << ", on_abort_signal_parent = " << (on_abort_signal_parent ? "true" : "false") << ", default_engine = " << (default_engine ? default_engine->name() : "NULL") << ") [" << (void*)this << "]"); #ifdef SHOW_ASSERT { multiplex_state_type_rat state_r(mState); // Can only be run when in one of these states. llassert(state_r->base_state == bs_reset || state_r->base_state == bs_finish || state_r->base_state == bs_callback); // Must be the first time we're being run, or we must be called from finish_impl or a callback function. llassert(!(state_r->base_state == bs_reset && (mParent || mCallback))); } #endif // Store the requested default engine. mDefaultEngine = default_engine; // Initialize sleep timer. mSleep = 0; // Allow NULL to be passed as parent to signal that we want to reuse the old one. if (parent) { mParent = parent; // In that case remove any old callback! if (mCallback) { delete mCallback; mCallback = NULL; } mNewParentState = new_parent_state; mAbortParent = abort_parent; mOnAbortSignalParent = on_abort_signal_parent; } // If abort_parent is requested then a parent must be provided. llassert(!abort_parent || mParent); // If a parent is provided, it must be running. llassert(!mParent || mParent->running()); // Start from the beginning. reset(); }
void AIStateMachine::yield(AIEngine* engine) { llassert(engine); DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::yield(" << engine->name() << ") [" << (void*)this << "]"); #ifdef SHOW_ASSERT { multiplex_state_type_rat state_r(mState); // yield() may only be called from multiplex_impl(). llassert(state_r->base_state == bs_multiplex); // May only be called by the thread that is holding mMultiplexMutex. llassert(mThreadId.equals_current_thread()); } #endif mYieldEngine = engine; }
void AIStateMachine::idle(state_type current_run_state) { DoutEntering(dc::statemachine, "AIStateMachine::idle(" << state_str(current_run_state) << ") [" << (void*)this << "]"); llassert(is_main_thread()); llassert(!mIdle); mSetStateLock.lock(); // Only go idle if the run state is (still) what we expect it to be. // Otherwise assume that another thread called set_state() and continue running. if (current_run_state == mRunState) { mIdle = true; mSleep = 0; } mSetStateLock.unlock(); }
void AIStateMachine::kill(void) { DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::kill() [" << (void*)this << "]"); #ifdef SHOW_ASSERT { multiplex_state_type_rat state_r(mState); // kill() may only be called from the call back function. llassert(state_r->base_state == bs_callback); // May only be called by the thread that is holding mMultiplexMutex. llassert(mThreadId.equals_current_thread()); } #endif sub_state_type_wat sub_state_w(mSubState); // Void last call to run() (ie from finish_impl()), if any. sub_state_w->reset = false; }
// static void AIStateMachine::flush(void) { DoutEntering(dc::curl, "AIStateMachine::flush(void)"); { 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) { AIStateMachine& statemachine(iter->statemachine()); if (statemachine.abortable()) { // We can't safely call abort() here for non-running (run() was called, but they weren't initialized yet) statemachines, // because that might call kill() which in some cases is undesirable (ie, when it is owned by a partent that will // also call abort() on it when it is aborted itself). if (statemachine.running()) statemachine.abort(); else statemachine.idle(); // Stop the statemachine from starting, in the next loop with batch == 0. } } for (int batch = 0;; ++batch) { // Run mainloop until all state machines are idle (batch == 0) or deleted (batch == 1). for(;;) { { AIReadAccess<csme_type> csme_r(sContinuedStateMachinesAndMainloopEnabled); if (!csme_r->mainloop_enabled) break; } mainloop(); } if (batch == 1) break; { AIReadAccess<csme_type> csme_r(sContinuedStateMachinesAndMainloopEnabled); add_continued_statemachines(csme_r); } } // At this point all statemachines should be idle. AIReadAccess<csme_type> csme_r(sContinuedStateMachinesAndMainloopEnabled); llinfos << "Current number of continued statemachines: " << csme_r->continued_statemachines.size() << llendl; llinfos << "Current number of active statemachines: " << active_statemachines.size() << llendl; llassert(csme_r->continued_statemachines.empty() && active_statemachines.empty()); }
void AICurlEasyRequestStateMachine::finish_impl(void) { DoutEntering(dc::curl, "AICurlEasyRequestStateMachine::finish_impl() [" << (void*)this << "] [" << (void*)mCurlEasyRequest.get() << "]"); // Revoke callbacks. { AICurlEasyRequest_wat curl_easy_request_w(*mCurlEasyRequest); curl_easy_request_w->send_buffer_events_to(NULL); curl_easy_request_w->send_handle_events_to(NULL); curl_easy_request_w->revokeCallbacks(); } if (mTimer) { // Stop the timer, if it's still running. if (!mHandled) mTimer->abort(); } }
void AIStateMachine::finish(void) { DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::finish() [" << (void*)this << "]"); #ifdef SHOW_ASSERT { multiplex_state_type_rat state_r(mState); // finish() may only be called from multiplex_impl(). llassert(state_r->base_state == bs_multiplex); // May only be called by the thread that is holding mMultiplexMutex. llassert(mThreadId.equals_current_thread()); } #endif sub_state_type_wat sub_state_w(mSubState); // finish() should not be called when idle. llassert(!sub_state_w->idle); // Mark that we are finished. sub_state_w->finished = true; }
// About thread safeness: // // The main thread initializes a statemachine and calls run, so a statemachine // runs in the main thread. However, it is allowed that a state calls idle(current_state) // and then allows one or more other threads to call cont() upon some // event (only once, of course, as idle() has to be called before cont() // can be called again-- and a non-main thread is not allowed to call idle()). // Instead of cont() one may also call set_state(). // Of course, this may give rise to a race condition; if that happens then // the thread that calls cont() (set_state()) first is serviced, and the other // thread(s) are ignored, as if they never called cont(). void AIStateMachine::locked_cont(void) { DoutEntering(dc::statemachine, "AIStateMachine::locked_cont() [" << (void*)this << "]"); llassert(mIdle); // Atomic test mActive and change mIdle. mIdleActive.lock(); #ifdef SHOW_ASSERT mContThread.reset(); #endif mIdle = false; bool not_active = mActive == as_idle; mIdleActive.unlock(); // mActive is only changed in AIStateMachine::mainloop, by the main-thread, and // here, possibly by any thread. However, after setting mIdle to false above, it // is impossible for any thread to come here, until after the main-thread called // idle(). So, if this is the main thread then that certainly isn't going to // happen until we left this function, while if this is another thread and the // state machine is already running in the main thread then not_active is false // and we're already at the end of this function. // 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 // 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<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"); csme_w->continued_statemachines.push_back(this); if (!csme_w->mainloop_enabled) { 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. } }
void AIStateMachine::abort(void) { DoutEntering(dc::statemachine, "AIStateMachine::abort() [" << (void*)this << "]"); // It's possible that abort() is called before calling AIStateMachine::multiplex. // In that case the statemachine wasn't initialized yet and we should just kill() it. if (LL_UNLIKELY(mState == bs_initialize)) { // It's ok to use the thread-unsafe idle() here, because if the statemachine // wasn't started yet, then other threads won't call set_state() on it. if (!mIdle) idle(); // run() calls locked_cont() after which the top of the mainloop adds this // state machine to active_statemachines. Therefore, if the following fails // then either the same statemachine called run() immediately followed by abort(), // which is not allowed; or there were two active statemachines running, // the first created a new statemachine and called run() on it, and then // the other (before reaching the top of the mainloop) called abort() on // that freshly created statemachine. Obviously, this is highly unlikely, // but if that is the case then here we bump the statemachine into // continued_statemachines to prevent kill() to delete this statemachine: // the caller of abort() does not expect that. if (LL_UNLIKELY(mActive == as_idle)) { mSetStateLock.lock(); locked_cont(); idle(); } kill(); } else { llassert(mState == bs_run); mSetStateLock.lock(); mState = bs_abort; // Causes additional calls to set_state to be ignored. mSetStateLock.unlock(); abort_impl(); mAborted = true; finish(); } }
AIStateMachine::state_type AIStateMachine::begin_loop(base_state_type base_state) { DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::begin_loop(" << state_str(base_state) << ") [" << (void*)this << "]"); sub_state_type_wat sub_state_w(mSubState); // Honor a subsequent call to idle() (only necessary in bs_multiplex, but it doesn't hurt to reset this flag in other states too). sub_state_w->skip_idle = false; // Mark that we're about to honor all previous run requests. sub_state_w->need_run = false; // Honor previous calls to advance_state() (once run_state is initialized). if (base_state == bs_multiplex && sub_state_w->advance_state > sub_state_w->run_state) { Dout(dc::statemachine(mSMDebug), "Copying advance_state to run_state, because it is larger [" << state_str_impl(sub_state_w->advance_state) << " > " << state_str_impl(sub_state_w->run_state) << "]"); sub_state_w->run_state = sub_state_w->advance_state; } #ifdef SHOW_ASSERT else { // If advance_state wasn't honored then it isn't a reason to run. // We're running anyway, but that should be because set_state() was called. mDebugAdvanceStatePending = false; } #endif sub_state_w->advance_state = 0; #ifdef SHOW_ASSERT // Mark that we're running the loop. mThreadId.reset(); // This point marks handling cont(). mDebugShouldRun |= mDebugContPending; mDebugContPending = false; // This point also marks handling advance_state(). mDebugShouldRun |= mDebugAdvanceStatePending; mDebugAdvanceStatePending = false; #endif // Make a copy of the state that we're about to run. return sub_state_w->run_state; }
void AIStateMachine::callback(void) { DoutEntering(dc::statemachine(mSMDebug), "AIStateMachine::callback() [" << (void*)this << "]"); bool aborted = sub_state_type_rat(mSubState)->aborted; if (mParent) { // It is possible that the parent is not running when the parent is in fact aborting and called // abort on this object from it's abort_impl function. It that case we don't want to recursively // call abort again (or change it's state). if (mParent->running()) { if (aborted && mAbortParent) { mParent->abort(); mParent = NULL; } else if (!aborted || mOnAbortSignalParent) { mParent->advance_state(mNewParentState); } } } if (mCallback) { mCallback->callback(!aborted); if (multiplex_state_type_rat(mState)->base_state != bs_reset) { delete mCallback; mCallback = NULL; mParent = NULL; } } else { // Not restarted by callback. Allow run() to be called later on. mParent = NULL; } }