Libspinscale: Initial top-level SMO port to coroutine framework
We haven't ported everything. Just the top-level methods. We'll dig in to the leaf stuff later. Surprisingly, this all went without any real difficulties. Runs like a charm on first try.
This commit is contained in:
+77
-176
@@ -1,190 +1,92 @@
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <spinscale/asynchronousContinuation.h>
|
||||
#include <spinscale/asynchronousLoop.h>
|
||||
#include <spinscale/callback.h>
|
||||
#include <spinscale/callableTracer.h>
|
||||
#include <spinscale/component.h>
|
||||
#include <marionette/marionette.h>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <boost/asio/post.hpp>
|
||||
#include <componentThread.h>
|
||||
#include <deviceManager/deviceManager.h>
|
||||
#include <marionette/marionette.h>
|
||||
#include <marionette/marionetteThread.h>
|
||||
#include <mindManager/mindManager.h>
|
||||
#include <spinscale/componentThread.h>
|
||||
|
||||
namespace smo {
|
||||
namespace mrntt {
|
||||
|
||||
class MarionetteComponent::MrnttLifetimeMgmtOp
|
||||
: public sscl::PostedAsynchronousContinuation<mrnttLifetimeMgmtOpCbFn>
|
||||
namespace {
|
||||
|
||||
void assertMarionetteThread()
|
||||
{
|
||||
public:
|
||||
MrnttLifetimeMgmtOp(
|
||||
MarionetteComponent &parent,
|
||||
const std::shared_ptr<sscl::ComponentThread> &caller,
|
||||
sscl::Callback<mrnttLifetimeMgmtOpCbFn> callback)
|
||||
: sscl::PostedAsynchronousContinuation<mrnttLifetimeMgmtOpCbFn>(
|
||||
caller, callback),
|
||||
parent(parent)
|
||||
{}
|
||||
|
||||
private:
|
||||
MarionetteComponent &parent;
|
||||
|
||||
public:
|
||||
void initializeReq1_posted(
|
||||
[[maybe_unused]] std::shared_ptr<MrnttLifetimeMgmtOp> context
|
||||
)
|
||||
auto self = sscl::ComponentThread::getSelf();
|
||||
if (self->id != SmoThreadId::MRNTT)
|
||||
{
|
||||
auto self = sscl::ComponentThread::getSelf();
|
||||
if (self->id != smo::SmoThreadId::MRNTT)
|
||||
{
|
||||
throw std::runtime_error(std::string(__func__)
|
||||
+ ": Must be executed on Marionette thread");
|
||||
}
|
||||
|
||||
smo::mind::globalMind = std::make_shared<smo::Mind>();
|
||||
smo::mind::globalMind->initializeReq({context, std::bind(
|
||||
&MrnttLifetimeMgmtOp::initializeReq2,
|
||||
this, context, std::placeholders::_1)});
|
||||
}
|
||||
|
||||
void initializeReq2(
|
||||
std::shared_ptr<MrnttLifetimeMgmtOp> context,
|
||||
bool success
|
||||
)
|
||||
{
|
||||
if (!success)
|
||||
{
|
||||
std::cerr << __func__ << ": Failed to initialize globalMind"
|
||||
<< std::endl;
|
||||
context->callOriginalCb(false);
|
||||
return;
|
||||
}
|
||||
|
||||
smo::device::DeviceManager::getInstance().initializeDeviceReattacher();
|
||||
|
||||
// Call negtrinEventInd on the Director in the final callback
|
||||
smo::mind::globalMind->director.negtrinEventInd();
|
||||
|
||||
context->callOriginalCb(success);
|
||||
}
|
||||
|
||||
void finalizeReq1_posted(
|
||||
[[maybe_unused]] std::shared_ptr<MrnttLifetimeMgmtOp> context
|
||||
)
|
||||
{
|
||||
auto self = sscl::ComponentThread::getSelf();
|
||||
if (self->id != smo::SmoThreadId::MRNTT)
|
||||
{
|
||||
throw std::runtime_error(std::string(__func__)
|
||||
+ ": Must be executed on Marionette thread");
|
||||
}
|
||||
|
||||
smo::device::DeviceManager::getInstance().finalizeDeviceReattacher();
|
||||
|
||||
/** FIXME:
|
||||
* It may be necessary to add a delay here to ensure that all in-flight
|
||||
* timer timeouts have finished executing? Or some other mechanism.
|
||||
*
|
||||
* We need some way to ensure that in-flight timeouts don't get fired
|
||||
* during the finalize sequence. This is because they may depend on
|
||||
* state that is being finalized or has been finalized at the point
|
||||
* when they timeout.
|
||||
*
|
||||
* This seems to be actually happening with the delayed calls to
|
||||
* AttachDeviceReq::attachDeviceReq2() inside of livoxGen1.cpp.
|
||||
*
|
||||
* One tactic might be to shut down device reattacher before finalizing
|
||||
* and pause for a bit before continuing to shutdown other components.
|
||||
*/
|
||||
|
||||
smo::mind::globalMind->finalizeReq({context, std::bind(
|
||||
&MrnttLifetimeMgmtOp::finalizeReq2,
|
||||
this, context, std::placeholders::_1)});
|
||||
}
|
||||
|
||||
void finalizeReq2(
|
||||
std::shared_ptr<MrnttLifetimeMgmtOp> context,
|
||||
bool success
|
||||
)
|
||||
{
|
||||
if (!success)
|
||||
{
|
||||
std::cerr << __func__ << ": globalMind finalization failed"
|
||||
<< std::endl;
|
||||
context->callOriginalCb(false);
|
||||
return;
|
||||
}
|
||||
|
||||
context->callOriginalCb(success);
|
||||
}
|
||||
};
|
||||
|
||||
class MarionetteComponent::TerminationEvent
|
||||
: public sscl::PostedAsynchronousContinuation<mrnttLifetimeMgmtOpCbFn>
|
||||
{
|
||||
public:
|
||||
TerminationEvent(
|
||||
const std::shared_ptr<sscl::ComponentThread> &caller)
|
||||
: sscl::PostedAsynchronousContinuation<mrnttLifetimeMgmtOpCbFn>(
|
||||
caller, {nullptr, nullptr})
|
||||
{}
|
||||
|
||||
public:
|
||||
void exceptionInd1_posted(
|
||||
[[maybe_unused]] std::shared_ptr<TerminationEvent> context
|
||||
)
|
||||
{
|
||||
auto self = sscl::ComponentThread::getSelf();
|
||||
if (self->id != smo::SmoThreadId::MRNTT)
|
||||
{
|
||||
throw std::runtime_error(std::string(__func__)
|
||||
+ ": Must be executed on Marionette thread");
|
||||
}
|
||||
|
||||
smo::mrntt::mrntt.finalizeReq({nullptr, std::bind(
|
||||
&smo::mrntt::marionetteFinalizeReqCb,
|
||||
std::placeholders::_1)});
|
||||
}
|
||||
};
|
||||
|
||||
void MarionetteComponent::initializeReq(
|
||||
sscl::Callback<mrnttLifetimeMgmtOpCbFn> callback)
|
||||
{
|
||||
auto mrntt = sscl::ComponentThread::getSelf();
|
||||
|
||||
if (mrntt->id != smo::SmoThreadId::MRNTT)
|
||||
{
|
||||
throw std::runtime_error(std::string(__func__)
|
||||
throw std::runtime_error(
|
||||
std::string(__func__)
|
||||
+ ": Must be executed on Marionette thread");
|
||||
}
|
||||
|
||||
auto request = std::make_shared<MrnttLifetimeMgmtOp>(
|
||||
*this, mrntt, callback);
|
||||
|
||||
mrntt->getIoService().post(
|
||||
STC(std::bind(
|
||||
&MrnttLifetimeMgmtOp::initializeReq1_posted,
|
||||
request.get(), request)));
|
||||
}
|
||||
|
||||
void MarionetteComponent::finalizeReq(
|
||||
sscl::Callback<mrnttLifetimeMgmtOpCbFn> callback)
|
||||
{
|
||||
auto mrntt = sscl::ComponentThread::getSelf();
|
||||
} // namespace
|
||||
|
||||
if (mrntt->id != smo::SmoThreadId::MRNTT)
|
||||
void MarionetteComponent::holdInitializeCReq(
|
||||
std::function<void()> completion)
|
||||
{
|
||||
initializeCReqInvoker.emplace(initializeCReq(
|
||||
initializeLifetimeExceptionPtr, std::move(completion)));
|
||||
}
|
||||
|
||||
void MarionetteComponent::holdFinalizeCReq(
|
||||
std::function<void()> completion)
|
||||
{
|
||||
finalizeCReqInvoker.emplace(finalizeCReq(
|
||||
finalizeLifetimeExceptionPtr, std::move(completion)));
|
||||
}
|
||||
|
||||
MrnttNonViralPostingInvoker MarionetteComponent::initializeCReq(
|
||||
[[maybe_unused]] std::exception_ptr &exceptionPtr,
|
||||
[[maybe_unused]] std::function<void()> callback)
|
||||
{
|
||||
assertMarionetteThread();
|
||||
|
||||
smo::mind::globalMind = std::make_shared<smo::Mind>();
|
||||
|
||||
bool mindInitialized = co_await smo::mind::globalMind->initializeCReq();
|
||||
if (!mindInitialized)
|
||||
{
|
||||
throw std::runtime_error(std::string(__func__)
|
||||
+ ": Must be executed on Marionette thread");
|
||||
std::cerr << __func__ << ": Failed to initialize globalMind"
|
||||
<< std::endl;
|
||||
co_return;
|
||||
}
|
||||
|
||||
auto request = std::make_shared<MrnttLifetimeMgmtOp>(
|
||||
*this, mrntt, callback);
|
||||
smo::device::DeviceManager::getInstance().initializeDeviceReattacher();
|
||||
|
||||
mrntt->getIoService().post(
|
||||
STC(std::bind(
|
||||
&MrnttLifetimeMgmtOp::finalizeReq1_posted,
|
||||
request.get(), request)));
|
||||
// Call negtrinEventInd on the Director in the final callback
|
||||
smo::mind::globalMind->director.negtrinEventInd();
|
||||
|
||||
co_return;
|
||||
}
|
||||
|
||||
MrnttNonViralPostingInvoker MarionetteComponent::finalizeCReq(
|
||||
[[maybe_unused]] std::exception_ptr &exceptionPtr,
|
||||
[[maybe_unused]] std::function<void()> callback)
|
||||
{
|
||||
assertMarionetteThread();
|
||||
|
||||
smo::device::DeviceManager::getInstance().finalizeDeviceReattacher();
|
||||
|
||||
if (!smo::mind::globalMind)
|
||||
{
|
||||
co_return;
|
||||
}
|
||||
|
||||
bool mindFinalized = co_await smo::mind::globalMind->finalizeCReq();
|
||||
if (!mindFinalized)
|
||||
{
|
||||
std::cerr << __func__ << ": globalMind finalization failed"
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
co_return;
|
||||
}
|
||||
|
||||
void MarionetteComponent::handleLoopExceptionHook()
|
||||
@@ -195,16 +97,15 @@ void MarionetteComponent::handleLoopExceptionHook()
|
||||
|
||||
void MarionetteComponent::exceptionInd()
|
||||
{
|
||||
auto faultyThread = sscl::ComponentThread::getSelf();
|
||||
auto mrntt = sscl::ComponentThread::getPptr();
|
||||
auto puppeteer = sscl::ComponentThread::getPptr();
|
||||
|
||||
auto request = std::make_shared<TerminationEvent>(
|
||||
faultyThread);
|
||||
|
||||
mrntt->getIoService().post(
|
||||
STC(std::bind(
|
||||
&TerminationEvent::exceptionInd1_posted,
|
||||
request.get(), request)));
|
||||
boost::asio::post(
|
||||
puppeteer->getIoService(),
|
||||
[]
|
||||
{
|
||||
mrntt.holdFinalizeCReq(
|
||||
[]() { marionetteFinalizeReqCb(true); });
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace mrntt
|
||||
|
||||
Reference in New Issue
Block a user