Files
salmanoff/smocore/marionette/marionette.cpp
T
hayodea 0dc8abaa28 Rework: Modularize Mind
Now we have modularized the Mind class to contain all of its
ComponentThreads. This enables us to run multiple mind instances
within the same SMO process, at least in theory.

We probably won't actually do this, but we want to ensure that the
design is clean enough to enable it.
2025-09-03 14:56:00 -04:00

165 lines
4.3 KiB
C++

#include <config.h>
#include <cstdlib>
#include <iostream>
#include <exception>
#include <opts.h>
#include <typeinfo>
#include <boost/asio/signal_set.hpp>
#include <mind.h>
#include <componentThread.h>
#include <marionette/marionette.h>
#include <salmanoff.h>
namespace smo {
// Global Mind instance
std::shared_ptr<Mind> globalMind = std::make_shared<Mind>();
// Global marionette thread instance
std::shared_ptr<ComponentThread> mrntt::mrntt =
std::make_shared<ComponentThread>(ComponentThread::MRNTT, *globalMind);
CrtCommandLineArgs crtCommandLineArgs(0, nullptr, nullptr);
void CrtCommandLineArgs::set(int argc, char *argv[], char *envp[])
{
crtCommandLineArgs = CrtCommandLineArgs(argc, argv, envp);
}
namespace mrntt {
std::atomic<int> exitCode;
void exitMarionetteLoop()
{
mrntt::mrntt->keepLooping = false;
mrntt::mrntt->getIoService().stop();
std::cout << "Mrntt: Signaled main loop to exit." << "\n";
}
} // namespace mrntt
void ComponentThread::marionetteMain(ComponentThread& self)
{
// Wait for CRT's main() to post us the command line args.
std::cout << __func__ << ": Waiting for command line JOLT" << std::endl;
self.getIoService().run();
self.initializeTls();
mrntt::exitCode = EXIT_SUCCESS;
static boost::asio::signal_set signals(self.getIoService(), SIGINT);
bool callFinalizeReq = false;
try {
// Register SIGINT (Ctrl+C) handler to request user shutdown
signals.async_wait(
[&self](const boost::system::error_code& ec, int /*signal*/)
{
if (ec) { return; }
// Post user shutdown indication
self.userShutdownInd();
}
);
OptionParser &options = OptionParser::getOptions();
std::cout << __func__ << ": " << PACKAGE_NAME << " " << PACKAGE_VERSION
<< std::endl;
options.parseArguments(
crtCommandLineArgs.argc, crtCommandLineArgs.argv,
crtCommandLineArgs.envp);
std::cout << __func__ << ": " << options.stringifyOptions()
<< std::endl;
if (options.printUsage) {
throw JustPrintUsageNoError(options);
}
initializeSalmanoff();
self.getIoService().post([]()
{
// Initialize the global Mind object
globalMind->initialize();
});
std::cout << __func__ << ": Entering event loop" << "\n";
/* 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
* need to post messages to our own event loop to initiate our own
* orderly exit. So we loop here to re-enter the event loop, both
* to receive the ACK messages from the mind threads, and to post
* messages to our own event loop to initiate our own orderly exit.
*/
for (self.keepLooping = true; self.keepLooping;)
{
bool sendExceptionInd = false;
try {
self.getIoService().reset();
self.getIoService().run();
}
catch (const std::exception& e)
{
sendExceptionInd = true;
std::cerr << self.name << ":" << __func__
<< ": Exception occurred: " << e.what() << "\n";
}
catch (...)
{
sendExceptionInd = true;
std::cerr << self.name << ":" << __func__
<< ": Unknown exception occurred" << "\n";
}
if (sendExceptionInd)
{
mrntt::exitCode = EXIT_FAILURE;
self.exceptionInd(self);
}
}
std::cout << __func__ << ": Exited event loop" << "\n";
}
catch (const OptionParser::Exception& e)
{
std::ostream *out = &std::cout;
std::string outUsageMsg;
if (typeid(e) == typeid(OptionsParserError))
{
mrntt::exitCode = EXIT_FAILURE;
out = &std::cerr;
outUsageMsg = std::string(__func__) + ": ";
}
*out << outUsageMsg << e.what() << std::endl;
callFinalizeReq = true;
}
catch (const std::exception& e)
{
std::cerr << __func__ << ": Exception occurred: " << e.what()
<< std::endl;
mrntt::exitCode = EXIT_FAILURE;
callFinalizeReq = true;
}
catch (...)
{
std::cerr << __func__ << ": Unknown exception occurred" << std::endl;
mrntt::exitCode = EXIT_FAILURE;
callFinalizeReq = true;
}
if (callFinalizeReq)
{
globalMind->finalizeReq([]{
mrntt::mrntt->getIoService().stop();
});
self.getIoService().reset();
self.getIoService().run();
}
shutdownSalmanoff();
}
} // namespace smo