#ifndef FACT_StateMachineAsio #define FACT_StateMachineAsio #include #include template class StateMachineAsio : public T, public boost::asio::io_service, public boost::asio::io_service::work { boost::asio::deadline_timer fTrigger; void HandleTrigger(const boost::system::error_code &error) { // 125: Operation canceled (bs::error_code(125, bs::system_category)) if (error && error!=boost::asio::error::basic_errors::operation_aborted) return; fTrigger.expires_from_now(boost::posix_time::microseconds(10000)); fTrigger.async_wait(boost::bind(&StateMachineAsio::HandleTrigger, this, boost::asio::placeholders::error)); if (!HandleNewState(Execute(), 0, "by HandleTrigger()")) Stop(-1); } void Handler() { const auto ptr = T::PopEvent(); if (!T::HandleEvent(*ptr)) Stop(-1); } void PushEvent(Event *cmd) { T::PushEvent(cmd); post(boost::bind(&StateMachineAsio::Handler, this)); } int Execute()=0; int Run(bool) { fTrigger.expires_from_now(boost::posix_time::microseconds(0)); fTrigger.async_wait(boost::bind(&StateMachineAsio::HandleTrigger, this, boost::asio::placeholders::error)); T::SetCurrentState(StateMachineImp::kSM_Ready, "by Run()"); T::fRunning = true; while (run_one()) { if (!HandleNewState(Execute(), 0, "by Run()")) Stop(-1); } reset(); T::fRunning = false; if (T::fExitRequested==-1) { T::Fatal("Fatal Error occured... shutting down."); return -1; } T::SetCurrentState(StateMachineImp::kSM_NotReady, "due to return from Run()."); const int exitcode = T::fExitRequested-1; T::fExitRequested = 0; return exitcode; } public: StateMachineAsio(std::ostream &out, const std::string &server) : T(out, server), boost::asio::io_service::work(static_cast(*this)), fTrigger(static_cast(*this)) { // ba::io_service::work is a kind of keep_alive for the loop. // It prevents the io_service to go to stopped state, which // would prevent any consecutive calls to run() // or poll() to do nothing. reset() could also revoke to the // previous state but this might introduce some overhead of // deletion and creation of threads and more. } void Stop(int code=0) { T::Stop(code); stop(); } }; #endif