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:
@@ -22,10 +22,15 @@ if(NOT MIND_VOSCILLATOR_PERIOD_MS GREATER 0)
|
|||||||
endif()
|
endif()
|
||||||
math(EXPR MIND_VOSCILLATOR_FREQ_MS "1000 / ${MIND_VOSCILLATOR_PERIOD_MS}")
|
math(EXPR MIND_VOSCILLATOR_FREQ_MS "1000 / ${MIND_VOSCILLATOR_PERIOD_MS}")
|
||||||
|
|
||||||
|
# World thread configuration
|
||||||
|
option(WORLD_USE_BODY_THREAD
|
||||||
|
"Use body thread for world component instead of separate world thread" OFF)
|
||||||
|
|
||||||
# Configure config.h
|
# Configure config.h
|
||||||
configure_file(
|
configure_file(
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/include/config.h.in
|
${CMAKE_CURRENT_SOURCE_DIR}/include/config.h.in
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/include/config.h
|
${CMAKE_CURRENT_BINARY_DIR}/include/config.h
|
||||||
|
@ONLY
|
||||||
)
|
)
|
||||||
|
|
||||||
# Include directories
|
# Include directories
|
||||||
|
|||||||
@@ -9,6 +9,9 @@
|
|||||||
#define CONFIG_MIND_VOSCILLATOR_PERIOD_MS @MIND_VOSCILLATOR_PERIOD_MS@
|
#define CONFIG_MIND_VOSCILLATOR_PERIOD_MS @MIND_VOSCILLATOR_PERIOD_MS@
|
||||||
#define CONFIG_MIND_VOSCILLATOR_FREQ_MS @MIND_VOSCILLATOR_FREQ_MS@
|
#define CONFIG_MIND_VOSCILLATOR_FREQ_MS @MIND_VOSCILLATOR_FREQ_MS@
|
||||||
|
|
||||||
|
/* World thread configuration */
|
||||||
|
#cmakedefine WORLD_USE_BODY_THREAD
|
||||||
|
|
||||||
/* Cross-compilation configuration */
|
/* Cross-compilation configuration */
|
||||||
#cmakedefine CMAKE_CROSSCOMPILING
|
#cmakedefine CMAKE_CROSSCOMPILING
|
||||||
|
|
||||||
|
|||||||
@@ -10,17 +10,17 @@ int main(int argc, char *argv[], char *envp[])
|
|||||||
*/
|
*/
|
||||||
std::cout << "CRT:" << __func__ << ": about to JOLT Mrntt with cmdline args"
|
std::cout << "CRT:" << __func__ << ": about to JOLT Mrntt with cmdline args"
|
||||||
<< '\n';
|
<< '\n';
|
||||||
smo::mrntt::mrntt->getIoService().post(
|
smo::mrntt::thread->getIoService().post(
|
||||||
[argc, argv, envp]()
|
[argc, argv, envp]()
|
||||||
{
|
{
|
||||||
std::cout << "Mrntt:" << __func__ << ":JOLTED: setting cmdline args"
|
std::cout << "Mrntt:" << __func__ << ":JOLTED: setting cmdline args"
|
||||||
<< '\n';
|
<< '\n';
|
||||||
smo::CrtCommandLineArgs::set(argc, argv, envp);
|
smo::CrtCommandLineArgs::set(argc, argv, envp);
|
||||||
smo::mrntt::mrntt->getIoService().stop();
|
smo::mrntt::thread->getIoService().stop();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
smo::mrntt::mrntt->thread.join();
|
smo::mrntt::thread->thread.join();
|
||||||
std::cout << "CRT:" << __func__ << ": Mrntt exited with code '"
|
std::cout << "CRT:" << __func__ << ": Mrntt exited with code '"
|
||||||
<< smo::mrntt::exitCode << "'\n";
|
<< smo::mrntt::exitCode << "'\n";
|
||||||
return smo::mrntt::exitCode;
|
return smo::mrntt::exitCode;
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ add_library(smocore STATIC
|
|||||||
mind.cpp
|
mind.cpp
|
||||||
opts.cpp
|
opts.cpp
|
||||||
componentThread.cpp
|
componentThread.cpp
|
||||||
|
component.cpp
|
||||||
|
body/body.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
target_include_directories(smocore PUBLIC
|
target_include_directories(smocore PUBLIC
|
||||||
@@ -12,8 +14,9 @@ target_include_directories(smocore PUBLIC
|
|||||||
# Link against pthread for CPU affinity functions
|
# Link against pthread for CPU affinity functions
|
||||||
find_package(Threads REQUIRED)
|
find_package(Threads REQUIRED)
|
||||||
target_link_libraries(smocore
|
target_link_libraries(smocore
|
||||||
PRIVATE Threads::Threads senseApis)
|
PRIVATE Threads::Threads senseApis mindManager)
|
||||||
|
|
||||||
add_subdirectory(marionette)
|
add_subdirectory(marionette)
|
||||||
add_subdirectory(deviceManager)
|
add_subdirectory(deviceManager)
|
||||||
add_subdirectory(senseApis)
|
add_subdirectory(senseApis)
|
||||||
|
add_subdirectory(mindManager)
|
||||||
|
|||||||
@@ -0,0 +1,193 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <opts.h>
|
||||||
|
#include <asynchronousContinuation.h>
|
||||||
|
#include <asynchronousLoop.h>
|
||||||
|
#include <body/body.h>
|
||||||
|
#include <componentThread.h>
|
||||||
|
#include <mind.h>
|
||||||
|
#include <senseApis/senseApiManager.h>
|
||||||
|
|
||||||
|
namespace smo {
|
||||||
|
namespace body {
|
||||||
|
|
||||||
|
Body::Body(Mind &parent, const std::shared_ptr<ComponentThread> &thread)
|
||||||
|
: MindComponent(parent, thread)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
class Body::InitializeReq
|
||||||
|
: public AsynchronousContinuation<bodyLifetimeMgmtOpCbFn>,
|
||||||
|
public ContinuationTarget
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
InitializeReq(
|
||||||
|
Mind &parent, const std::shared_ptr<ComponentThread> &caller,
|
||||||
|
bodyLifetimeMgmtOpCbFn callback)
|
||||||
|
: AsynchronousContinuation<bodyLifetimeMgmtOpCbFn>(callback),
|
||||||
|
ContinuationTarget(caller),
|
||||||
|
parent(parent)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void callOriginalCbFn(bool success)
|
||||||
|
{
|
||||||
|
if (originalCbFn)
|
||||||
|
{
|
||||||
|
caller->getIoService().post(
|
||||||
|
std::bind(originalCbFn, success));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Mind &parent;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void initializeReq1(
|
||||||
|
[[maybe_unused]] std::shared_ptr<InitializeReq> 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(
|
||||||
|
&InitializeReq::initializeReq2,
|
||||||
|
context.get(), context,
|
||||||
|
std::placeholders::_1));
|
||||||
|
}
|
||||||
|
|
||||||
|
void initializeReq2(
|
||||||
|
[[maybe_unused]] std::shared_ptr<InitializeReq> 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 Body::FinalizeReq
|
||||||
|
: public InitializeReq
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using InitializeReq::InitializeReq;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void finalizeReq1(
|
||||||
|
[[maybe_unused]] std::shared_ptr<FinalizeReq> 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(
|
||||||
|
&FinalizeReq::finalizeReq2,
|
||||||
|
context.get(), context,
|
||||||
|
std::placeholders::_1));
|
||||||
|
}
|
||||||
|
|
||||||
|
void finalizeReq2(
|
||||||
|
[[maybe_unused]] std::shared_ptr<FinalizeReq> 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 Body::initializeReq(bodyLifetimeMgmtOpCbFn 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<InitializeReq>(
|
||||||
|
parent, mrntt, callback);
|
||||||
|
|
||||||
|
thread->getIoService().post(
|
||||||
|
std::bind(
|
||||||
|
&InitializeReq::initializeReq1,
|
||||||
|
request.get(), request));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Body::finalizeReq(bodyLifetimeMgmtOpCbFn callback)
|
||||||
|
{
|
||||||
|
auto mrntt = ComponentThread::getSelf();
|
||||||
|
|
||||||
|
if (mrntt->id != ComponentThread::MRNTT)
|
||||||
|
{
|
||||||
|
throw std::runtime_error(std::string(__func__)
|
||||||
|
+ ": Must be invoked by Mrntt thread");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!parent.bodyComponentInitialized)
|
||||||
|
{
|
||||||
|
std::cout << "Mrntt: Body component not initialized. "
|
||||||
|
<< "Skipping finalization." << "\n";
|
||||||
|
callback(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto request = std::make_shared<FinalizeReq>(
|
||||||
|
parent, mrntt, callback);
|
||||||
|
|
||||||
|
thread->getIoService().post(
|
||||||
|
std::bind(
|
||||||
|
&FinalizeReq::finalizeReq1,
|
||||||
|
request.get(), request));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace body
|
||||||
|
} // namespace smo
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
#include <component.h>
|
||||||
|
|
||||||
|
namespace smo {
|
||||||
|
|
||||||
|
Component::Component(const std::shared_ptr<ComponentThread> &thread)
|
||||||
|
: thread(thread)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
MindComponent::MindComponent(
|
||||||
|
Mind &parent, const std::shared_ptr<ComponentThread> &thread)
|
||||||
|
: Component(thread),
|
||||||
|
parent(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace mrntt {
|
||||||
|
|
||||||
|
MarionetteComponent::MarionetteComponent(
|
||||||
|
const std::shared_ptr<ComponentThread> &thread)
|
||||||
|
: Component(thread)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace mrntt
|
||||||
|
|
||||||
|
} // namespace smo
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <opts.h>
|
#include <opts.h>
|
||||||
#include <asynchronousContinuation.h>
|
#include <asynchronousContinuation.h>
|
||||||
#include <mind.h>
|
#include <mind.h>
|
||||||
|
#include <mindManager/mindManager.h>
|
||||||
#include <componentThread.h>
|
#include <componentThread.h>
|
||||||
#include <marionette/marionette.h>
|
#include <marionette/marionette.h>
|
||||||
|
|
||||||
@@ -16,7 +17,7 @@ thread_local std::shared_ptr<ComponentThread> thisComponentThread;
|
|||||||
// Implementation of static method
|
// Implementation of static method
|
||||||
std::shared_ptr<MarionetteThread> ComponentThread::getMrntt()
|
std::shared_ptr<MarionetteThread> ComponentThread::getMrntt()
|
||||||
{
|
{
|
||||||
return mrntt::mrntt;
|
return mrntt::thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MarionetteThread::initializeTls(void)
|
void MarionetteThread::initializeTls(void)
|
||||||
@@ -93,7 +94,7 @@ void MindThread::main(MindThread& self)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (sendExceptionInd)
|
if (sendExceptionInd)
|
||||||
{ mrntt::mrntt->exceptionInd(self.shared_from_this()); }
|
{ mrntt::thread->exceptionInd(self.shared_from_this()); }
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << self.name << ":" << __func__ << ": Exited event loop" << "\n";
|
std::cout << self.name << ":" << __func__ << ": Exited event loop" << "\n";
|
||||||
@@ -228,7 +229,7 @@ void MindThread::joltThreadReq(threadLifetimeMgmtOpCbFn callback)
|
|||||||
+ ": invoked on mrntt thread");
|
+ ": invoked on mrntt thread");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<MarionetteThread> mrntt = mrntt::mrntt;
|
std::shared_ptr<MarionetteThread> mrntt = mrntt::thread;
|
||||||
std::shared_ptr<MindThread> target = getParent().getComponentThread(id);
|
std::shared_ptr<MindThread> target = getParent().getComponentThread(id);
|
||||||
|
|
||||||
auto request = std::make_shared<ThreadLifetimeMgmtOp>(
|
auto request = std::make_shared<ThreadLifetimeMgmtOp>(
|
||||||
@@ -330,7 +331,7 @@ public:
|
|||||||
* An exception has occurred in one of a mind's threads. We need to
|
* An exception has occurred in one of a mind's threads. We need to
|
||||||
* shut down all of that particular mind's threads.
|
* shut down all of that particular mind's threads.
|
||||||
*/
|
*/
|
||||||
globalMind->finalizeReq(
|
smo::mind::globalMind->finalizeReq(
|
||||||
std::bind(
|
std::bind(
|
||||||
&MindShutdownIndOp::mindShutdownInd2,
|
&MindShutdownIndOp::mindShutdownInd2,
|
||||||
context.get(), context));
|
context.get(), context));
|
||||||
@@ -351,7 +352,7 @@ public:
|
|||||||
* So this should ideally be a loop
|
* So this should ideally be a loop
|
||||||
* through all running Minds, calling finalizeReq on each one.
|
* through all running Minds, calling finalizeReq on each one.
|
||||||
*/
|
*/
|
||||||
globalMind->finalizeReq(
|
smo::mind::globalMind->finalizeReq(
|
||||||
std::bind(
|
std::bind(
|
||||||
&MindShutdownIndOp::mindShutdownInd2,
|
&MindShutdownIndOp::mindShutdownInd2,
|
||||||
context.get(), context));
|
context.get(), context));
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
#ifndef _BODY_COMPONENT_H
|
||||||
|
#define _BODY_COMPONENT_H
|
||||||
|
|
||||||
|
#include <component.h>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
namespace smo {
|
||||||
|
|
||||||
|
class Mind;
|
||||||
|
class ComponentThread;
|
||||||
|
|
||||||
|
namespace body {
|
||||||
|
|
||||||
|
class Body
|
||||||
|
: public MindComponent
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Body(Mind &parent, const std::shared_ptr<ComponentThread> &thread);
|
||||||
|
~Body() = default;
|
||||||
|
|
||||||
|
typedef std::function<void(bool)> bodyLifetimeMgmtOpCbFn;
|
||||||
|
void initializeReq(bodyLifetimeMgmtOpCbFn callback);
|
||||||
|
void finalizeReq(bodyLifetimeMgmtOpCbFn callback);
|
||||||
|
|
||||||
|
private:
|
||||||
|
class InitializeReq;
|
||||||
|
class FinalizeReq;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace body
|
||||||
|
} // namespace smo
|
||||||
|
|
||||||
|
#endif // _BODY_COMPONENT_H
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
#ifndef COMPONENT_H
|
||||||
|
#define COMPONENT_H
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
#include <memory>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
namespace smo {
|
||||||
|
|
||||||
|
class Mind;
|
||||||
|
class ComponentThread;
|
||||||
|
|
||||||
|
class Component
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Component(const std::shared_ptr<ComponentThread> &thread);
|
||||||
|
~Component() = default;
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::shared_ptr<ComponentThread> thread;
|
||||||
|
|
||||||
|
public:
|
||||||
|
};
|
||||||
|
|
||||||
|
class MindComponent
|
||||||
|
: public Component
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MindComponent(Mind &parent, const std::shared_ptr<ComponentThread> &thread);
|
||||||
|
~MindComponent() = default;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Mind &parent;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace mrntt {
|
||||||
|
|
||||||
|
class MarionetteComponent
|
||||||
|
: public Component
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MarionetteComponent(const std::shared_ptr<ComponentThread> &thread);
|
||||||
|
~MarionetteComponent() = default;
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef std::function<void(bool)> mrnttLifetimeMgmtOpCbFn;
|
||||||
|
void initializeReq(mrnttLifetimeMgmtOpCbFn callback);
|
||||||
|
void finalizeReq(mrnttLifetimeMgmtOpCbFn callback);
|
||||||
|
|
||||||
|
private:
|
||||||
|
class MrnttLifetimeMgmtOp;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace mrntt
|
||||||
|
|
||||||
|
} // namespace smo
|
||||||
|
|
||||||
|
#endif // COMPONENT_H
|
||||||
@@ -167,8 +167,8 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
namespace mrntt {
|
namespace mrntt {
|
||||||
extern std::shared_ptr<MarionetteThread> mrntt;
|
extern std::shared_ptr<MarionetteThread> thread;
|
||||||
}
|
} // namespace mrntt
|
||||||
|
|
||||||
} // namespace smo
|
} // namespace smo
|
||||||
|
|
||||||
|
|||||||
@@ -2,16 +2,26 @@
|
|||||||
#define DIRECTOR_H
|
#define DIRECTOR_H
|
||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
#include <component.h>
|
||||||
#include <goal.h>
|
#include <goal.h>
|
||||||
#include <lruLifo.h>
|
#include <lruLifo.h>
|
||||||
|
|
||||||
namespace smo {
|
namespace smo {
|
||||||
|
|
||||||
|
class Mind;
|
||||||
|
class ComponentThread;
|
||||||
|
|
||||||
namespace director {
|
namespace director {
|
||||||
|
|
||||||
class Director {
|
class Director
|
||||||
|
: public MindComponent
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
Director() = default;
|
Director(Mind &parent, const std::shared_ptr<ComponentThread> &thread)
|
||||||
~Director() = default;
|
: MindComponent(parent, thread)
|
||||||
|
{}
|
||||||
|
|
||||||
|
~Director() = default;
|
||||||
|
|
||||||
/** EXPLANATION:
|
/** EXPLANATION:
|
||||||
* We allow SMO to prioritize negtrins over injected goals, so that it can
|
* We allow SMO to prioritize negtrins over injected goals, so that it can
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <componentThread.h>
|
#include <componentThread.h>
|
||||||
|
#include <component.h>
|
||||||
|
|
||||||
namespace smo {
|
namespace smo {
|
||||||
|
|
||||||
@@ -13,8 +14,8 @@ class MarionetteThread;
|
|||||||
namespace mrntt {
|
namespace mrntt {
|
||||||
|
|
||||||
extern std::atomic<int> exitCode;
|
extern std::atomic<int> exitCode;
|
||||||
|
|
||||||
void exitMarionetteLoop();
|
void exitMarionetteLoop();
|
||||||
|
extern mrntt::MarionetteComponent mrntt;
|
||||||
|
|
||||||
} // namespace mrntt
|
} // namespace mrntt
|
||||||
|
|
||||||
|
|||||||
+14
-13
@@ -8,9 +8,11 @@
|
|||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include <component.h>
|
||||||
|
#include <componentThread.h>
|
||||||
#include <director/director.h>
|
#include <director/director.h>
|
||||||
#include <simulator/simulator.h>
|
#include <simulator/simulator.h>
|
||||||
#include <componentThread.h>
|
#include <body/body.h>
|
||||||
|
|
||||||
namespace smo {
|
namespace smo {
|
||||||
|
|
||||||
@@ -23,8 +25,6 @@ public:
|
|||||||
typedef std::function<void(bool)> mindLifetimeMgmtOpCbFn;
|
typedef std::function<void(bool)> mindLifetimeMgmtOpCbFn;
|
||||||
void initializeReq(mindLifetimeMgmtOpCbFn callback);
|
void initializeReq(mindLifetimeMgmtOpCbFn callback);
|
||||||
void finalizeReq(mindLifetimeMgmtOpCbFn callback);
|
void finalizeReq(mindLifetimeMgmtOpCbFn callback);
|
||||||
void initializeBodyReq(mindLifetimeMgmtOpCbFn callback);
|
|
||||||
void finalizeBodyReq(mindLifetimeMgmtOpCbFn callback);
|
|
||||||
|
|
||||||
// ComponentThread access methods
|
// ComponentThread access methods
|
||||||
std::shared_ptr<MindThread> getComponentThread(
|
std::shared_ptr<MindThread> getComponentThread(
|
||||||
@@ -45,15 +45,19 @@ public:
|
|||||||
// CPU distribution method
|
// CPU distribution method
|
||||||
void distributeAndPinThreadsAcrossCpus();
|
void distributeAndPinThreadsAcrossCpus();
|
||||||
|
|
||||||
public:
|
private:
|
||||||
std::thread directorThread;
|
// Collection of ComponentThread instances (excluding marionette)
|
||||||
std::thread simulatorThread;
|
std::vector<std::shared_ptr<MindThread>> componentThreads;
|
||||||
std::thread subconsciousThread;
|
|
||||||
|
|
||||||
director::Director director;
|
public:
|
||||||
simulator::Simulator canvas;
|
director::Director director;
|
||||||
|
simulator::Simulator canvas;
|
||||||
|
MindComponent subconscious;
|
||||||
|
body::Body body;
|
||||||
|
MindComponent world;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
friend class body::Body;
|
||||||
/**
|
/**
|
||||||
* Indicates whether all mind threads have been JOLTed at least once.
|
* Indicates whether all mind threads have been JOLTed at least once.
|
||||||
*
|
*
|
||||||
@@ -75,13 +79,10 @@ private:
|
|||||||
*/
|
*/
|
||||||
bool threadsHaveBeenJolted = false,
|
bool threadsHaveBeenJolted = false,
|
||||||
bodyComponentInitialized = false;
|
bodyComponentInitialized = false;
|
||||||
// Collection of ComponentThread instances (excluding marionette)
|
|
||||||
std::vector<std::shared_ptr<MindThread>> componentThreads;
|
|
||||||
|
|
||||||
|
private:
|
||||||
class MindLifetimeMgmtOp;
|
class MindLifetimeMgmtOp;
|
||||||
class MindThreadLifetimeMgmtOp;
|
class MindThreadLifetimeMgmtOp;
|
||||||
class InitializeBodyReq;
|
|
||||||
class FinalizeBodyReq;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Global Mind instance will be defined in marionette.cpp
|
// Global Mind instance will be defined in marionette.cpp
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
#ifndef _SMO_MIND_MANAGER_H
|
||||||
|
#define _SMO_MIND_MANAGER_H
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
#include <mind.h>
|
||||||
|
|
||||||
|
namespace smo {
|
||||||
|
namespace mind {
|
||||||
|
|
||||||
|
/** EXPLANATION:
|
||||||
|
* MindManager is responsible for managing the lifecycle of all minds.
|
||||||
|
* It is responsible for creating, destroying, and managing the minds.
|
||||||
|
*
|
||||||
|
* For now it does nothing since we haven't yet added support for multiple
|
||||||
|
* minds.
|
||||||
|
*/
|
||||||
|
class MindManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MindManager(void) = default;
|
||||||
|
~MindManager(void) = default;
|
||||||
|
|
||||||
|
static MindManager& getInstance()
|
||||||
|
{
|
||||||
|
static MindManager instance;
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
void initialize(void) {};
|
||||||
|
void finalize(void) {};
|
||||||
|
|
||||||
|
std::shared_ptr<Mind> getMind(void) const;
|
||||||
|
void addMind(const std::shared_ptr<Mind>& mind);
|
||||||
|
void removeMind(const std::shared_ptr<Mind>& mind);
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::vector<std::shared_ptr<Mind>> minds;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern std::shared_ptr<Mind> globalMind;
|
||||||
|
|
||||||
|
} // namespace mind
|
||||||
|
} // namespace smo
|
||||||
|
|
||||||
|
#endif // _SMO_MIND_MANAGER_H
|
||||||
@@ -2,15 +2,25 @@
|
|||||||
#define SIMULATOR_H
|
#define SIMULATOR_H
|
||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
#include <component.h>
|
||||||
#include <simulator/scene.h>
|
#include <simulator/scene.h>
|
||||||
|
|
||||||
namespace smo {
|
namespace smo {
|
||||||
|
|
||||||
|
class Mind;
|
||||||
|
class ComponentThread;
|
||||||
|
|
||||||
namespace simulator {
|
namespace simulator {
|
||||||
|
|
||||||
class Simulator {
|
class Simulator
|
||||||
|
: public MindComponent
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
Simulator() = default;
|
Simulator(Mind &parent, const std::shared_ptr<ComponentThread> &thread)
|
||||||
~Simulator() = default;
|
: MindComponent(parent, thread)
|
||||||
|
{}
|
||||||
|
|
||||||
|
~Simulator() = default;
|
||||||
|
|
||||||
void initialize();
|
void initialize();
|
||||||
void loadScene(Scene::Id sceneId, Scene &scene);
|
void loadScene(Scene::Id sceneId, Scene &scene);
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
add_library(marionette STATIC
|
add_library(marionette STATIC
|
||||||
marionette.cpp
|
main.cpp
|
||||||
salmanoff.cpp
|
salmanoff.cpp
|
||||||
|
lifetime.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(marionette
|
target_link_libraries(marionette
|
||||||
smocore
|
smocore
|
||||||
|
mindManager
|
||||||
)
|
)
|
||||||
|
|
||||||
target_include_directories(marionette PUBLIC
|
target_include_directories(marionette PUBLIC
|
||||||
|
|||||||
@@ -0,0 +1,145 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <asynchronousContinuation.h>
|
||||||
|
#include <asynchronousLoop.h>
|
||||||
|
#include <component.h>
|
||||||
|
#include <componentThread.h>
|
||||||
|
#include <mindManager/mindManager.h>
|
||||||
|
#include <marionette/marionette.h>
|
||||||
|
|
||||||
|
namespace smo {
|
||||||
|
namespace mrntt {
|
||||||
|
|
||||||
|
class MarionetteComponent::MrnttLifetimeMgmtOp
|
||||||
|
: public AsynchronousContinuation<mrnttLifetimeMgmtOpCbFn>,
|
||||||
|
public ContinuationTarget
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MrnttLifetimeMgmtOp(
|
||||||
|
MarionetteComponent &parent, const std::shared_ptr<ComponentThread> &caller,
|
||||||
|
mrnttLifetimeMgmtOpCbFn callback)
|
||||||
|
: AsynchronousContinuation<mrnttLifetimeMgmtOpCbFn>(callback),
|
||||||
|
ContinuationTarget(caller),
|
||||||
|
parent(parent)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void callOriginalCbFn(bool success)
|
||||||
|
{
|
||||||
|
if (originalCbFn)
|
||||||
|
{
|
||||||
|
caller->getIoService().post(
|
||||||
|
std::bind(originalCbFn, success));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
MarionetteComponent &parent;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void initializeReq1_posted(
|
||||||
|
[[maybe_unused]] std::shared_ptr<MrnttLifetimeMgmtOp> context
|
||||||
|
)
|
||||||
|
{
|
||||||
|
auto self = ComponentThread::getSelf();
|
||||||
|
if (self->id != ComponentThread::MRNTT)
|
||||||
|
{
|
||||||
|
throw std::runtime_error(std::string(__func__)
|
||||||
|
+ ": Must be executed on Marionette thread");
|
||||||
|
}
|
||||||
|
|
||||||
|
smo::mind::globalMind = std::make_shared<Mind>();
|
||||||
|
smo::mind::globalMind->initializeReq(
|
||||||
|
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->callOriginalCbFn(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
context->callOriginalCbFn(success);
|
||||||
|
}
|
||||||
|
|
||||||
|
void finalizeReq1_posted(
|
||||||
|
[[maybe_unused]] std::shared_ptr<MrnttLifetimeMgmtOp> context
|
||||||
|
)
|
||||||
|
{
|
||||||
|
auto self = ComponentThread::getSelf();
|
||||||
|
if (self->id != ComponentThread::MRNTT)
|
||||||
|
{
|
||||||
|
throw std::runtime_error(std::string(__func__)
|
||||||
|
+ ": Must be executed on Marionette thread");
|
||||||
|
}
|
||||||
|
|
||||||
|
smo::mind::globalMind->finalizeReq(
|
||||||
|
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->callOriginalCbFn(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
context->callOriginalCbFn(success);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void MarionetteComponent::initializeReq(mrnttLifetimeMgmtOpCbFn callback)
|
||||||
|
{
|
||||||
|
auto mrntt = ComponentThread::getSelf();
|
||||||
|
|
||||||
|
if (mrntt->id != ComponentThread::MRNTT)
|
||||||
|
{
|
||||||
|
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(
|
||||||
|
std::bind(
|
||||||
|
&MrnttLifetimeMgmtOp::initializeReq1_posted,
|
||||||
|
request.get(), request));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MarionetteComponent::finalizeReq(mrnttLifetimeMgmtOpCbFn callback)
|
||||||
|
{
|
||||||
|
auto mrntt = ComponentThread::getSelf();
|
||||||
|
|
||||||
|
if (mrntt->id != ComponentThread::MRNTT)
|
||||||
|
{
|
||||||
|
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(
|
||||||
|
std::bind(
|
||||||
|
&MrnttLifetimeMgmtOp::finalizeReq1_posted,
|
||||||
|
request.get(), request));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace mrntt
|
||||||
|
} // namespace smo
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
#include <typeinfo>
|
#include <typeinfo>
|
||||||
#include <boost/asio/signal_set.hpp>
|
#include <boost/asio/signal_set.hpp>
|
||||||
#include <asynchronousBridge.h>
|
#include <asynchronousBridge.h>
|
||||||
#include <mind.h>
|
#include <mindManager/mindManager.h>
|
||||||
#include <componentThread.h>
|
#include <componentThread.h>
|
||||||
#include <marionette/marionette.h>
|
#include <marionette/marionette.h>
|
||||||
#include <salmanoff.h>
|
#include <salmanoff.h>
|
||||||
@@ -20,21 +20,46 @@ void CrtCommandLineArgs::set(int argc, char *argv[], char *envp[])
|
|||||||
crtCommandLineArgs = CrtCommandLineArgs(argc, argv, envp);
|
crtCommandLineArgs = CrtCommandLineArgs(argc, argv, envp);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Global Mind instance
|
|
||||||
std::shared_ptr<Mind> globalMind;
|
|
||||||
|
|
||||||
namespace mrntt {
|
namespace mrntt {
|
||||||
std::atomic<int> exitCode;
|
std::atomic<int> exitCode;
|
||||||
// Global marionette thread instance
|
// Global marionette thread instance
|
||||||
std::shared_ptr<MarionetteThread> mrntt = std::make_shared<MarionetteThread>();
|
std::shared_ptr<MarionetteThread> thread =
|
||||||
|
std::make_shared<MarionetteThread>();
|
||||||
|
MarionetteComponent mrntt(thread);
|
||||||
|
|
||||||
void exitMarionetteLoop()
|
void exitMarionetteLoop()
|
||||||
{
|
{
|
||||||
mrntt::mrntt->keepLooping = false;
|
mrntt::thread->keepLooping = false;
|
||||||
mrntt::mrntt->getIoService().stop();
|
mrntt::thread->getIoService().stop();
|
||||||
std::cout << "Mrntt: Signaled main loop to exit." << "\n";
|
std::cout << "Mrntt: Signaled main loop to exit." << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void marionetteFinalizeReqCb(bool success)
|
||||||
|
{
|
||||||
|
if (!success) {
|
||||||
|
std::cerr << __func__ << ": Failed to finalize Marionette." << '\n';
|
||||||
|
}
|
||||||
|
std::cout << __func__ << ": Marionette finalized." << '\n';
|
||||||
|
exitMarionetteLoop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void marionetteInitializeReqCb(bool success)
|
||||||
|
{
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
std::cout << __func__ << ": Marionette initialized." << '\n';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cerr << __func__ << ": Failed to initialize Marionette. Shutting down."
|
||||||
|
<< '\n';
|
||||||
|
|
||||||
|
mrntt::mrntt.finalizeReq(
|
||||||
|
std::bind(
|
||||||
|
&mrntt::marionetteFinalizeReqCb,
|
||||||
|
std::placeholders::_1));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace mrntt
|
} // namespace mrntt
|
||||||
|
|
||||||
void MarionetteThread::main(MarionetteThread& self)
|
void MarionetteThread::main(MarionetteThread& self)
|
||||||
@@ -66,7 +91,10 @@ void MarionetteThread::main(MarionetteThread& self)
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
self.userShutdownInd();
|
mrntt::mrntt.finalizeReq(
|
||||||
|
std::bind(
|
||||||
|
&mrntt::marionetteFinalizeReqCb,
|
||||||
|
std::placeholders::_1));
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -86,46 +114,33 @@ void MarionetteThread::main(MarionetteThread& self)
|
|||||||
throw JustPrintUsageNoError(options);
|
throw JustPrintUsageNoError(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 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.
|
||||||
|
*
|
||||||
|
* Then we initialize the Minds. Minds are asynchronous and they
|
||||||
|
* call upon the async methods of the Manager classes. Device
|
||||||
|
* attachment is actually Mind specific and not Smo-global
|
||||||
|
*
|
||||||
|
* It is arguable whether library loading is Mind specific or
|
||||||
|
* Smo-global. You could argue that libraries should be loaded and
|
||||||
|
* unloaded dynamically as-needed by the bodies and worlds of
|
||||||
|
* particular Minds. You could also argue that we should load all
|
||||||
|
* libraries at startup and unload them at shutdown.
|
||||||
|
*
|
||||||
|
* The latter is cleaner and more resource-respecting. The former is
|
||||||
|
* easier to implement.
|
||||||
|
*/
|
||||||
initializeSalmanoff();
|
initializeSalmanoff();
|
||||||
callShutdownSalmanoff = true;
|
callShutdownSalmanoff = true;
|
||||||
|
|
||||||
self.getIoService().post([]()
|
// Create new Mind instance just before initializeReq
|
||||||
{
|
mrntt::mrntt.initializeReq(
|
||||||
/** EXPLANATION:
|
std::bind(
|
||||||
* Initialize Salmanoff's Manager classes first.
|
&mrntt::marionetteInitializeReqCb, std::placeholders::_1));
|
||||||
* Manager classes' initialization is synchronous in nature, so we
|
|
||||||
* don't need the minds to be running to initialize them.
|
|
||||||
*
|
|
||||||
* Then we initialize the Minds. Minds are asynchronous and they
|
|
||||||
* call upon the async methods of the Manager classes. Device
|
|
||||||
* attachment is actually Mind specific and not Smo-global
|
|
||||||
*
|
|
||||||
* It is arguable whether library loading is Mind specific or
|
|
||||||
* Smo-global. You could argue that libraries should be loaded and
|
|
||||||
* unloaded dynamically as-needed by the bodies and worlds of
|
|
||||||
* particular Minds. You could also argue that we should load all
|
|
||||||
* libraries at startup and unload them at shutdown.
|
|
||||||
*
|
|
||||||
* The latter is cleaner and more resource-respecting. The former is
|
|
||||||
* easier to implement.
|
|
||||||
*/
|
|
||||||
// Create new Mind instance just before initializeReq
|
|
||||||
globalMind = std::make_shared<Mind>();
|
|
||||||
globalMind->initializeReq(
|
|
||||||
[](bool success)
|
|
||||||
{
|
|
||||||
if (!success)
|
|
||||||
{
|
|
||||||
std::cerr << "Failed to initialize Mind object "
|
|
||||||
"(threads)" << '\n';
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << "Mrntt: Mind object (threads) initialized."
|
std::cout << __func__ << ": Entering event loop" << "\n";
|
||||||
<< '\n';
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
std::cout << __func__ << ": Entering event loop" << "\n";
|
|
||||||
|
|
||||||
/* We loop here because when an exception occurs in mrntt, we need to
|
/* We loop here because when an exception occurs in mrntt, we need to
|
||||||
* both direct the mind threads to exit gracefully, and then we also
|
* both direct the mind threads to exit gracefully, and then we also
|
||||||
@@ -204,12 +219,13 @@ void MarionetteThread::main(MarionetteThread& self)
|
|||||||
|
|
||||||
if (callFinalizeReq)
|
if (callFinalizeReq)
|
||||||
{
|
{
|
||||||
globalMind->finalizeReq([](bool success)
|
std::cout << __func__ << ": About call finalizeReq at end of mrnttMain." << '\n';
|
||||||
|
mind::globalMind->finalizeReq([](bool success)
|
||||||
{
|
{
|
||||||
if (!success) {
|
if (!success) {
|
||||||
std::cerr << "Failed to finalize Mind object (threads)" << '\n';
|
std::cerr << "Failed to finalize Mind object (threads)" << '\n';
|
||||||
}
|
}
|
||||||
mrntt::mrntt->getIoService().stop();
|
mrntt::thread->getIoService().stop();
|
||||||
});
|
});
|
||||||
self.getIoService().reset();
|
self.getIoService().reset();
|
||||||
self.getIoService().run();
|
self.getIoService().run();
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <mindManager/mindManager.h>
|
||||||
#include <deviceManager/deviceManager.h>
|
#include <deviceManager/deviceManager.h>
|
||||||
#include <senseApis/senseApiManager.h>
|
#include <senseApis/senseApiManager.h>
|
||||||
#include <asynchronousContinuation.h>
|
|
||||||
#include <salmanoff.h>
|
#include <salmanoff.h>
|
||||||
|
|
||||||
|
|
||||||
@@ -11,6 +11,7 @@ void initializeSalmanoff(void)
|
|||||||
{
|
{
|
||||||
std::cout << __func__ << ": Entered." << std::endl;
|
std::cout << __func__ << ": Entered." << std::endl;
|
||||||
|
|
||||||
|
mind::MindManager::getInstance().initialize();
|
||||||
sense_api::SenseApiManager::getInstance().initialize();
|
sense_api::SenseApiManager::getInstance().initialize();
|
||||||
device::DeviceManager::getInstance().initialize();
|
device::DeviceManager::getInstance().initialize();
|
||||||
device::DeviceManager::getInstance().collateAllDapSpecs();
|
device::DeviceManager::getInstance().collateAllDapSpecs();
|
||||||
@@ -23,6 +24,7 @@ void shutdownSalmanoff(void)
|
|||||||
std::cout << __func__ << ": Entered." << std::endl;
|
std::cout << __func__ << ": Entered." << std::endl;
|
||||||
device::DeviceManager::getInstance().finalize();
|
device::DeviceManager::getInstance().finalize();
|
||||||
sense_api::SenseApiManager::getInstance().finalize();
|
sense_api::SenseApiManager::getInstance().finalize();
|
||||||
|
mind::MindManager::getInstance().finalize();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace smo
|
} // namespace smo
|
||||||
|
|||||||
+20
-173
@@ -4,6 +4,8 @@
|
|||||||
#include <asynchronousLoop.h>
|
#include <asynchronousLoop.h>
|
||||||
#include <mind.h>
|
#include <mind.h>
|
||||||
#include <componentThread.h>
|
#include <componentThread.h>
|
||||||
|
#include <director/director.h>
|
||||||
|
#include <simulator/simulator.h>
|
||||||
#include <senseApis/senseApiManager.h>
|
#include <senseApis/senseApiManager.h>
|
||||||
|
|
||||||
namespace smo {
|
namespace smo {
|
||||||
@@ -13,9 +15,22 @@ Mind::Mind(void)
|
|||||||
std::make_shared<MindThread>(ComponentThread::DIRECTOR, *this),
|
std::make_shared<MindThread>(ComponentThread::DIRECTOR, *this),
|
||||||
std::make_shared<MindThread>(ComponentThread::SIMULATOR, *this),
|
std::make_shared<MindThread>(ComponentThread::SIMULATOR, *this),
|
||||||
std::make_shared<MindThread>(ComponentThread::SUBCONSCIOUS, *this),
|
std::make_shared<MindThread>(ComponentThread::SUBCONSCIOUS, *this),
|
||||||
std::make_shared<MindThread>(ComponentThread::BODY, *this),
|
std::make_shared<MindThread>(ComponentThread::BODY, *this)
|
||||||
std::make_shared<MindThread>(ComponentThread::WORLD, *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";
|
std::cout << "Mrntt: All mind threads started." << "\n";
|
||||||
|
|
||||||
parent.initializeBodyReq(
|
parent.body.initializeReq(
|
||||||
std::bind(
|
std::bind(
|
||||||
&MindLifetimeMgmtOp::initializeReq3,
|
&MindLifetimeMgmtOp::initializeReq3,
|
||||||
context.get(), context, std::placeholders::_1));
|
context.get(), context, std::placeholders::_1));
|
||||||
@@ -192,180 +207,12 @@ void Mind::finalizeReq(mindLifetimeMgmtOpCbFn callback)
|
|||||||
auto request = std::make_shared<MindLifetimeMgmtOp>(
|
auto request = std::make_shared<MindLifetimeMgmtOp>(
|
||||||
*this, callback);
|
*this, callback);
|
||||||
|
|
||||||
finalizeBodyReq(
|
body.finalizeReq(
|
||||||
std::bind(
|
std::bind(
|
||||||
&MindLifetimeMgmtOp::finalizeReq1,
|
&MindLifetimeMgmtOp::finalizeReq1,
|
||||||
request.get(), request, std::placeholders::_1));
|
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()
|
void Mind::distributeAndPinThreadsAcrossCpus()
|
||||||
{
|
{
|
||||||
int cpuCount = ComponentThread::getAvailableCpuCount();
|
int cpuCount = ComponentThread::getAvailableCpuCount();
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
add_library(mindManager STATIC
|
||||||
|
mindManager.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(mindManager PUBLIC
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/../include
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(mindManager
|
||||||
|
smocore
|
||||||
|
)
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
#include <mindManager/mindManager.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace smo {
|
||||||
|
namespace mind {
|
||||||
|
|
||||||
|
std::shared_ptr<Mind> globalMind;
|
||||||
|
|
||||||
|
} // namespace mind
|
||||||
|
} // namespace smo
|
||||||
@@ -456,7 +456,9 @@ void SenseApiManager::detachAllSenseDevicesReq(
|
|||||||
std::cerr << __func__ << ": Exception: " << e.what() << "\n";
|
std::cerr << __func__ << ": Exception: " << e.what() << "\n";
|
||||||
if (request->loop.incrementSuccessOrFailureAndTestForCompletionDueTo(false))
|
if (request->loop.incrementSuccessOrFailureAndTestForCompletionDueTo(false))
|
||||||
{
|
{
|
||||||
|
std::cout << __func__ << ": About to call original cbFn." << "\n";
|
||||||
request->callOriginalCallback();
|
request->callOriginalCallback();
|
||||||
|
std::cout << __func__ << ": Just called original cbFn." << "\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user