2025-01-11 04:34:49 -04:00
|
|
|
#include <iostream>
|
|
|
|
|
#include <componentThread.h>
|
2025-07-28 07:20:44 -04:00
|
|
|
#include <boost/asio.hpp>
|
2025-01-11 04:34:49 -04:00
|
|
|
|
2025-07-22 06:48:04 -04:00
|
|
|
namespace smo {
|
2025-01-11 04:34:49 -04:00
|
|
|
|
2025-07-28 07:20:44 -04:00
|
|
|
thread_local std::shared_ptr<ComponentThread> thisComponentThread;
|
|
|
|
|
|
|
|
|
|
const std::string ComponentThread::threadNames[N_ITEMS] =
|
|
|
|
|
{
|
|
|
|
|
"mrntt",
|
|
|
|
|
"director",
|
|
|
|
|
"simulator",
|
|
|
|
|
"subconscious",
|
|
|
|
|
"body",
|
|
|
|
|
"world"
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
namespace mrntt {
|
|
|
|
|
std::shared_ptr<ComponentThread> mrntt =
|
|
|
|
|
std::make_shared<ComponentThread>(ComponentThread::MRNTT);
|
|
|
|
|
}
|
2025-01-11 04:34:49 -04:00
|
|
|
namespace director {
|
2025-07-22 06:48:04 -04:00
|
|
|
/* The director is the seat of volition in Salmanoff. It receives sensor
|
2025-01-17 11:36:05 -04:00
|
|
|
* events from the body and world, and uses them to direct its implexors
|
|
|
|
|
* to implex new menties. It then loads the menties into canvas for simulation
|
|
|
|
|
* and correlation with intrins, in order to form new attrimotions and
|
|
|
|
|
* menties.
|
|
|
|
|
*/
|
2025-07-28 07:20:44 -04:00
|
|
|
std::shared_ptr<ComponentThread> director =
|
|
|
|
|
std::make_shared<ComponentThread>(ComponentThread::DIRECTOR);
|
2025-01-11 04:34:49 -04:00
|
|
|
}
|
|
|
|
|
namespace simulator {
|
2025-07-22 06:48:04 -04:00
|
|
|
/* The canvas is the simulation engine in Salmanoff. It receives menties and
|
2025-01-17 11:36:05 -04:00
|
|
|
* simulates them in accordance with the instructions from director. It then
|
|
|
|
|
* re-renders them into perception for director to get feedback.
|
|
|
|
|
*/
|
2025-07-28 07:20:44 -04:00
|
|
|
std::shared_ptr<ComponentThread> canvas =
|
|
|
|
|
std::make_shared<ComponentThread>(ComponentThread::SIMULATOR);
|
2025-01-11 04:34:49 -04:00
|
|
|
}
|
|
|
|
|
namespace subconscious {
|
2025-07-22 06:48:04 -04:00
|
|
|
/* The subconscious is the seat of memory in Salmanoff. It receives menties
|
2025-01-17 11:36:05 -04:00
|
|
|
* from director and stores them in memory for later recall.
|
|
|
|
|
*/
|
2025-07-28 07:20:44 -04:00
|
|
|
std::shared_ptr<ComponentThread> subconscious =
|
|
|
|
|
std::make_shared<ComponentThread>(ComponentThread::SUBCONSCIOUS);
|
2025-01-11 04:34:49 -04:00
|
|
|
}
|
2025-01-17 11:36:05 -04:00
|
|
|
namespace body {
|
|
|
|
|
/* The body is a thread that polls, processes, and sends interoceptive sensor
|
|
|
|
|
* events to director. It enables these events to occur asynchronously,
|
|
|
|
|
* indepdendent any actions that the other threads are taking.
|
|
|
|
|
*/
|
2025-07-28 07:20:44 -04:00
|
|
|
std::shared_ptr<ComponentThread> body =
|
|
|
|
|
std::make_shared<ComponentThread>(ComponentThread::BODY);
|
2025-01-17 11:36:05 -04:00
|
|
|
}
|
|
|
|
|
namespace world {
|
|
|
|
|
/* The world performs the same functions as the body, but for extrospective
|
|
|
|
|
* sensor events.
|
|
|
|
|
*/
|
2025-07-28 07:20:44 -04:00
|
|
|
std::shared_ptr<ComponentThread> world =
|
|
|
|
|
std::make_shared<ComponentThread>(ComponentThread::WORLD);
|
2025-01-17 11:36:05 -04:00
|
|
|
}
|
|
|
|
|
|
2025-07-28 07:20:44 -04:00
|
|
|
std::array<std::shared_ptr<ComponentThread>, ComponentThread::N_ITEMS>
|
2025-01-11 04:34:49 -04:00
|
|
|
ComponentThread::componentThreads =
|
|
|
|
|
{
|
2025-07-28 07:20:44 -04:00
|
|
|
mrntt::mrntt,
|
|
|
|
|
director::director,
|
|
|
|
|
simulator::canvas,
|
|
|
|
|
subconscious::subconscious,
|
|
|
|
|
body::body,
|
|
|
|
|
world::world
|
2025-01-11 04:34:49 -04:00
|
|
|
};
|
|
|
|
|
|
2025-07-28 07:20:44 -04:00
|
|
|
void ComponentThread::initializeTls(void)
|
|
|
|
|
{
|
|
|
|
|
thisComponentThread = shared_from_this();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const std::shared_ptr<ComponentThread> ComponentThread::getSelf(void)
|
2025-01-11 04:34:49 -04:00
|
|
|
{
|
2025-07-28 07:20:44 -04:00
|
|
|
if (!thisComponentThread)
|
2025-01-11 04:34:49 -04:00
|
|
|
{
|
|
|
|
|
throw std::runtime_error(std::string(__func__)
|
2025-07-28 07:20:44 -04:00
|
|
|
+ ": TLS not initialized");
|
2025-01-11 04:34:49 -04:00
|
|
|
}
|
|
|
|
|
|
2025-07-28 07:20:44 -04:00
|
|
|
return thisComponentThread;
|
2025-01-11 04:34:49 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ComponentThread::main(ComponentThread& self)
|
|
|
|
|
{
|
2025-07-28 07:20:44 -04:00
|
|
|
std::cout << self.name << ":" << __func__ << ": Waiting for JOLT" <<"\n";
|
|
|
|
|
self.getIoService().run();
|
|
|
|
|
self.initializeTls();
|
|
|
|
|
|
|
|
|
|
std::cout << self.name << ":" << __func__ << ": Entering event loop" <<"\n";
|
|
|
|
|
|
2025-07-30 09:09:38 -04:00
|
|
|
/* We loop here because when an exception is caught, we need to first catch
|
|
|
|
|
* it in the catch blocks. We bubble the exception to mrntt in the catch
|
|
|
|
|
* blocks, and then we loop here to await control messages from mrntt.
|
|
|
|
|
*
|
|
|
|
|
* We can't just exit on our own. Rather, we must wait for mrntt to tell us
|
|
|
|
|
* to exit. When we wish to finally exit, we set keepLooping to false.
|
|
|
|
|
*/
|
2025-07-28 07:20:44 -04:00
|
|
|
for (self.keepLooping = true; self.keepLooping;)
|
2025-01-11 04:34:49 -04:00
|
|
|
{
|
2025-07-28 07:20:44 -04:00
|
|
|
try {
|
|
|
|
|
self.getIoService().reset();
|
|
|
|
|
self.getIoService().run();
|
|
|
|
|
}
|
|
|
|
|
catch (const std::exception& e)
|
|
|
|
|
{
|
|
|
|
|
std::cerr << self.name << ":" << __func__
|
|
|
|
|
<< ": Exception occurred: " << e.what() << "\n";
|
|
|
|
|
|
|
|
|
|
mrntt::mrntt->exceptionInd(self);
|
|
|
|
|
}
|
|
|
|
|
catch (...)
|
|
|
|
|
{
|
|
|
|
|
std::cerr << self.name << ":" << __func__
|
|
|
|
|
<< ": Unknown exception occurred" << "\n";
|
|
|
|
|
|
|
|
|
|
mrntt::mrntt->exceptionInd(self);
|
|
|
|
|
}
|
2025-01-11 04:34:49 -04:00
|
|
|
}
|
|
|
|
|
|
2025-07-30 09:09:38 -04:00
|
|
|
std::cout << self.name << ":" << __func__ << ": Exited event loop" << "\n";
|
2025-01-11 04:34:49 -04:00
|
|
|
}
|
|
|
|
|
|
2025-07-28 07:20:44 -04:00
|
|
|
// Thread management method implementations
|
|
|
|
|
void ComponentThread::startThreadReq(std::function<void()> callback)
|
2025-01-11 04:34:49 -04:00
|
|
|
{
|
2025-07-28 07:20:44 -04:00
|
|
|
this->getIoService().post([this, caller = getSelf(), callback]()
|
2025-01-11 04:34:49 -04:00
|
|
|
{
|
2025-07-28 07:20:44 -04:00
|
|
|
std::cout << "Thread '" << name << "': handling startThread." << "\n";
|
|
|
|
|
|
|
|
|
|
// Execute private setup sequence here
|
|
|
|
|
// This is where each thread would implement its specific initialization
|
|
|
|
|
|
|
|
|
|
if (callback) {
|
|
|
|
|
caller->getIoService().post(callback);
|
2025-01-11 04:34:49 -04:00
|
|
|
}
|
2025-07-28 07:20:44 -04:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ComponentThread::cleanup(void)
|
|
|
|
|
{
|
|
|
|
|
this->keepLooping = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ComponentThread::exitThreadReq(std::function<void()> callback)
|
|
|
|
|
{
|
|
|
|
|
// Post to the main io_service
|
|
|
|
|
this->getIoService().post([this, caller = getSelf(), callback]()
|
|
|
|
|
{
|
|
|
|
|
std::cout << "Thread '" << name << "': handling exitThread "
|
|
|
|
|
"(main queue)." << std::endl;
|
|
|
|
|
|
|
|
|
|
cleanup();
|
|
|
|
|
|
|
|
|
|
// Stop the main io_service to exit the thread
|
|
|
|
|
io_service.stop();
|
|
|
|
|
if (callback) { caller->getIoService().post(callback); }
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Also post to the pause io_service
|
|
|
|
|
this->pause_io_service.post([this, caller = getSelf(), callback]()
|
|
|
|
|
{
|
|
|
|
|
std::cout << "Thread '" << name << "': handling exitThread "
|
|
|
|
|
"(pause queue)." << std::endl;
|
|
|
|
|
|
|
|
|
|
cleanup();
|
|
|
|
|
|
|
|
|
|
// Stop both io_services to exit the thread
|
|
|
|
|
pause_io_service.stop();
|
|
|
|
|
io_service.stop();
|
|
|
|
|
if (callback) { caller->getIoService().post(callback); }
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ComponentThread::pauseThreadReq(std::function<void()> callback)
|
|
|
|
|
{
|
|
|
|
|
this->getIoService().post([this, caller = getSelf(), callback]()
|
|
|
|
|
{
|
|
|
|
|
std::cout << "Thread '" << name << "': handling pauseThread."
|
|
|
|
|
<< std::endl;
|
|
|
|
|
|
|
|
|
|
if (callback) {
|
|
|
|
|
caller->getIoService().post(callback);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Reset the pause io_service before running to ensure it can run again
|
|
|
|
|
pause_io_service.reset();
|
|
|
|
|
// Run the pause io_service to block this thread
|
|
|
|
|
pause_io_service.run();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ComponentThread::resumeThreadReq(std::function<void()> callback)
|
|
|
|
|
{
|
|
|
|
|
// Post to the pause_io_service to unblock the paused thread
|
|
|
|
|
pause_io_service.post([this, caller = getSelf(), callback]()
|
|
|
|
|
{
|
|
|
|
|
std::cout << "Thread '" << name << "': handling resumeThread."
|
|
|
|
|
<< std::endl;
|
|
|
|
|
|
|
|
|
|
if (callback) {
|
|
|
|
|
caller->getIoService().post(callback);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Stop the pause_io_service to unblock the thread
|
|
|
|
|
pause_io_service.stop();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int threadsKilledCount;
|
|
|
|
|
|
|
|
|
|
void ComponentThread::exceptionInd(ComponentThread& thread)
|
|
|
|
|
{
|
|
|
|
|
if (this->id != MRNTT)
|
|
|
|
|
{
|
|
|
|
|
throw std::runtime_error(std::string(__func__)
|
|
|
|
|
+ ": invoked on non-mrntt thread " + thread.name);
|
2025-01-11 04:34:49 -04:00
|
|
|
}
|
2025-07-28 07:20:44 -04:00
|
|
|
|
|
|
|
|
// Post the exception to the mrntt thread.
|
|
|
|
|
this->getIoService().post(
|
|
|
|
|
[&thread]()
|
|
|
|
|
{
|
|
|
|
|
std::cerr << "Mrntt: Exception occurred: in thread "
|
|
|
|
|
<< thread.name << ". Killing Salmanoff." << "\n";
|
|
|
|
|
|
|
|
|
|
threadsKilledCount = 0;
|
|
|
|
|
for (auto &currThread : ComponentThread::componentThreads)
|
|
|
|
|
{
|
|
|
|
|
if (currThread->id == MRNTT)
|
|
|
|
|
{ continue; }
|
|
|
|
|
|
|
|
|
|
currThread->exitThreadReq(
|
|
|
|
|
[]()
|
|
|
|
|
{
|
|
|
|
|
++threadsKilledCount;
|
|
|
|
|
if (threadsKilledCount < ComponentThread::N_ITEMS - 1)
|
|
|
|
|
{ return; }
|
|
|
|
|
|
|
|
|
|
for (auto &currThreadJ
|
|
|
|
|
: ComponentThread::componentThreads)
|
|
|
|
|
{
|
|
|
|
|
if (currThreadJ->id == MRNTT)
|
|
|
|
|
{ continue; }
|
|
|
|
|
|
|
|
|
|
currThreadJ->thread.join();
|
|
|
|
|
}
|
2025-07-30 09:09:38 -04:00
|
|
|
|
|
|
|
|
mrntt::mrntt->keepLooping = false;
|
2025-07-28 07:20:44 -04:00
|
|
|
mrntt::mrntt->getIoService().stop();
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
);
|
2025-01-11 04:34:49 -04:00
|
|
|
}
|
|
|
|
|
|
2025-07-22 06:48:04 -04:00
|
|
|
} // namespace smo
|