Threading: run all code in PThreads, add JOLTing & exception bubbling
This commit significantly restructures the way we setup threading in SMO. We now don't use the CRT main() thread at all. It's only used as a mechanism to ensure that Marionette doesn't execute before global constructors have been executed. JOLTing: This is a simple ASIO post()ed message that makes each thread setup its thread-local data pointer to its own ComponentThread object, and then enter its main ASIO run() loop to await commands from Marionette. Exception bubbling: We now cleanly cause mind threads to report their exceptions to marionette, so that marionette can cleanly shut the mind down in an orderly fashion. Thread Control messaging API: A namespace of asynchronous messages to be post()ed to threads to control them. It enables us to pause and resume threads. This will be very useful for Marionette when we add the ability for it to suspend Salmanoff's running mind, inject new goals, inspect current state, etc; and then resume the mind's execution.
This commit is contained in:
@@ -1,5 +1,10 @@
|
||||
add_library(marionette STATIC
|
||||
marionette.cpp
|
||||
salmanoff.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(marionette
|
||||
smocore
|
||||
)
|
||||
|
||||
target_include_directories(marionette PUBLIC
|
||||
|
||||
@@ -1,9 +1,110 @@
|
||||
#include <config.h>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <exception>
|
||||
#include <opts.h>
|
||||
#include <componentThread.h>
|
||||
#include <marionette/marionette.h>
|
||||
|
||||
namespace mrntt {
|
||||
namespace smo {
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
CrtCommandLineArgs crtCommandLineArgs(0, nullptr, nullptr);
|
||||
|
||||
void CrtCommandLineArgs::set(int argc, char *argv[], char *envp[])
|
||||
{
|
||||
return 0;
|
||||
crtCommandLineArgs = CrtCommandLineArgs(argc, argv, envp);
|
||||
}
|
||||
|
||||
} // namespace mrntt
|
||||
namespace mrntt {
|
||||
std::atomic<int> exitCode;
|
||||
}
|
||||
|
||||
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 = 0;
|
||||
|
||||
try {
|
||||
OptionParser &options = OptionParser::getOptions();
|
||||
|
||||
std::cout << __func__ << ": " << PACKAGE_NAME << " " << PACKAGE_VERSION
|
||||
<< std::endl;
|
||||
|
||||
try {
|
||||
options.parseArguments(
|
||||
crtCommandLineArgs.argc, crtCommandLineArgs.argv,
|
||||
crtCommandLineArgs.envp);
|
||||
|
||||
std::cout << __func__ << ": " << options.stringifyOptions()
|
||||
<< std::endl;
|
||||
}
|
||||
catch (const std::invalid_argument& e)
|
||||
{
|
||||
std::cerr << __func__ << ": Exception occurred: " << e.what()
|
||||
<< '\n' << options.getUsage() << '\n';
|
||||
|
||||
mrntt::exitCode = EXIT_FAILURE;
|
||||
return;
|
||||
}
|
||||
|
||||
if (options.printUsage)
|
||||
{
|
||||
std::cout << __func__ << ": " << options.getUsage() << std::endl;
|
||||
mrntt::exitCode = EXIT_SUCCESS;
|
||||
return;
|
||||
}
|
||||
|
||||
int ret = smo::initializeSalmanoff();
|
||||
if (ret != 0)
|
||||
{
|
||||
std::cerr << __func__ << ": Initialization failed with code: "
|
||||
<< ret << std::endl;
|
||||
mrntt::exitCode = ret;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Start the threads */
|
||||
for (auto& componentThread : smo::ComponentThread::componentThreads)
|
||||
{
|
||||
// Post startThread() to the event loop of all threads except MRNTT.
|
||||
if (componentThread->id == ComponentThread::MRNTT) { continue; }
|
||||
|
||||
// JOLT the thread.
|
||||
componentThread->getIoService().post([componentThread]()
|
||||
{ componentThread->getIoService().stop(); }
|
||||
);
|
||||
|
||||
// Now tell it to execute its initialization sequence.
|
||||
componentThread->startThreadReq();
|
||||
}
|
||||
|
||||
body::body->getIoService().post([]{
|
||||
throw std::runtime_error("test exception");
|
||||
});
|
||||
|
||||
std::cout << __func__ << ": Entering event loop" << "\n";
|
||||
self.getIoService().reset();
|
||||
self.getIoService().run();
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
std::cerr << __func__ << ": Exception occurred: " << e.what()
|
||||
<< std::endl;
|
||||
mrntt::exitCode = EXIT_FAILURE;
|
||||
return;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cerr << __func__ << ": Unknown exception occurred" << std::endl;
|
||||
mrntt::exitCode = EXIT_FAILURE;
|
||||
return;
|
||||
}
|
||||
|
||||
std::cout << __func__ << ": Exiting normally" << std::endl;
|
||||
}
|
||||
|
||||
|
||||
} // namespace smo
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
#include <iostream>
|
||||
#include <deviceManager/deviceManager.h>
|
||||
#include <senseApis/senseApiManager.h>
|
||||
|
||||
namespace smo {
|
||||
|
||||
int initializeSalmanoff(void)
|
||||
{
|
||||
std::cout << __func__ << ": Entered." << std::endl;
|
||||
|
||||
device::DeviceManager::getInstance().collateAllDeviceSpecs();
|
||||
device::DeviceManager::getInstance().parseAllDeviceSpecs();
|
||||
std::cout << device::DeviceManager::stringifyDeviceSpecs() << std::endl;
|
||||
sense_api::SenseApiManager::getInstance().loadAllSenseApiLibsFromOptions();
|
||||
std::cout << sense_api::SenseApiManager::getInstance().stringifyLibs()
|
||||
<< std::endl;
|
||||
std::cerr << "About to initializeAllSenseApiLibs" << std::endl;
|
||||
sense_api::SenseApiManager::getInstance().initializeAllSenseApiLibs();
|
||||
std::cerr << "About to attachAllSenseDevicesFromSpecs" << std::endl;
|
||||
sense_api::SenseApiManager::getInstance().attachAllSenseDevicesFromSpecs();
|
||||
std::cerr << "Done attachAllSenseDevicesFromSpecs" << std::endl;
|
||||
|
||||
std::cout << __func__ << ": Done." << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace smo
|
||||
Reference in New Issue
Block a user