Add Mrntt component; init globalMind in mrntt.initializeReq
This makes the initialization sequence much cleaner and conceptually well encapsulated. We also now dynamically allocate the Mind objects. They're allocated dynamically by Mrntt inside of initializeReq. This means that we no longer have to worry about jolting and cleaning up the running threads of global mind object even when we never explicitly called Mind.initializeReq. Along with other conceptual improvements to our abstractions, this patch also gets us to a real "end of program initialization" point for the first time.
This commit is contained in:
+20
-173
@@ -4,6 +4,8 @@
|
||||
#include <asynchronousLoop.h>
|
||||
#include <mind.h>
|
||||
#include <componentThread.h>
|
||||
#include <director/director.h>
|
||||
#include <simulator/simulator.h>
|
||||
#include <senseApis/senseApiManager.h>
|
||||
|
||||
namespace smo {
|
||||
@@ -13,9 +15,22 @@ Mind::Mind(void)
|
||||
std::make_shared<MindThread>(ComponentThread::DIRECTOR, *this),
|
||||
std::make_shared<MindThread>(ComponentThread::SIMULATOR, *this),
|
||||
std::make_shared<MindThread>(ComponentThread::SUBCONSCIOUS, *this),
|
||||
std::make_shared<MindThread>(ComponentThread::BODY, *this),
|
||||
std::make_shared<MindThread>(ComponentThread::WORLD, *this)
|
||||
}
|
||||
std::make_shared<MindThread>(ComponentThread::BODY, *this)
|
||||
#ifndef WORLD_USE_BODY_THREAD
|
||||
, std::make_shared<MindThread>(ComponentThread::WORLD, *this)
|
||||
#endif
|
||||
},
|
||||
director(*this, componentThreads[0]),
|
||||
canvas(*this, componentThreads[1]),
|
||||
subconscious(*this, componentThreads[2]),
|
||||
body(*this, componentThreads[3]),
|
||||
world(*this,
|
||||
#ifndef WORLD_USE_BODY_THREAD
|
||||
componentThreads[4]
|
||||
#else
|
||||
componentThreads[3]
|
||||
#endif
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -106,7 +121,7 @@ public:
|
||||
{
|
||||
std::cout << "Mrntt: All mind threads started." << "\n";
|
||||
|
||||
parent.initializeBodyReq(
|
||||
parent.body.initializeReq(
|
||||
std::bind(
|
||||
&MindLifetimeMgmtOp::initializeReq3,
|
||||
context.get(), context, std::placeholders::_1));
|
||||
@@ -192,180 +207,12 @@ void Mind::finalizeReq(mindLifetimeMgmtOpCbFn callback)
|
||||
auto request = std::make_shared<MindLifetimeMgmtOp>(
|
||||
*this, callback);
|
||||
|
||||
finalizeBodyReq(
|
||||
body.finalizeReq(
|
||||
std::bind(
|
||||
&MindLifetimeMgmtOp::finalizeReq1,
|
||||
request.get(), request, std::placeholders::_1));
|
||||
}
|
||||
|
||||
class Mind::InitializeBodyReq
|
||||
: public MindLifetimeMgmtOp, public ContinuationTarget
|
||||
{
|
||||
public:
|
||||
InitializeBodyReq(
|
||||
Mind &parent, const std::shared_ptr<ComponentThread> &caller,
|
||||
mindLifetimeMgmtOpCbFn callback)
|
||||
: MindLifetimeMgmtOp(parent, callback), ContinuationTarget(caller)
|
||||
{}
|
||||
|
||||
void callOriginalCbFn(bool success)
|
||||
{
|
||||
if (originalCbFn)
|
||||
{
|
||||
caller->getIoService().post(
|
||||
std::bind(originalCbFn, success));
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
void initializeBodyReq1(
|
||||
[[maybe_unused]] std::shared_ptr<InitializeBodyReq> context
|
||||
)
|
||||
{
|
||||
auto self = ComponentThread::getSelf();
|
||||
if (self->id != ComponentThread::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.
|
||||
*
|
||||
* Right now we use Marionette, but there's a strong argument for using
|
||||
* Body instead since it's meant to handle device-management operations.
|
||||
*/
|
||||
sense_api::SenseApiManager::getInstance()
|
||||
.loadAllSenseApiLibsFromOptions(caller);
|
||||
|
||||
std::cout << sense_api::SenseApiManager::getInstance().stringifyLibs()
|
||||
<< std::endl;
|
||||
|
||||
if (OptionParser::getOptions().verbose)
|
||||
{
|
||||
std::cout << __func__ << ": About to initializeAllSenseApiLibs"
|
||||
<< '\n';
|
||||
}
|
||||
sense_api::SenseApiManager::getInstance().initializeAllSenseApiLibs();
|
||||
|
||||
if (OptionParser::getOptions().verbose)
|
||||
{
|
||||
std::cout << __func__ << ": About to attachAllSenseDevicesFromSpecs"
|
||||
<< '\n';
|
||||
}
|
||||
sense_api::SenseApiManager::getInstance()
|
||||
.attachAllSenseDevicesFromSpecsReq(
|
||||
std::bind(
|
||||
&InitializeBodyReq::initializeBodyReq2,
|
||||
context.get(), context,
|
||||
std::placeholders::_1));
|
||||
}
|
||||
|
||||
void initializeBodyReq2(
|
||||
[[maybe_unused]] std::shared_ptr<InitializeBodyReq> context,
|
||||
smo::AsynchronousLoop &results
|
||||
)
|
||||
{
|
||||
parent.bodyComponentInitialized = true;
|
||||
std::cout << "Mrntt: attached "
|
||||
<< results.nSucceeded << " of " << results.nTotal
|
||||
<< " sense devices." << "\n";
|
||||
|
||||
callOriginalCbFn(results.nSucceeded == results.nTotal);
|
||||
}
|
||||
};
|
||||
|
||||
class Mind::FinalizeBodyReq
|
||||
: public InitializeBodyReq
|
||||
{
|
||||
public:
|
||||
using InitializeBodyReq::InitializeBodyReq;
|
||||
|
||||
public:
|
||||
void finalizeBodyReq1(
|
||||
[[maybe_unused]] std::shared_ptr<FinalizeBodyReq> context
|
||||
)
|
||||
{
|
||||
auto self = ComponentThread::getSelf();
|
||||
if (self->id != ComponentThread::BODY)
|
||||
{
|
||||
throw std::runtime_error(std::string(__func__)
|
||||
+ ": Must be executed on Body thread");
|
||||
}
|
||||
|
||||
std::cout << "Mrntt: About to detach all sense devices." << "\n";
|
||||
sense_api::SenseApiManager::getInstance().detachAllSenseDevicesReq(
|
||||
std::bind(
|
||||
&FinalizeBodyReq::finalizeBodyReq2,
|
||||
context.get(), context,
|
||||
std::placeholders::_1));
|
||||
}
|
||||
|
||||
void finalizeBodyReq2(
|
||||
[[maybe_unused]] std::shared_ptr<FinalizeBodyReq> context,
|
||||
smo::AsynchronousLoop &results
|
||||
)
|
||||
{
|
||||
std::cout << "Mrntt: Successfully detached "
|
||||
<< results.nSucceeded << " of " << results.nTotal
|
||||
<< " sense devices." << "\n";
|
||||
|
||||
std::cout << "Mrntt: About to unload all sense api libs." << "\n";
|
||||
sense_api::SenseApiManager::getInstance().unloadAllSenseApiLibs();
|
||||
callOriginalCbFn(results.nSucceeded == results.nTotal);
|
||||
}
|
||||
};
|
||||
|
||||
void Mind::initializeBodyReq(mindLifetimeMgmtOpCbFn callback)
|
||||
{
|
||||
auto mrntt = ComponentThread::getSelf();
|
||||
|
||||
if (mrntt->id != ComponentThread::MRNTT)
|
||||
{
|
||||
throw std::runtime_error(std::string(__func__)
|
||||
+ ": Must be invoked by Mrntt thread");
|
||||
}
|
||||
|
||||
auto request = std::make_shared<InitializeBodyReq>(
|
||||
*this, mrntt, callback);
|
||||
|
||||
this->getComponentThread(ComponentThread::BODY)->getIoService().post(
|
||||
std::bind(
|
||||
&InitializeBodyReq::initializeBodyReq1,
|
||||
request.get(), request));
|
||||
}
|
||||
|
||||
void Mind::finalizeBodyReq(mindLifetimeMgmtOpCbFn callback)
|
||||
{
|
||||
auto mrntt = ComponentThread::getSelf();
|
||||
|
||||
if (mrntt->id != ComponentThread::MRNTT)
|
||||
{
|
||||
throw std::runtime_error(std::string(__func__)
|
||||
+ ": Must be invoked by Mrntt thread");
|
||||
}
|
||||
|
||||
if (!bodyComponentInitialized)
|
||||
{
|
||||
std::cout << "Mrntt: Body component not initialized. "
|
||||
<< "Skipping finalization." << "\n";
|
||||
callback(true);
|
||||
return;
|
||||
}
|
||||
|
||||
auto request = std::make_shared<FinalizeBodyReq>(
|
||||
*this, mrntt, callback);
|
||||
|
||||
this->getComponentThread(ComponentThread::BODY)->getIoService().post(
|
||||
std::bind(
|
||||
&FinalizeBodyReq::finalizeBodyReq1,
|
||||
request.get(), request));
|
||||
}
|
||||
|
||||
void Mind::distributeAndPinThreadsAcrossCpus()
|
||||
{
|
||||
int cpuCount = ComponentThread::getAvailableCpuCount();
|
||||
|
||||
Reference in New Issue
Block a user