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:
@@ -7,6 +7,7 @@ add_library(smocore STATIC
|
||||
mind.cpp
|
||||
mindComponent.cpp
|
||||
componentThread.cpp
|
||||
componentThreadTags.cpp
|
||||
opts.cpp
|
||||
|
||||
# Body
|
||||
|
||||
+72
-163
@@ -1,15 +1,12 @@
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <opts.h>
|
||||
#include <spinscale/asynchronousContinuation.h>
|
||||
#include <spinscale/asynchronousLoop.h>
|
||||
#include <spinscale/callback.h>
|
||||
#include <spinscale/callableTracer.h>
|
||||
#include <spinscale/puppetApplication.h>
|
||||
#include <body/body.h>
|
||||
#include <body/bodyThread.h>
|
||||
#include <componentThread.h>
|
||||
#include <deviceManager/deviceManager.h>
|
||||
#include <mind.h>
|
||||
#include <stimBuffApis/stimBuffApiManager.h>
|
||||
#include <deviceManager/deviceManager.h>
|
||||
|
||||
namespace smo {
|
||||
namespace body {
|
||||
@@ -19,165 +16,71 @@ Body::Body(Mind &parent, const std::shared_ptr<sscl::PuppetThread> &thread)
|
||||
{
|
||||
}
|
||||
|
||||
class Body::InitializeReq
|
||||
: public sscl::PostedAsynchronousContinuation<bodyLifetimeMgmtOpCbFn>
|
||||
BodyViralPostingInvoker<bool> Body::initializeCReq()
|
||||
{
|
||||
public:
|
||||
InitializeReq(
|
||||
sscl::PuppetApplication &parent,
|
||||
const std::shared_ptr<sscl::ComponentThread> &caller,
|
||||
sscl::Callback<bodyLifetimeMgmtOpCbFn> callback)
|
||||
: sscl::PostedAsynchronousContinuation<bodyLifetimeMgmtOpCbFn>(caller, callback),
|
||||
parent(parent)
|
||||
{}
|
||||
|
||||
private:
|
||||
sscl::PuppetApplication &parent;
|
||||
|
||||
public:
|
||||
void initializeReq1_posted(
|
||||
[[maybe_unused]] std::shared_ptr<InitializeReq> context
|
||||
)
|
||||
{
|
||||
auto self = sscl::ComponentThread::getSelf();
|
||||
if (self->id != SmoThreadId::BODY)
|
||||
{
|
||||
throw std::runtime_error(std::string(__func__)
|
||||
+ ": Must be executed on Body thread");
|
||||
}
|
||||
|
||||
/** EXPLANATION:
|
||||
* The ComponentThread instance we pass in here is the one that will be
|
||||
* used by Senseapi libs to perform device-independent background
|
||||
* operations.
|
||||
* For example, liblivoxProto1's BroadcastListener will use this thread
|
||||
* to listen for UDP broadcast dgrams from Livox devices.
|
||||
*
|
||||
* We used to use Marionette, but there's a strong argument for using
|
||||
* Body instead since it's meant to handle device-management operations.
|
||||
*/
|
||||
// Upcast to Mind to access Mind-specific members
|
||||
Mind &mind = static_cast<Mind&>(context->parent);
|
||||
stim_buff::StimBuffApiManager::getInstance()
|
||||
.loadAllStimBuffApiLibsFromOptions(mind.body.thread);
|
||||
|
||||
/** EXPLANATION:
|
||||
* Consider body::initializeReq to have been called if even one of its
|
||||
* operations was executed at all, whether successfully or
|
||||
* unsuccessfully.
|
||||
*/
|
||||
mind.bodyComponentInitialized = true;
|
||||
|
||||
std::cout << stim_buff::StimBuffApiManager::getInstance().stringifyLibs()
|
||||
<< std::endl;
|
||||
|
||||
if (OptionParser::getOptions().verbose)
|
||||
{
|
||||
std::cout << __func__ << ": About to initializeAllStimBuffApiLibs"
|
||||
<< '\n';
|
||||
}
|
||||
stim_buff::StimBuffApiManager::getInstance()
|
||||
.initializeAllStimBuffApiLibs();
|
||||
|
||||
if (OptionParser::getOptions().verbose)
|
||||
{
|
||||
std::cout << __func__ << ": About to attachAllSenseDevicesFromSpecs"
|
||||
<< '\n';
|
||||
}
|
||||
device::DeviceManager::getInstance()
|
||||
.attachAllUnattachedDevicesFromCmdlineReq(
|
||||
{context, std::bind(
|
||||
&InitializeReq::initializeReq2,
|
||||
context.get(), context,
|
||||
std::placeholders::_1)});
|
||||
}
|
||||
|
||||
void initializeReq2(
|
||||
[[maybe_unused]] std::shared_ptr<InitializeReq> context,
|
||||
sscl::AsynchronousLoop &results
|
||||
)
|
||||
{
|
||||
std::cout << "Mrntt: attached "
|
||||
<< results.nSucceeded << " of " << results.nTotal
|
||||
<< " sense devices." << "\n";
|
||||
|
||||
callOriginalCb(results.nSucceeded > 0);
|
||||
}
|
||||
};
|
||||
|
||||
class Body::FinalizeReq
|
||||
: public InitializeReq
|
||||
{
|
||||
public:
|
||||
using InitializeReq::InitializeReq;
|
||||
|
||||
public:
|
||||
void finalizeReq1_posted(
|
||||
[[maybe_unused]] std::shared_ptr<FinalizeReq> context
|
||||
)
|
||||
{
|
||||
auto self = sscl::ComponentThread::getSelf();
|
||||
if (self->id != SmoThreadId::BODY)
|
||||
{
|
||||
throw std::runtime_error(std::string(__func__)
|
||||
+ ": Must be executed on Body thread");
|
||||
}
|
||||
|
||||
std::cout << "Mrntt: About to detach all sense devices." << "\n";
|
||||
device::DeviceManager::getInstance().detachAllAttachedDeviceRoles(
|
||||
{context, std::bind(
|
||||
&FinalizeReq::finalizeReq2,
|
||||
context.get(), context,
|
||||
std::placeholders::_1)});
|
||||
}
|
||||
|
||||
void finalizeReq2(
|
||||
[[maybe_unused]] std::shared_ptr<FinalizeReq> context,
|
||||
sscl::AsynchronousLoop &results
|
||||
)
|
||||
{
|
||||
std::cout << "Mrntt: Successfully detached "
|
||||
<< results.nSucceeded << " of " << results.nTotal
|
||||
<< " sense devices." << "\n";
|
||||
|
||||
std::cout << "Mrntt: About to finalize all stim buff api libs." << "\n";
|
||||
stim_buff::StimBuffApiManager::getInstance().finalizeAllStimBuffApiLibs();
|
||||
|
||||
std::cout << "Mrntt: About to unload all stim buff api libs." << "\n";
|
||||
stim_buff::StimBuffApiManager::getInstance().unloadAllStimBuffApiLibs();
|
||||
callOriginalCb(results.nSucceeded == results.nTotal);
|
||||
}
|
||||
};
|
||||
|
||||
void Body::initializeReq(sscl::Callback<bodyLifetimeMgmtOpCbFn> callback)
|
||||
{
|
||||
auto mrntt = sscl::ComponentThread::getSelf();
|
||||
|
||||
if (mrntt->id != SmoThreadId::MRNTT)
|
||||
auto self = sscl::ComponentThread::getSelf();
|
||||
if (self->id != SmoThreadId::BODY)
|
||||
{
|
||||
throw std::runtime_error(std::string(__func__)
|
||||
+ ": Must be invoked by Mrntt thread");
|
||||
+ ": Must be executed on Body thread");
|
||||
}
|
||||
|
||||
auto request = std::make_shared<InitializeReq>(
|
||||
parent, mrntt, callback);
|
||||
/** EXPLANATION:
|
||||
* The ComponentThread instance we pass in here is the one that will be
|
||||
* used by Senseapi libs to perform device-independent background
|
||||
* operations.
|
||||
* For example, liblivoxProto1's BroadcastListener will use this thread
|
||||
* to listen for UDP broadcast dgrams from Livox devices.
|
||||
*
|
||||
* We used to use Marionette, but there's a strong argument for using
|
||||
* Body instead since it's meant to handle device-management operations.
|
||||
*/
|
||||
// Upcast to Mind to access Mind-specific members
|
||||
Mind &mind = static_cast<Mind&>(parent);
|
||||
stim_buff::StimBuffApiManager::getInstance()
|
||||
.loadAllStimBuffApiLibsFromOptions(mind.body.thread);
|
||||
|
||||
thread->getIoService().post(
|
||||
STC(std::bind(
|
||||
&InitializeReq::initializeReq1_posted,
|
||||
request.get(), request)));
|
||||
/** EXPLANATION:
|
||||
* Consider body::initializeCReq to have been called if even one of its
|
||||
* operations was executed at all, whether successfully or
|
||||
* unsuccessfully.
|
||||
*/
|
||||
mind.bodyComponentInitialized = true;
|
||||
|
||||
std::cout << stim_buff::StimBuffApiManager::getInstance().stringifyLibs()
|
||||
<< std::endl;
|
||||
|
||||
if (OptionParser::getOptions().verbose)
|
||||
{
|
||||
std::cout << __func__ << ": About to initializeAllStimBuffApiLibs"
|
||||
<< '\n';
|
||||
}
|
||||
stim_buff::StimBuffApiManager::getInstance()
|
||||
.initializeAllStimBuffApiLibs();
|
||||
|
||||
if (OptionParser::getOptions().verbose)
|
||||
{
|
||||
std::cout << __func__ << ": About to attachAllUnattachedDevicesFromCmdline"
|
||||
<< '\n';
|
||||
}
|
||||
|
||||
sscl::MultiOperationResultSet attachResults = co_await
|
||||
device::DeviceManager::getInstance()
|
||||
.attachAllUnattachedDevicesFromCmdlineCReq();
|
||||
std::cout << "Mrntt: attached "
|
||||
<< attachResults.nSucceeded << " of " << attachResults.nTotal
|
||||
<< " sense devices." << "\n";
|
||||
|
||||
co_return attachResults.nSucceeded > 0;
|
||||
}
|
||||
|
||||
void Body::finalizeReq(sscl::Callback<bodyLifetimeMgmtOpCbFn> callback)
|
||||
BodyViralPostingInvoker<bool> Body::finalizeCReq()
|
||||
{
|
||||
auto mrntt = sscl::ComponentThread::getSelf();
|
||||
|
||||
if (mrntt->id != SmoThreadId::MRNTT)
|
||||
auto self = sscl::ComponentThread::getSelf();
|
||||
if (self->id != SmoThreadId::BODY)
|
||||
{
|
||||
std::cerr << __func__ << ": Must be invoked by Mrntt thread"
|
||||
<< std::endl;
|
||||
callback.callbackFn(false);
|
||||
return;
|
||||
throw std::runtime_error(std::string(__func__)
|
||||
+ ": Must be executed on Body thread");
|
||||
}
|
||||
|
||||
// Upcast to Mind to access Mind-specific members
|
||||
@@ -186,17 +89,23 @@ void Body::finalizeReq(sscl::Callback<bodyLifetimeMgmtOpCbFn> callback)
|
||||
{
|
||||
std::cout << "Mrntt: Body component not initialized. "
|
||||
<< "Skipping finalization." << "\n";
|
||||
callback.callbackFn(true);
|
||||
return;
|
||||
co_return true;
|
||||
}
|
||||
|
||||
auto request = std::make_shared<FinalizeReq>(
|
||||
parent, mrntt, callback);
|
||||
std::cout << "Mrntt: About to detach all sense devices." << "\n";
|
||||
sscl::MultiOperationResultSet detachResults = co_await
|
||||
device::DeviceManager::getInstance().detachAllAttachedDeviceRolesCReq();
|
||||
std::cout << "Mrntt: Successfully detached "
|
||||
<< detachResults.nSucceeded << " of " << detachResults.nTotal
|
||||
<< " sense devices." << "\n";
|
||||
|
||||
thread->getIoService().post(
|
||||
STC(std::bind(
|
||||
&FinalizeReq::finalizeReq1_posted,
|
||||
request.get(), request)));
|
||||
std::cout << "Mrntt: About to finalize all stim buff api libs." << "\n";
|
||||
stim_buff::StimBuffApiManager::getInstance().finalizeAllStimBuffApiLibs();
|
||||
|
||||
std::cout << "Mrntt: About to unload all stim buff api libs." << "\n";
|
||||
stim_buff::StimBuffApiManager::getInstance().unloadAllStimBuffApiLibs();
|
||||
|
||||
co_return detachResults.nSucceeded == detachResults.nTotal;
|
||||
}
|
||||
|
||||
} // namespace body
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
#include <stdexcept>
|
||||
|
||||
#include <body/bodyThread.h>
|
||||
#include <componentThread.h>
|
||||
#include <director/directorThread.h>
|
||||
#include <marionette/marionette.h>
|
||||
#include <marionette/marionetteThread.h>
|
||||
#include <mind.h>
|
||||
#include <simulator/simulatorThread.h>
|
||||
#include <subconsciousThread.h>
|
||||
#include <world/worldThread.h>
|
||||
|
||||
namespace smo {
|
||||
namespace mrntt {
|
||||
|
||||
boost::asio::io_service &MrnttThreadTag::io_service() noexcept
|
||||
{
|
||||
return thread->getIoService();
|
||||
}
|
||||
|
||||
} // namespace mrntt
|
||||
|
||||
namespace body {
|
||||
|
||||
boost::asio::io_service &BodyThreadTag::io_service()
|
||||
{
|
||||
if (!mind::globalMind) {
|
||||
throw std::runtime_error(
|
||||
"BodyThreadTag: globalMind not initialized");
|
||||
}
|
||||
|
||||
return mind::globalMind->body.thread->getIoService();
|
||||
}
|
||||
|
||||
} // namespace body
|
||||
|
||||
namespace director {
|
||||
|
||||
boost::asio::io_service &DirectorThreadTag::io_service()
|
||||
{
|
||||
if (!mind::globalMind) {
|
||||
throw std::runtime_error(
|
||||
"DirectorThreadTag: globalMind not initialized");
|
||||
}
|
||||
|
||||
return mind::globalMind->director.thread->getIoService();
|
||||
}
|
||||
|
||||
} // namespace director
|
||||
|
||||
namespace simulator {
|
||||
|
||||
boost::asio::io_service &SimulatorThreadTag::io_service()
|
||||
{
|
||||
if (!mind::globalMind) {
|
||||
throw std::runtime_error(
|
||||
"SimulatorThreadTag: globalMind not initialized");
|
||||
}
|
||||
|
||||
return mind::globalMind->canvas.thread->getIoService();
|
||||
}
|
||||
|
||||
} // namespace simulator
|
||||
|
||||
boost::asio::io_service &SubconsciousThreadTag::io_service()
|
||||
{
|
||||
if (!mind::globalMind) {
|
||||
throw std::runtime_error(
|
||||
"SubconsciousThreadTag: globalMind not initialized");
|
||||
}
|
||||
|
||||
return mind::globalMind->subconscious.thread->getIoService();
|
||||
}
|
||||
|
||||
boost::asio::io_service &WorldThreadTag::io_service()
|
||||
{
|
||||
if (!mind::globalMind) {
|
||||
throw std::runtime_error(
|
||||
"WorldThreadTag: globalMind not initialized");
|
||||
}
|
||||
|
||||
return mind::globalMind->world.thread->getIoService();
|
||||
}
|
||||
|
||||
} // namespace smo
|
||||
@@ -33,23 +33,27 @@ std::string DeviceManager::readDapSpecFile(const std::string& filename)
|
||||
void DeviceManager::collateAllDapSpecs(void)
|
||||
{
|
||||
OptionParser &options = OptionParser::getOptions();
|
||||
allDapSpecs = options.dapSpecs;
|
||||
DeviceManager &dm = getInstance();
|
||||
dm.s.rsrc.allDapSpecs = options.dapSpecs;
|
||||
|
||||
for (const auto& file : options.dapSpecFiles)
|
||||
{
|
||||
std::string fileContent = readDapSpecFile(file);
|
||||
if (!allDapSpecs.empty()) {
|
||||
allDapSpecs += "||";
|
||||
if (!dm.s.rsrc.allDapSpecs.empty()) {
|
||||
dm.s.rsrc.allDapSpecs += "||";
|
||||
}
|
||||
allDapSpecs += fileContent;
|
||||
dm.s.rsrc.allDapSpecs += fileContent;
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceManager::parseAllDapSpecs(void)
|
||||
{
|
||||
DeviceManager &dm = getInstance();
|
||||
auto file_deleter = [](FILE* f) { if (f) fclose(f); };
|
||||
std::unique_ptr<FILE, decltype(file_deleter)> input(
|
||||
fmemopen((void*)allDapSpecs.c_str(), allDapSpecs.size(), "r"),
|
||||
fmemopen(
|
||||
(void*)dm.s.rsrc.allDapSpecs.c_str(),
|
||||
dm.s.rsrc.allDapSpecs.size(), "r"),
|
||||
file_deleter);
|
||||
|
||||
if (!input)
|
||||
|
||||
@@ -91,7 +91,7 @@ interoceptor_spec:
|
||||
*static_cast<smo::device::InteroceptorDevAttachmentSpec *>($3));
|
||||
|
||||
spec->sensorType = $1;
|
||||
smo::device::DeviceManager::commandLineDASpecs.push_back(*spec);
|
||||
smo::device::DeviceManager::getInstance().s.rsrc.commandLineDASpecs.push_back(*spec);
|
||||
|
||||
delete $3;
|
||||
}
|
||||
@@ -103,7 +103,7 @@ extrospector_spec:
|
||||
*static_cast<smo::device::ExtrospectorDevAttachmentSpec *>($3));
|
||||
|
||||
spec->sensorType = $1;
|
||||
smo::device::DeviceManager::commandLineDASpecs.push_back(*spec);
|
||||
smo::device::DeviceManager::getInstance().s.rsrc.commandLineDASpecs.push_back(*spec);
|
||||
|
||||
delete $3;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,22 +1,20 @@
|
||||
#include <config.h>
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include <functional>
|
||||
#include <componentThread.h>
|
||||
#include <spinscale/callback.h>
|
||||
#include <deviceManager/deviceReattacher.h>
|
||||
#include <deviceManager/deviceManager.h>
|
||||
#include <marionette/marionetteThread.h>
|
||||
|
||||
namespace smo {
|
||||
namespace device {
|
||||
|
||||
static void reattachmentCb(sscl::AsynchronousLoop& results)
|
||||
{
|
||||
if (results.nTotal == 0) { return; }
|
||||
namespace {
|
||||
|
||||
std::cout << "DeviceReattacher: Successfully reattached "
|
||||
<< results.nSucceeded << " of " << results.nTotal << " devices"
|
||||
<< std::endl;
|
||||
}
|
||||
constexpr unsigned int reattachInFlightStaleThresholdMultiplier = 4;
|
||||
|
||||
} // namespace
|
||||
|
||||
DeviceReattacher::DeviceReattacher(
|
||||
DeviceManager& parent, std::shared_ptr<sscl::ComponentThread> ioThread)
|
||||
@@ -25,6 +23,22 @@ timer(ioThread->getIoService())
|
||||
{
|
||||
}
|
||||
|
||||
mrntt::MrnttNonViralPostingInvoker DeviceReattacher::reattachKnownListCReq(
|
||||
[[maybe_unused]] std::exception_ptr &exceptionPtr,
|
||||
[[maybe_unused]] std::function<void()> callback)
|
||||
{
|
||||
sscl::MultiOperationResultSet results = co_await
|
||||
parent.attachAllUnattachedDevicesFromKnownListCReq();
|
||||
if (results.nTotal > 0)
|
||||
{
|
||||
std::cout << "DeviceReattacher: Successfully reattached "
|
||||
<< results.nSucceeded << " of " << results.nTotal
|
||||
<< " devices" << std::endl;
|
||||
}
|
||||
|
||||
co_return;
|
||||
}
|
||||
|
||||
void DeviceReattacher::start()
|
||||
{
|
||||
shouldContinue = true;
|
||||
@@ -36,6 +50,14 @@ void DeviceReattacher::stop()
|
||||
{
|
||||
sscl::SpinLock::Guard lock(shouldContinueLock);
|
||||
shouldContinue = false;
|
||||
reattachOpInFlight = false;
|
||||
/** EXPLANATION:
|
||||
* Do not call reattachCReqInvoker.reset() here. Forcibly destroying
|
||||
* the invoker would tear down an in-flight reattach coroutine frame
|
||||
* mid-operation. During normal program teardown the optional (and
|
||||
* its invoker) are destroyed with the rest of the binary anyway; leave
|
||||
* a running reattach time to finish if shutdown races with it.
|
||||
*/
|
||||
}
|
||||
|
||||
timer.cancel();
|
||||
@@ -56,6 +78,21 @@ void DeviceReattacher::scheduleNextTimeout()
|
||||
std::bind(&DeviceReattacher::onTimeout, this, std::placeholders::_1));
|
||||
}
|
||||
|
||||
void DeviceReattacher::holdReattachCReq()
|
||||
{
|
||||
reattachOpInFlight = true;
|
||||
lastReattachReqTimestamp = std::chrono::steady_clock::now();
|
||||
|
||||
reattachCReqInvoker.reset();
|
||||
reattachCReqInvoker.emplace(reattachKnownListCReq(
|
||||
reattachLifetimeExceptionPtr,
|
||||
[this]()
|
||||
{
|
||||
sscl::SpinLock::Guard lock(shouldContinueLock);
|
||||
reattachOpInFlight = false;
|
||||
}));
|
||||
}
|
||||
|
||||
void DeviceReattacher::onTimeout(const boost::system::error_code& error)
|
||||
{
|
||||
// Timer was cancelled, which is expected when stopping
|
||||
@@ -75,9 +112,32 @@ void DeviceReattacher::onTimeout(const boost::system::error_code& error)
|
||||
return;
|
||||
}
|
||||
|
||||
const auto staleThreshold = std::chrono::milliseconds(
|
||||
reattachInFlightStaleThresholdMultiplier
|
||||
* CONFIG_MRNTT_DEVMGR_REATTACHER_PERIOD_MS);
|
||||
|
||||
// Attempt to reattach all unattached devices from the known list
|
||||
parent.attachAllUnattachedDevicesFromKnownListReq(
|
||||
{ nullptr, reattachmentCb});
|
||||
if (!reattachOpInFlight)
|
||||
{
|
||||
holdReattachCReq();
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto elapsedSinceLastReattachReq =
|
||||
std::chrono::steady_clock::now() - lastReattachReqTimestamp;
|
||||
|
||||
if (elapsedSinceLastReattachReq >= staleThreshold)
|
||||
{
|
||||
std::cerr << "DeviceReattacher: Reattach op still in flight after "
|
||||
<< std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
elapsedSinceLastReattachReq).count()
|
||||
<< "ms (threshold "
|
||||
<< staleThreshold.count()
|
||||
<< "ms); forcing a new reattach request."
|
||||
<< std::endl;
|
||||
holdReattachCReq();
|
||||
}
|
||||
}
|
||||
|
||||
// Schedule the next timeout
|
||||
scheduleNextTimeout();
|
||||
|
||||
@@ -4,8 +4,7 @@
|
||||
#include <spinscale/puppetApplication.h>
|
||||
#include <spinscale/component.h>
|
||||
#include <mindComponent.h>
|
||||
#include <functional>
|
||||
#include <spinscale/callback.h>
|
||||
#include <body/bodyThread.h>
|
||||
|
||||
namespace smo {
|
||||
|
||||
@@ -20,16 +19,11 @@ public:
|
||||
Body(Mind &parent, const std::shared_ptr<sscl::PuppetThread> &thread);
|
||||
~Body() = default;
|
||||
|
||||
typedef std::function<void(bool)> bodyLifetimeMgmtOpCbFn;
|
||||
void initializeReq(sscl::Callback<bodyLifetimeMgmtOpCbFn> callback);
|
||||
void finalizeReq(sscl::Callback<bodyLifetimeMgmtOpCbFn> callback);
|
||||
|
||||
private:
|
||||
class InitializeReq;
|
||||
class FinalizeReq;
|
||||
BodyViralPostingInvoker<bool> initializeCReq();
|
||||
BodyViralPostingInvoker<bool> finalizeCReq();
|
||||
};
|
||||
|
||||
} // namespace body
|
||||
} // namespace smo
|
||||
|
||||
#endif // _BODY_COMPONENT_H
|
||||
#endif // _BODY_COMPONENT_H
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
#ifndef SMO_BODY_THREAD_H
|
||||
#define SMO_BODY_THREAD_H
|
||||
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <spinscale/co/invokers.h>
|
||||
#include <spinscale/co/postingPromise.h>
|
||||
|
||||
namespace smo {
|
||||
namespace body {
|
||||
|
||||
struct BodyThreadTag
|
||||
{
|
||||
static boost::asio::io_service &io_service();
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using BodyPostingPromise =
|
||||
sscl::co::TaggedPostingPromise<T, BodyThreadTag>;
|
||||
|
||||
using BodyNonViralPostingInvoker =
|
||||
sscl::co::NonViralPostingInvoker<BodyPostingPromise>;
|
||||
|
||||
template <typename T>
|
||||
using BodyViralPostingInvoker =
|
||||
sscl::co::ViralPostingInvoker<BodyPostingPromise, T>;
|
||||
|
||||
} // namespace body
|
||||
} // namespace smo
|
||||
|
||||
#endif // SMO_BODY_THREAD_H
|
||||
@@ -7,7 +7,7 @@
|
||||
#include <sstream>
|
||||
#include <user/deviceAttachmentSpec.h>
|
||||
#include <deviceManager/deviceRole.h>
|
||||
#include <spinscale/qutex.h>
|
||||
#include <spinscale/co/coQutex.h>
|
||||
|
||||
namespace smo {
|
||||
namespace device {
|
||||
@@ -15,25 +15,26 @@ namespace device {
|
||||
class Device
|
||||
{
|
||||
public:
|
||||
Device(const std::string& identifier)
|
||||
: deviceIdentifier(identifier), qutex("Device-" + identifier)
|
||||
explicit Device(const std::string& identifier)
|
||||
: deviceIdentifier(identifier),
|
||||
qutex("Device-" + identifier)
|
||||
{}
|
||||
|
||||
std::string stringify() const
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << "Device Identifier: " << deviceIdentifier
|
||||
<< ", Device Roles: " << deviceRoles.size() << std::endl;
|
||||
for (const auto& deviceRole : deviceRoles) {
|
||||
os << " " << deviceRole->deviceAttachmentSpec->stringify();
|
||||
}
|
||||
return os.str();
|
||||
}
|
||||
std::string stringify() const
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << "Device Identifier: " << deviceIdentifier
|
||||
<< ", Device Roles: " << deviceRoles.size() << std::endl;
|
||||
for (const auto& deviceRole : deviceRoles) {
|
||||
os << " " << deviceRole->deviceAttachmentSpec->stringify();
|
||||
}
|
||||
return os.str();
|
||||
}
|
||||
|
||||
public:
|
||||
std::string deviceIdentifier;
|
||||
std::vector<std::shared_ptr<DeviceRole>> deviceRoles;
|
||||
sscl::Qutex qutex;
|
||||
sscl::co::CoQutex qutex;
|
||||
};
|
||||
|
||||
} // namespace device
|
||||
|
||||
@@ -7,15 +7,16 @@
|
||||
#include <opts.h>
|
||||
#include <utility>
|
||||
#include <iostream>
|
||||
#include <functional>
|
||||
#include <user/senseApiDesc.h>
|
||||
#include <user/deviceAttachmentSpec.h>
|
||||
#include <spinscale/asynchronousLoop.h>
|
||||
#include <deviceManager/device.h>
|
||||
#include <deviceManager/deviceRole.h>
|
||||
#include <deviceManager/deviceReattacher.h>
|
||||
#include <spinscale/callback.h>
|
||||
#include <spinscale/qutex.h>
|
||||
#include <cpsBoundary/stimBuffDeviceAReq.h>
|
||||
#include <marionette/marionetteThread.h>
|
||||
#include <spinscale/co/coQutex.h>
|
||||
#include <spinscale/multiOperationResultSet.h>
|
||||
#include <spinscale/sharedResourceGroup.h>
|
||||
|
||||
namespace smo {
|
||||
namespace device {
|
||||
@@ -25,11 +26,18 @@ class DeviceReattacher;
|
||||
class DeviceManager
|
||||
{
|
||||
public:
|
||||
static DeviceManager& getInstance()
|
||||
{
|
||||
static DeviceManager instance;
|
||||
return instance;
|
||||
}
|
||||
struct DeviceAttachmentIndResult
|
||||
{
|
||||
bool success = false;
|
||||
std::shared_ptr<DeviceRole> deviceRole;
|
||||
std::shared_ptr<DeviceAttachmentSpec> deviceSpec;
|
||||
};
|
||||
|
||||
static DeviceManager& getInstance()
|
||||
{
|
||||
static DeviceManager instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
void initialize(void)
|
||||
{};
|
||||
@@ -39,80 +47,61 @@ public:
|
||||
void initializeDeviceReattacher();
|
||||
void finalizeDeviceReattacher();
|
||||
|
||||
std::string readDapSpecFile(const std::string& filename);
|
||||
void collateAllDapSpecs(void);
|
||||
void parseAllDapSpecs(void);
|
||||
std::string readDapSpecFile(const std::string& filename);
|
||||
void collateAllDapSpecs(void);
|
||||
void parseAllDapSpecs(void);
|
||||
|
||||
static const std::string stringifyDeviceSpecs(void);
|
||||
static const std::string stringifyDeviceSpecs(void);
|
||||
|
||||
typedef std::function<void(
|
||||
bool success, std::shared_ptr<DeviceRole> deviceRole,
|
||||
std::shared_ptr<DeviceAttachmentSpec> deviceSpec)>
|
||||
newDeviceAttachmentSpecIndCbFn;
|
||||
typedef std::function<void(
|
||||
bool success, std::shared_ptr<DeviceAttachmentSpec> deviceSpec)>
|
||||
removeDeviceAttachmentSpecReqCbFn;
|
||||
mrntt::MrnttViralPostingInvoker<DeviceAttachmentIndResult>
|
||||
newDeviceAttachmentSpecIndCReq(const DeviceAttachmentSpec &spec);
|
||||
|
||||
void newDeviceAttachmentSpecInd(
|
||||
const DeviceAttachmentSpec &spec,
|
||||
sscl::Callback<newDeviceAttachmentSpecIndCbFn> callback);
|
||||
void removeDeviceAttachmentSpecReq(
|
||||
const DeviceAttachmentSpec &spec,
|
||||
sscl::Callback<removeDeviceAttachmentSpecReqCbFn> callback);
|
||||
mrntt::MrnttViralPostingInvoker<DeviceAttachmentIndResult>
|
||||
removeDeviceAttachmentSpecCReq(const DeviceAttachmentSpec &spec);
|
||||
|
||||
// Device attachment/detachment methods moved from SenseApiManager
|
||||
typedef stim_buff::sal_mlo_attachDeviceReqCbFn attachStimBuffDeviceReqCbFn;
|
||||
typedef stim_buff::sal_mlo_detachDeviceReqCbFn detachStimBuffDeviceReqCbFn;
|
||||
mrntt::MrnttViralPostingInvoker<cpsBoundary::StimBuffDeviceOpResult>
|
||||
attachStimBuffDeviceCReq(
|
||||
const std::shared_ptr<DeviceAttachmentSpec>& spec);
|
||||
|
||||
void attachStimBuffDeviceReq(
|
||||
const std::shared_ptr<DeviceAttachmentSpec>& spec,
|
||||
sscl::Callback<attachStimBuffDeviceReqCbFn> cb);
|
||||
void detachStimBuffDeviceReq(
|
||||
const std::shared_ptr<DeviceAttachmentSpec>& spec,
|
||||
sscl::Callback<detachStimBuffDeviceReqCbFn> cb);
|
||||
mrntt::MrnttViralPostingInvoker<cpsBoundary::StimBuffDeviceOpResult>
|
||||
detachStimBuffDeviceCReq(
|
||||
const std::shared_ptr<DeviceAttachmentSpec>& spec);
|
||||
|
||||
typedef std::function<void(sscl::AsynchronousLoop &results)>
|
||||
attachAllUnattachedDevicesFromReqCbFn;
|
||||
typedef std::function<void(sscl::AsynchronousLoop &results)>
|
||||
detachAllAttachedDeviceRolesCbFn;
|
||||
mrntt::MrnttViralPostingInvoker<sscl::MultiOperationResultSet>
|
||||
attachAllUnattachedDevicesFromCReq(
|
||||
const std::shared_ptr<std::vector<DeviceAttachmentSpec>> &specs);
|
||||
|
||||
void attachAllUnattachedDevicesFromReq(
|
||||
const std::shared_ptr<std::vector<DeviceAttachmentSpec>> &specs,
|
||||
sscl::Callback<attachAllUnattachedDevicesFromReqCbFn> cb);
|
||||
void attachAllUnattachedDevicesFromKnownListReq(
|
||||
sscl::Callback<attachAllUnattachedDevicesFromReqCbFn> cb);
|
||||
void attachAllUnattachedDevicesFromCmdlineReq(
|
||||
sscl::Callback<attachAllUnattachedDevicesFromReqCbFn> cb);
|
||||
void detachAllAttachedDeviceRoles(
|
||||
sscl::Callback<detachAllAttachedDeviceRolesCbFn> cb);
|
||||
mrntt::MrnttViralPostingInvoker<sscl::MultiOperationResultSet>
|
||||
attachAllUnattachedDevicesFromKnownListCReq();
|
||||
|
||||
mrntt::MrnttViralPostingInvoker<sscl::MultiOperationResultSet>
|
||||
attachAllUnattachedDevicesFromCmdlineCReq();
|
||||
|
||||
mrntt::MrnttViralPostingInvoker<sscl::MultiOperationResultSet>
|
||||
detachAllAttachedDeviceRolesCReq();
|
||||
|
||||
private:
|
||||
DeviceManager()
|
||||
: qutex("DeviceManager"), deviceReattacher(nullptr)
|
||||
DeviceManager()
|
||||
: s("DeviceManager")
|
||||
{}
|
||||
~DeviceManager();
|
||||
DeviceManager(const DeviceManager&) = delete;
|
||||
DeviceManager& operator=(const DeviceManager&) = delete;
|
||||
|
||||
~DeviceManager();
|
||||
DeviceManager(const DeviceManager&) = delete;
|
||||
DeviceManager& operator=(const DeviceManager&) = delete;
|
||||
|
||||
public:
|
||||
sscl::Qutex qutex;
|
||||
std::string allDapSpecs;
|
||||
static std::vector<std::shared_ptr<DeviceAttachmentSpec>>
|
||||
deviceAttachmentSpecs;
|
||||
static std::vector<std::shared_ptr<Device>> devices;
|
||||
static std::vector<std::shared_ptr<DeviceRole>> attachedDeviceRoles;
|
||||
static std::vector<DeviceAttachmentSpec> commandLineDASpecs;
|
||||
struct Resources
|
||||
{
|
||||
std::vector<std::shared_ptr<DeviceAttachmentSpec>> deviceAttachmentSpecs;
|
||||
std::vector<std::shared_ptr<Device>> devices;
|
||||
std::vector<std::shared_ptr<DeviceRole>> attachedDeviceRoles;
|
||||
std::vector<DeviceAttachmentSpec> commandLineDASpecs;
|
||||
std::string allDapSpecs;
|
||||
};
|
||||
sscl::SharedResourceGroup<sscl::co::CoQutex, Resources> s;
|
||||
|
||||
private:
|
||||
std::unique_ptr<DeviceReattacher> deviceReattacher;
|
||||
|
||||
class NewDeviceAttachmentSpecInd;
|
||||
class RemoveDeviceAttachmentSpecReq;
|
||||
class AttachStimBuffDeviceReq;
|
||||
typedef AttachStimBuffDeviceReq DetachStimBuffDeviceReq;
|
||||
class AttachAllUnattachedDevicesFromReq;
|
||||
class AttachAllUnattachedDevicesFromKnownListReq;
|
||||
class DetachAllAttachedDeviceRoles;
|
||||
};
|
||||
|
||||
} // namespace device
|
||||
|
||||
@@ -3,8 +3,14 @@
|
||||
|
||||
#include <boostAsioLinkageFix.h>
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <exception>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <boost/asio/deadline_timer.hpp>
|
||||
#include <marionette/marionetteThread.h>
|
||||
#include <spinscale/multiOperationResultSet.h>
|
||||
#include <spinscale/spinLock.h>
|
||||
|
||||
namespace smo {
|
||||
@@ -16,27 +22,35 @@ class DeviceManager;
|
||||
class DeviceReattacher
|
||||
{
|
||||
public:
|
||||
DeviceReattacher(
|
||||
DeviceReattacher(
|
||||
DeviceManager& parent, std::shared_ptr<sscl::ComponentThread> ioThread);
|
||||
~DeviceReattacher() = default;
|
||||
~DeviceReattacher() = default;
|
||||
|
||||
// Non-copyable
|
||||
DeviceReattacher(const DeviceReattacher&) = delete;
|
||||
DeviceReattacher& operator=(const DeviceReattacher&) = delete;
|
||||
DeviceReattacher(const DeviceReattacher&) = delete;
|
||||
DeviceReattacher& operator=(const DeviceReattacher&) = delete;
|
||||
|
||||
// Control methods
|
||||
void start();
|
||||
void stop();
|
||||
// Control methods
|
||||
void start();
|
||||
void stop();
|
||||
|
||||
private:
|
||||
void scheduleNextTimeout();
|
||||
void onTimeout(const boost::system::error_code& error);
|
||||
void scheduleNextTimeout();
|
||||
void onTimeout(const boost::system::error_code& error);
|
||||
void holdReattachCReq();
|
||||
|
||||
DeviceManager &parent;
|
||||
std::shared_ptr<sscl::ComponentThread> ioThread;
|
||||
sscl::SpinLock shouldContinueLock;
|
||||
bool shouldContinue;
|
||||
boost::asio::deadline_timer timer;
|
||||
mrntt::MrnttNonViralPostingInvoker reattachKnownListCReq(
|
||||
std::exception_ptr &exceptionPtr,
|
||||
std::function<void()> callback);
|
||||
|
||||
DeviceManager &parent;
|
||||
std::shared_ptr<sscl::ComponentThread> ioThread;
|
||||
sscl::SpinLock shouldContinueLock;
|
||||
bool shouldContinue;
|
||||
boost::asio::deadline_timer timer;
|
||||
std::exception_ptr reattachLifetimeExceptionPtr;
|
||||
std::optional<mrntt::MrnttNonViralPostingInvoker> reattachCReqInvoker;
|
||||
bool reattachOpInFlight = false;
|
||||
std::chrono::steady_clock::time_point lastReattachReqTimestamp{};
|
||||
};
|
||||
|
||||
} // namespace device
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
#ifndef SMO_DIRECTOR_THREAD_H
|
||||
#define SMO_DIRECTOR_THREAD_H
|
||||
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <spinscale/co/invokers.h>
|
||||
#include <spinscale/co/postingPromise.h>
|
||||
|
||||
namespace smo {
|
||||
namespace director {
|
||||
|
||||
struct DirectorThreadTag
|
||||
{
|
||||
static boost::asio::io_service &io_service();
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using DirectorPostingPromise =
|
||||
sscl::co::TaggedPostingPromise<T, DirectorThreadTag>;
|
||||
|
||||
template <typename T>
|
||||
using DirectorViralPostingInvoker =
|
||||
sscl::co::ViralPostingInvoker<DirectorPostingPromise, T>;
|
||||
|
||||
} // namespace director
|
||||
} // namespace smo
|
||||
|
||||
#endif // SMO_DIRECTOR_THREAD_H
|
||||
@@ -4,9 +4,12 @@
|
||||
#include <boost/asio/signal_set.hpp>
|
||||
#include <cstdint>
|
||||
#include <atomic>
|
||||
#include <exception>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <spinscale/component.h>
|
||||
#include <marionette/marionetteThread.h>
|
||||
|
||||
namespace sscl {
|
||||
|
||||
@@ -26,11 +29,17 @@ public:
|
||||
{}
|
||||
~MarionetteComponent() = default;
|
||||
|
||||
public:
|
||||
typedef std::function<void(bool)> mrnttLifetimeMgmtOpCbFn;
|
||||
void initializeReq(sscl::Callback<mrnttLifetimeMgmtOpCbFn> callback);
|
||||
void finalizeReq(sscl::Callback<mrnttLifetimeMgmtOpCbFn> callback);
|
||||
// Intentionally doesn't take a callback.
|
||||
void holdInitializeCReq(std::function<void()> completion);
|
||||
void holdFinalizeCReq(std::function<void()> completion);
|
||||
|
||||
MrnttNonViralPostingInvoker initializeCReq(
|
||||
std::exception_ptr &exceptionPtr,
|
||||
std::function<void()> callback);
|
||||
|
||||
MrnttNonViralPostingInvoker finalizeCReq(
|
||||
std::exception_ptr &exceptionPtr,
|
||||
std::function<void()> callback);
|
||||
|
||||
void exceptionInd();
|
||||
|
||||
void handleLoopExceptionHook() override;
|
||||
@@ -47,11 +56,14 @@ protected:
|
||||
void handleTryBlock1UnknownException() override;
|
||||
|
||||
private:
|
||||
class MrnttLifetimeMgmtOp;
|
||||
class TerminationEvent;
|
||||
|
||||
std::unique_ptr<boost::asio::signal_set> signals;
|
||||
bool callShutdownSalmanoff = false;
|
||||
std::optional<MrnttNonViralPostingInvoker> initializeCReqInvoker;
|
||||
std::optional<MrnttNonViralPostingInvoker> finalizeCReqInvoker;
|
||||
|
||||
public:
|
||||
std::exception_ptr initializeLifetimeExceptionPtr;
|
||||
std::exception_ptr finalizeLifetimeExceptionPtr;
|
||||
};
|
||||
|
||||
extern std::shared_ptr<sscl::PuppeteerThread> thread;
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
#ifndef SMO_MARIONETTE_THREAD_H
|
||||
#define SMO_MARIONETTE_THREAD_H
|
||||
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <spinscale/co/invokers.h>
|
||||
#include <spinscale/co/postingPromise.h>
|
||||
|
||||
namespace smo {
|
||||
namespace mrntt {
|
||||
|
||||
struct MrnttThreadTag
|
||||
{
|
||||
static boost::asio::io_service &io_service() noexcept;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using MrnttPostingPromise =
|
||||
sscl::co::TaggedPostingPromise<T, MrnttThreadTag>;
|
||||
|
||||
using MrnttNonViralPostingInvoker =
|
||||
sscl::co::NonViralPostingInvoker<MrnttPostingPromise>;
|
||||
|
||||
template <typename T>
|
||||
using MrnttViralPostingInvoker =
|
||||
sscl::co::ViralPostingInvoker<MrnttPostingPromise, T>;
|
||||
|
||||
using MrnttViralNonPostingInvoker =
|
||||
sscl::co::ViralNonPostingInvoker<void>;
|
||||
|
||||
template <typename T>
|
||||
using MrnttViralNonPostingInvokerT =
|
||||
sscl::co::ViralNonPostingInvoker<T>;
|
||||
|
||||
} // namespace mrntt
|
||||
} // namespace smo
|
||||
|
||||
#endif // SMO_MARIONETTE_THREAD_H
|
||||
@@ -2,16 +2,15 @@
|
||||
#define _MIND_H
|
||||
|
||||
#include <config.h>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <spinscale/callback.h>
|
||||
|
||||
#include <spinscale/puppetApplication.h>
|
||||
#include <spinscale/component.h>
|
||||
#include <componentThread.h>
|
||||
#include <mindThread.h>
|
||||
#include <mindComponent.h>
|
||||
#include <marionette/marionetteThread.h>
|
||||
#include <director/director.h>
|
||||
#include <simulator/simulator.h>
|
||||
#include <body/body.h>
|
||||
@@ -25,9 +24,8 @@ public:
|
||||
Mind(void);
|
||||
~Mind(void) = default;
|
||||
|
||||
typedef std::function<void(bool)> mindLifetimeMgmtOpCbFn;
|
||||
void initializeReq(sscl::Callback<mindLifetimeMgmtOpCbFn> callback);
|
||||
void finalizeReq(sscl::Callback<mindLifetimeMgmtOpCbFn> callback);
|
||||
mrntt::MrnttViralNonPostingInvokerT<bool> initializeCReq();
|
||||
mrntt::MrnttViralNonPostingInvokerT<bool> finalizeCReq();
|
||||
|
||||
// ComponentThread access methods
|
||||
std::shared_ptr<MindThread> getComponentThread(sscl::ThreadId id) const;
|
||||
@@ -46,9 +44,6 @@ public:
|
||||
private:
|
||||
friend class body::Body;
|
||||
bool bodyComponentInitialized = false;
|
||||
|
||||
private:
|
||||
class MindLifetimeMgmtOp;
|
||||
};
|
||||
|
||||
namespace mind {
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
#ifndef SMO_SIMULATOR_THREAD_H
|
||||
#define SMO_SIMULATOR_THREAD_H
|
||||
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <spinscale/co/invokers.h>
|
||||
#include <spinscale/co/postingPromise.h>
|
||||
|
||||
namespace smo {
|
||||
namespace simulator {
|
||||
|
||||
struct SimulatorThreadTag
|
||||
{
|
||||
static boost::asio::io_service &io_service();
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using SimulatorPostingPromise =
|
||||
sscl::co::TaggedPostingPromise<T, SimulatorThreadTag>;
|
||||
|
||||
template <typename T>
|
||||
using SimulatorViralPostingInvoker =
|
||||
sscl::co::ViralPostingInvoker<SimulatorPostingPromise, T>;
|
||||
|
||||
} // namespace simulator
|
||||
} // namespace smo
|
||||
|
||||
#endif // SMO_SIMULATOR_THREAD_H
|
||||
@@ -8,7 +8,8 @@
|
||||
#include <dlfcn.h>
|
||||
#include <functional>
|
||||
#include <user/senseApiDesc.h>
|
||||
#include <spinscale/qutex.h>
|
||||
#include <spinscale/co/coQutex.h>
|
||||
#include <spinscale/sharedResourceGroup.h>
|
||||
|
||||
namespace smo {
|
||||
namespace stim_buff {
|
||||
@@ -31,10 +32,11 @@ public:
|
||||
StimBuffApiLib(
|
||||
const std::string& path, void *_dlopen_handle,
|
||||
SMO_GET_STIM_BUFF_API_DESC_FN_TYPEDEF *descFn)
|
||||
: libraryPath(path), qutex("StimBuffApiLib-" + path),
|
||||
: libraryPath(path),
|
||||
isBeingDestroyed(false),
|
||||
dlopen_handle(_dlopen_handle, DlCloser()),
|
||||
SMO_GET_STIM_BUFF_API_DESC_FN_NAME(descFn)
|
||||
SMO_GET_STIM_BUFF_API_DESC_FN_NAME(descFn),
|
||||
s("StimBuffApiLib-" + path)
|
||||
{}
|
||||
|
||||
void setStimBuffApiDesc(const StimBuffApiDesc &desc)
|
||||
@@ -51,7 +53,6 @@ public:
|
||||
|
||||
public:
|
||||
std::string libraryPath;
|
||||
sscl::Qutex qutex;
|
||||
std::atomic<bool> isBeingDestroyed;
|
||||
std::unique_ptr<void, DlCloser> dlopen_handle;
|
||||
/* UNIMPLEMENTED: API-specific cmdline options. These affect this specific
|
||||
@@ -77,6 +78,11 @@ public:
|
||||
*/
|
||||
StimBuffApiDesc stimBuffApiDesc;
|
||||
|
||||
struct StimBuffApiLibResources
|
||||
{};
|
||||
|
||||
sscl::SharedResourceGroup<sscl::co::CoQutex, StimBuffApiLibResources> s;
|
||||
|
||||
std::string stringify() const {
|
||||
std::string result = "Library Path: " + libraryPath + "\n";
|
||||
result += "Stim Buff API Descriptor: " + stimBuffApiDesc.stringify() + "\n";
|
||||
|
||||
@@ -7,11 +7,10 @@
|
||||
#include <string>
|
||||
#include <optional>
|
||||
#include <functional>
|
||||
#include <spinscale/asynchronousLoop.h>
|
||||
#include <stimBuffApis/stimBuffApiLib.h>
|
||||
#include <user/deviceAttachmentSpec.h>
|
||||
#include <spinscale/callback.h>
|
||||
#include <spinscale/qutex.h>
|
||||
#include <spinscale/co/coQutex.h>
|
||||
#include <spinscale/sharedResourceGroup.h>
|
||||
|
||||
namespace smo {
|
||||
namespace stim_buff {
|
||||
@@ -19,6 +18,11 @@ namespace stim_buff {
|
||||
class StimBuffApiManager
|
||||
{
|
||||
public:
|
||||
struct Resources
|
||||
{
|
||||
std::vector<std::shared_ptr<StimBuffApiLib>> stimBuffApiLibs;
|
||||
};
|
||||
|
||||
static StimBuffApiManager& getInstance()
|
||||
{
|
||||
static StimBuffApiManager instance;
|
||||
@@ -54,17 +58,16 @@ public:
|
||||
|
||||
private:
|
||||
StimBuffApiManager()
|
||||
: qutex("StimBuffApiManager")
|
||||
: s("StimBuffApiManager")
|
||||
{}
|
||||
|
||||
~StimBuffApiManager() = default;
|
||||
|
||||
StimBuffApiManager(const StimBuffApiManager&) = delete;
|
||||
StimBuffApiManager& operator=(const StimBuffApiManager&) = delete;
|
||||
|
||||
std::vector<std::shared_ptr<StimBuffApiLib>> stimBuffApiLibs;
|
||||
|
||||
public:
|
||||
sscl::Qutex qutex;
|
||||
sscl::SharedResourceGroup<sscl::co::CoQutex, Resources> s;
|
||||
|
||||
public:
|
||||
static std::optional<std::string> searchForLibInSmoSearchPaths(
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
#ifndef SMO_SUBCONSCIOUS_THREAD_H
|
||||
#define SMO_SUBCONSCIOUS_THREAD_H
|
||||
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <spinscale/co/invokers.h>
|
||||
#include <spinscale/co/postingPromise.h>
|
||||
|
||||
namespace smo {
|
||||
|
||||
struct SubconsciousThreadTag
|
||||
{
|
||||
static boost::asio::io_service &io_service();
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using SubconsciousPostingPromise =
|
||||
sscl::co::TaggedPostingPromise<T, SubconsciousThreadTag>;
|
||||
|
||||
template <typename T>
|
||||
using SubconsciousViralPostingInvoker =
|
||||
sscl::co::ViralPostingInvoker<SubconsciousPostingPromise, T>;
|
||||
|
||||
} // namespace smo
|
||||
|
||||
#endif // SMO_SUBCONSCIOUS_THREAD_H
|
||||
@@ -0,0 +1,25 @@
|
||||
#ifndef SMO_WORLD_THREAD_H
|
||||
#define SMO_WORLD_THREAD_H
|
||||
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <spinscale/co/invokers.h>
|
||||
#include <spinscale/co/postingPromise.h>
|
||||
|
||||
namespace smo {
|
||||
|
||||
struct WorldThreadTag
|
||||
{
|
||||
static boost::asio::io_service &io_service();
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using WorldPostingPromise =
|
||||
sscl::co::TaggedPostingPromise<T, WorldThreadTag>;
|
||||
|
||||
template <typename T>
|
||||
using WorldViralPostingInvoker =
|
||||
sscl::co::ViralPostingInvoker<WorldPostingPromise, T>;
|
||||
|
||||
} // namespace smo
|
||||
|
||||
#endif // SMO_WORLD_THREAD_H
|
||||
+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
|
||||
|
||||
+11
-10
@@ -33,9 +33,8 @@ void marionetteInitializeReqCb(bool success)
|
||||
std::cerr << __func__ << ": Failed to initialize Marionette. Shutting down."
|
||||
<< '\n';
|
||||
|
||||
mrntt.finalizeReq({nullptr, std::bind(
|
||||
&smo::mrntt::marionetteFinalizeReqCb,
|
||||
std::placeholders::_1)});
|
||||
mrntt.holdFinalizeCReq(
|
||||
[]() { marionetteFinalizeReqCb(true); });
|
||||
}
|
||||
|
||||
void marionetteFinalizeReqCb(bool success)
|
||||
@@ -83,9 +82,8 @@ void MarionetteComponent::postJoltHook()
|
||||
default:
|
||||
break;
|
||||
}
|
||||
mrntt.finalizeReq({nullptr, std::bind(
|
||||
&marionetteFinalizeReqCb,
|
||||
std::placeholders::_1)});
|
||||
mrntt.holdFinalizeCReq(
|
||||
[]() { marionetteFinalizeReqCb(true); });
|
||||
});
|
||||
}
|
||||
|
||||
@@ -110,7 +108,7 @@ void MarionetteComponent::tryBlock1Hook()
|
||||
|
||||
void MarionetteComponent::preLoopHook()
|
||||
{
|
||||
/** EXPLANATION:
|
||||
/** EXPLANATION:
|
||||
* Initialize Salmanoff's Manager classes first.
|
||||
* Manager classes' initialization is synchronous in nature, so we
|
||||
* don't need the minds to be running to initialize them.
|
||||
@@ -131,9 +129,12 @@ void MarionetteComponent::preLoopHook()
|
||||
smo::initializeSalmanoff();
|
||||
callShutdownSalmanoff = true;
|
||||
|
||||
initializeReq(sscl::Callback<mrnttLifetimeMgmtOpCbFn>{
|
||||
nullptr,
|
||||
std::bind(&marionetteInitializeReqCb, std::placeholders::_1)});
|
||||
holdInitializeCReq(
|
||||
[]
|
||||
{
|
||||
marionetteInitializeReqCb(
|
||||
!mrntt.initializeLifetimeExceptionPtr);
|
||||
});
|
||||
|
||||
std::cout << "PuppeteerThread::main: Entering event loop" << "\n";
|
||||
}
|
||||
|
||||
+42
-152
@@ -2,11 +2,6 @@
|
||||
#include <iostream>
|
||||
#include <opts.h>
|
||||
#include <componentThread.h>
|
||||
#include <spinscale/asynchronousContinuation.h>
|
||||
#include <spinscale/asynchronousLoop.h>
|
||||
#include <spinscale/callback.h>
|
||||
#include <spinscale/callableTracer.h>
|
||||
#include <spinscale/componentThread.h>
|
||||
#include <mind.h>
|
||||
#include <mindThread.h>
|
||||
#include <director/director.h>
|
||||
@@ -63,17 +58,17 @@ Mind::getComponentThread(sscl::ThreadId id) const
|
||||
"getComponentThread");
|
||||
}
|
||||
|
||||
// Search through the vector for the thread with matching id
|
||||
for (auto& thread : componentThreads)
|
||||
// Search through the vector for the thread with matching id
|
||||
for (auto& thread : componentThreads)
|
||||
{
|
||||
if (thread->id == id) {
|
||||
if (thread->id == id) {
|
||||
return std::static_pointer_cast<MindThread>(thread);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Throw exception if no thread found
|
||||
throw std::runtime_error(std::string(__func__) +
|
||||
": No MindThread found with ID "
|
||||
// Throw exception if no thread found
|
||||
throw std::runtime_error(std::string(__func__) +
|
||||
": No MindThread found with ID "
|
||||
+ std::to_string(static_cast<int>(id)));
|
||||
}
|
||||
|
||||
@@ -88,16 +83,16 @@ Mind::getComponentThread(const std::string& name) const
|
||||
"getComponentThread");
|
||||
}
|
||||
|
||||
for (auto& thread : componentThreads)
|
||||
for (auto& thread : componentThreads)
|
||||
{
|
||||
if (thread->name == name) {
|
||||
if (thread->name == name) {
|
||||
return std::static_pointer_cast<MindThread>(thread);
|
||||
}
|
||||
}
|
||||
|
||||
// Throw exception if no thread found
|
||||
throw std::runtime_error(std::string(__func__) +
|
||||
": No MindThread found with name '" + name + "'");
|
||||
// Throw exception if no thread found
|
||||
throw std::runtime_error(std::string(__func__) +
|
||||
": No MindThread found with name '" + name + "'");
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<MindThread>>
|
||||
@@ -111,152 +106,47 @@ Mind::getMindThreads() const
|
||||
return mindThreads;
|
||||
}
|
||||
|
||||
class Mind::MindLifetimeMgmtOp
|
||||
: public sscl::PostedAsynchronousContinuation<mindLifetimeMgmtOpCbFn>
|
||||
mrntt::MrnttViralNonPostingInvokerT<bool> Mind::initializeCReq()
|
||||
{
|
||||
public:
|
||||
MindLifetimeMgmtOp(
|
||||
Mind &parent, const std::shared_ptr<sscl::ComponentThread> &caller,
|
||||
sscl::Callback<mindLifetimeMgmtOpCbFn> callback)
|
||||
: sscl::PostedAsynchronousContinuation<mindLifetimeMgmtOpCbFn>(
|
||||
caller, callback),
|
||||
parent(parent)
|
||||
{}
|
||||
|
||||
public:
|
||||
Mind &parent;
|
||||
|
||||
public:
|
||||
void initializeReq1_posted(
|
||||
[[maybe_unused]] std::shared_ptr<MindLifetimeMgmtOp> context
|
||||
)
|
||||
try
|
||||
{
|
||||
/* Jolt the threads, then start them */
|
||||
parent.joltAllPuppetThreadsReq(
|
||||
{context, std::bind(
|
||||
&MindLifetimeMgmtOp::initializeReq2,
|
||||
context.get(), context)});
|
||||
distributeAndPinThreadsAcrossCpus();
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
std::cerr << "Salmanoff couldn't distribute the mind threads across "
|
||||
"the CPUs, so performance may be suboptimal.\n"
|
||||
"Error: " << e.what() << "\n";
|
||||
}
|
||||
|
||||
void initializeReq2(
|
||||
[[maybe_unused]] std::shared_ptr<MindLifetimeMgmtOp> context
|
||||
)
|
||||
{
|
||||
std::cout << "Mrntt: All mind threads JOLTed." << "\n";
|
||||
co_await joltAllPuppetThreadsCReq();
|
||||
std::cout << "Mrntt: All mind threads JOLTed." << "\n";
|
||||
|
||||
parent.startAllPuppetThreadsReq(
|
||||
{context, std::bind(
|
||||
&MindLifetimeMgmtOp::initializeReq3,
|
||||
context.get(), context)});
|
||||
}
|
||||
co_await startAllPuppetThreadsCReq();
|
||||
std::cout << "Mrntt: All mind threads started." << "\n";
|
||||
|
||||
void initializeReq3(
|
||||
[[maybe_unused]] std::shared_ptr<MindLifetimeMgmtOp> context
|
||||
)
|
||||
{
|
||||
std::cout << "Mrntt: All mind threads started." << "\n";
|
||||
bool bodyInitialized = co_await body.initializeCReq();
|
||||
std::cout << "Mrntt: Body component initialized." << "\n";
|
||||
|
||||
parent.body.initializeReq(
|
||||
{context, std::bind(
|
||||
&MindLifetimeMgmtOp::initializeReq4,
|
||||
context.get(), context, std::placeholders::_1)});
|
||||
}
|
||||
|
||||
void initializeReq4(
|
||||
[[maybe_unused]] std::shared_ptr<MindLifetimeMgmtOp> context,
|
||||
bool success
|
||||
)
|
||||
{
|
||||
std::cout << "Mrntt: Body component initialized." << "\n";
|
||||
callOriginalCb(success);
|
||||
}
|
||||
|
||||
void finalizeReq1_posted(
|
||||
[[maybe_unused]] std::shared_ptr<MindLifetimeMgmtOp> context
|
||||
)
|
||||
{
|
||||
parent.body.finalizeReq(
|
||||
{context, std::bind(
|
||||
&MindLifetimeMgmtOp::finalizeReq2,
|
||||
context.get(), context, std::placeholders::_1)});
|
||||
}
|
||||
|
||||
void finalizeReq2(
|
||||
[[maybe_unused]] std::shared_ptr<MindLifetimeMgmtOp> context,
|
||||
bool success
|
||||
)
|
||||
{
|
||||
if (!success) {
|
||||
std::cerr << "Mrntt: Body component failed to finalize." << "\n";
|
||||
} else {
|
||||
std::cout << "Mrntt: Body component finalized." << "\n";
|
||||
}
|
||||
|
||||
/* If the threads haven't been jolted, we need to do that first, because
|
||||
* otherwise they'll just enter their main loops and wait for control
|
||||
* messages from mrntt after processing the exit request.
|
||||
*/
|
||||
parent.joltAllPuppetThreadsReq(
|
||||
{context, std::bind(
|
||||
&MindLifetimeMgmtOp::finalizeReq3,
|
||||
context.get(), context)});
|
||||
}
|
||||
|
||||
void finalizeReq3(
|
||||
[[maybe_unused]] std::shared_ptr<MindLifetimeMgmtOp> context
|
||||
)
|
||||
{
|
||||
std::cout << "Mrntt: All mind threads JOLTed for finalization." << "\n";
|
||||
|
||||
parent.exitAllPuppetThreadsReq(
|
||||
{context, std::bind(
|
||||
&MindLifetimeMgmtOp::finalizeReq4,
|
||||
context.get(), context)});
|
||||
}
|
||||
|
||||
void finalizeReq4(
|
||||
[[maybe_unused]] std::shared_ptr<MindLifetimeMgmtOp> context
|
||||
)
|
||||
{
|
||||
std::cout << "Mrntt: All mind threads exited." << "\n";
|
||||
callOriginalCb(true);
|
||||
}
|
||||
};
|
||||
|
||||
void Mind::initializeReq(sscl::Callback<mindLifetimeMgmtOpCbFn> callback)
|
||||
{
|
||||
/* Distribute threads across available CPUs */
|
||||
try
|
||||
{
|
||||
distributeAndPinThreadsAcrossCpus();
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
std::cerr << "Salmanoff couldn't distribute the mind threads across "
|
||||
"the CPUs, so performance may be suboptimal.\n"
|
||||
"Error: " << e.what() << "\n";
|
||||
}
|
||||
|
||||
const auto& caller = sscl::ComponentThread::getSelf();
|
||||
auto request = std::make_shared<MindLifetimeMgmtOp>(
|
||||
*this, caller, callback);
|
||||
|
||||
mrntt::mrntt.thread->getIoService().post(
|
||||
STC(std::bind(
|
||||
&MindLifetimeMgmtOp::initializeReq1_posted,
|
||||
request.get(), request)));
|
||||
co_return bodyInitialized;
|
||||
}
|
||||
|
||||
void Mind::finalizeReq(sscl::Callback<mindLifetimeMgmtOpCbFn> callback)
|
||||
mrntt::MrnttViralNonPostingInvokerT<bool> Mind::finalizeCReq()
|
||||
{
|
||||
const auto& caller = sscl::ComponentThread::getSelf();
|
||||
auto request = std::make_shared<MindLifetimeMgmtOp>(
|
||||
*this, caller, callback);
|
||||
bool bodyFinalized = co_await body.finalizeCReq();
|
||||
if (!bodyFinalized) {
|
||||
std::cerr << "Mrntt: Body component failed to finalize." << "\n";
|
||||
} else {
|
||||
std::cout << "Mrntt: Body component finalized." << "\n";
|
||||
}
|
||||
|
||||
mrntt::mrntt.thread->getIoService().post(
|
||||
STC(std::bind(
|
||||
&MindLifetimeMgmtOp::finalizeReq1_posted,
|
||||
request.get(), request)));
|
||||
co_await joltAllPuppetThreadsCReq();
|
||||
std::cout << "Mrntt: All mind threads JOLTed for finalization." << "\n";
|
||||
|
||||
co_await exitAllPuppetThreadsCReq();
|
||||
std::cout << "Mrntt: All mind threads exited." << "\n";
|
||||
|
||||
co_return bodyFinalized;
|
||||
}
|
||||
|
||||
} // namespace smo
|
||||
|
||||
+2
-2
@@ -7,7 +7,7 @@
|
||||
#include <sys/stat.h>
|
||||
#include <sstream>
|
||||
#include <opts.h>
|
||||
#include <spinscale/callableTracer.h>
|
||||
#include <spinscale/cps/callableTracer.h>
|
||||
|
||||
|
||||
OptionParser::Exception::Exception(std::string message_)
|
||||
@@ -107,7 +107,7 @@ void OptionParser::parseArguments(int argc, char *argv[], char **envp)
|
||||
}
|
||||
}
|
||||
|
||||
sscl::CallableTracer::optTraceCallables = traceCallables;
|
||||
sscl::cps::CallableTracer::optTraceCallables = traceCallables;
|
||||
}
|
||||
|
||||
std::string OptionParser::getUsage() const
|
||||
|
||||
@@ -5,10 +5,6 @@
|
||||
#include <stimBuffApis/stimBuffApiManager.h>
|
||||
#include <stimBuffApis/stimBuffApiLib.h>
|
||||
#include <opts.h>
|
||||
#include <spinscale/asynchronousBridge.h>
|
||||
#include <spinscale/asynchronousContinuation.h>
|
||||
#include <spinscale/asynchronousLoop.h>
|
||||
#include <spinscale/callback.h>
|
||||
#include <user/senseApiDesc.h>
|
||||
#include <mind.h>
|
||||
#include <deviceManager/deviceManager.h>
|
||||
@@ -198,47 +194,50 @@ StimBuffApiLib& StimBuffApiManager::loadStimBuffApiLib(
|
||||
auto lib = std::make_shared<StimBuffApiLib>(
|
||||
libraryPath, dlopen_handle.release(), func);
|
||||
lib->setStimBuffApiDesc(libApiDesc);
|
||||
stimBuffApiLibs.push_back(lib);
|
||||
return *stimBuffApiLibs.back();
|
||||
getInstance().s.rsrc.stimBuffApiLibs.push_back(lib);
|
||||
return *getInstance().s.rsrc.stimBuffApiLibs.back();
|
||||
}
|
||||
|
||||
std::optional<std::shared_ptr<StimBuffApiLib>>
|
||||
StimBuffApiManager::getStimBuffApiLib(const std::string& libraryPath)
|
||||
{
|
||||
auto it = std::find_if(stimBuffApiLibs.begin(), stimBuffApiLibs.end(),
|
||||
auto &libs = getInstance().s.rsrc.stimBuffApiLibs;
|
||||
auto it = std::find_if(libs.begin(), libs.end(),
|
||||
[&libPath = libraryPath](const std::shared_ptr<StimBuffApiLib>& lib) {
|
||||
return lib->libraryPath == libPath;
|
||||
}
|
||||
);
|
||||
|
||||
if (it != stimBuffApiLibs.end()) { return *it; }
|
||||
if (it != libs.end()) { return *it; }
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::shared_ptr<StimBuffApiLib>>
|
||||
StimBuffApiManager::getStimBuffApiLibByApiName(const std::string& apiName)
|
||||
{
|
||||
auto it = std::find_if(stimBuffApiLibs.begin(), stimBuffApiLibs.end(),
|
||||
auto &libs = getInstance().s.rsrc.stimBuffApiLibs;
|
||||
auto it = std::find_if(libs.begin(), libs.end(),
|
||||
[&apiName](const std::shared_ptr<StimBuffApiLib>& lib) {
|
||||
return lib->stimBuffApiDesc.name == apiName;
|
||||
}
|
||||
);
|
||||
|
||||
if (it != stimBuffApiLibs.end()) { return *it; }
|
||||
if (it != libs.end()) { return *it; }
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
void StimBuffApiManager::unloadStimBuffApiLib(const std::string& libraryPath)
|
||||
{
|
||||
auto it = std::find_if(stimBuffApiLibs.begin(), stimBuffApiLibs.end(),
|
||||
auto &libs = getInstance().s.rsrc.stimBuffApiLibs;
|
||||
auto it = std::find_if(libs.begin(), libs.end(),
|
||||
[&lpath = libraryPath](const std::shared_ptr<StimBuffApiLib>& lib) {
|
||||
return lib->libraryPath == lpath;
|
||||
}
|
||||
);
|
||||
|
||||
if (it != stimBuffApiLibs.end())
|
||||
if (it != libs.end())
|
||||
{
|
||||
stimBuffApiLibs.erase(it);
|
||||
libs.erase(it);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -248,7 +247,7 @@ void StimBuffApiManager::unloadStimBuffApiLib(const std::string& libraryPath)
|
||||
|
||||
void StimBuffApiManager::unloadAllStimBuffApiLibs(void)
|
||||
{
|
||||
stimBuffApiLibs.clear();
|
||||
getInstance().s.rsrc.stimBuffApiLibs.clear();
|
||||
}
|
||||
|
||||
void StimBuffApiManager::loadAllStimBuffApiLibsFromOptions(
|
||||
@@ -264,7 +263,7 @@ void StimBuffApiManager::loadAllStimBuffApiLibsFromOptions(
|
||||
std::string StimBuffApiManager::stringifyLibs() const
|
||||
{
|
||||
std::string result;
|
||||
for (const auto& lib : stimBuffApiLibs) {
|
||||
for (const auto& lib : getInstance().s.rsrc.stimBuffApiLibs) {
|
||||
result += lib->stringify() + "\n";
|
||||
}
|
||||
return result;
|
||||
@@ -303,14 +302,14 @@ void StimBuffApiManager::finalizeStimBuffApiLib(StimBuffApiLib& lib)
|
||||
|
||||
void StimBuffApiManager::initializeAllStimBuffApiLibs(void)
|
||||
{
|
||||
for (auto& lib : stimBuffApiLibs) {
|
||||
for (auto& lib : getInstance().s.rsrc.stimBuffApiLibs) {
|
||||
initializeStimBuffApiLib(*lib);
|
||||
}
|
||||
}
|
||||
|
||||
void StimBuffApiManager::finalizeAllStimBuffApiLibs(void)
|
||||
{
|
||||
for (auto& lib : stimBuffApiLibs) {
|
||||
for (auto& lib : getInstance().s.rsrc.stimBuffApiLibs) {
|
||||
finalizeStimBuffApiLib(*lib);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user