Libspinscale: Initial top-level SMO port to coroutine framework

We haven't ported everything. Just the top-level methods. We'll
dig in to the leaf stuff later. Surprisingly, this all went without
any real difficulties.

Runs like a charm on first try.
This commit is contained in:
2026-05-24 16:12:29 -04:00
parent c539e6e924
commit cde2737876
44 changed files with 1296 additions and 1530 deletions
+42 -152
View File
@@ -2,11 +2,6 @@
#include <iostream>
#include <opts.h>
#include <componentThread.h>
#include <spinscale/asynchronousContinuation.h>
#include <spinscale/asynchronousLoop.h>
#include <spinscale/callback.h>
#include <spinscale/callableTracer.h>
#include <spinscale/componentThread.h>
#include <mind.h>
#include <mindThread.h>
#include <director/director.h>
@@ -63,17 +58,17 @@ Mind::getComponentThread(sscl::ThreadId id) const
"getComponentThread");
}
// Search through the vector for the thread with matching id
for (auto& thread : componentThreads)
// Search through the vector for the thread with matching id
for (auto& thread : componentThreads)
{
if (thread->id == id) {
if (thread->id == id) {
return std::static_pointer_cast<MindThread>(thread);
}
}
}
// Throw exception if no thread found
throw std::runtime_error(std::string(__func__) +
": No MindThread found with ID "
// Throw exception if no thread found
throw std::runtime_error(std::string(__func__) +
": No MindThread found with ID "
+ std::to_string(static_cast<int>(id)));
}
@@ -88,16 +83,16 @@ Mind::getComponentThread(const std::string& name) const
"getComponentThread");
}
for (auto& thread : componentThreads)
for (auto& thread : componentThreads)
{
if (thread->name == name) {
if (thread->name == name) {
return std::static_pointer_cast<MindThread>(thread);
}
}
// Throw exception if no thread found
throw std::runtime_error(std::string(__func__) +
": No MindThread found with name '" + name + "'");
// Throw exception if no thread found
throw std::runtime_error(std::string(__func__) +
": No MindThread found with name '" + name + "'");
}
std::vector<std::shared_ptr<MindThread>>
@@ -111,152 +106,47 @@ Mind::getMindThreads() const
return mindThreads;
}
class Mind::MindLifetimeMgmtOp
: public sscl::PostedAsynchronousContinuation<mindLifetimeMgmtOpCbFn>
mrntt::MrnttViralNonPostingInvokerT<bool> Mind::initializeCReq()
{
public:
MindLifetimeMgmtOp(
Mind &parent, const std::shared_ptr<sscl::ComponentThread> &caller,
sscl::Callback<mindLifetimeMgmtOpCbFn> callback)
: sscl::PostedAsynchronousContinuation<mindLifetimeMgmtOpCbFn>(
caller, callback),
parent(parent)
{}
public:
Mind &parent;
public:
void initializeReq1_posted(
[[maybe_unused]] std::shared_ptr<MindLifetimeMgmtOp> context
)
try
{
/* Jolt the threads, then start them */
parent.joltAllPuppetThreadsReq(
{context, std::bind(
&MindLifetimeMgmtOp::initializeReq2,
context.get(), context)});
distributeAndPinThreadsAcrossCpus();
}
catch (const std::exception& e)
{
std::cerr << "Salmanoff couldn't distribute the mind threads across "
"the CPUs, so performance may be suboptimal.\n"
"Error: " << e.what() << "\n";
}
void initializeReq2(
[[maybe_unused]] std::shared_ptr<MindLifetimeMgmtOp> context
)
{
std::cout << "Mrntt: All mind threads JOLTed." << "\n";
co_await joltAllPuppetThreadsCReq();
std::cout << "Mrntt: All mind threads JOLTed." << "\n";
parent.startAllPuppetThreadsReq(
{context, std::bind(
&MindLifetimeMgmtOp::initializeReq3,
context.get(), context)});
}
co_await startAllPuppetThreadsCReq();
std::cout << "Mrntt: All mind threads started." << "\n";
void initializeReq3(
[[maybe_unused]] std::shared_ptr<MindLifetimeMgmtOp> context
)
{
std::cout << "Mrntt: All mind threads started." << "\n";
bool bodyInitialized = co_await body.initializeCReq();
std::cout << "Mrntt: Body component initialized." << "\n";
parent.body.initializeReq(
{context, std::bind(
&MindLifetimeMgmtOp::initializeReq4,
context.get(), context, std::placeholders::_1)});
}
void initializeReq4(
[[maybe_unused]] std::shared_ptr<MindLifetimeMgmtOp> context,
bool success
)
{
std::cout << "Mrntt: Body component initialized." << "\n";
callOriginalCb(success);
}
void finalizeReq1_posted(
[[maybe_unused]] std::shared_ptr<MindLifetimeMgmtOp> context
)
{
parent.body.finalizeReq(
{context, std::bind(
&MindLifetimeMgmtOp::finalizeReq2,
context.get(), context, std::placeholders::_1)});
}
void finalizeReq2(
[[maybe_unused]] std::shared_ptr<MindLifetimeMgmtOp> context,
bool success
)
{
if (!success) {
std::cerr << "Mrntt: Body component failed to finalize." << "\n";
} else {
std::cout << "Mrntt: Body component finalized." << "\n";
}
/* If the threads haven't been jolted, we need to do that first, because
* otherwise they'll just enter their main loops and wait for control
* messages from mrntt after processing the exit request.
*/
parent.joltAllPuppetThreadsReq(
{context, std::bind(
&MindLifetimeMgmtOp::finalizeReq3,
context.get(), context)});
}
void finalizeReq3(
[[maybe_unused]] std::shared_ptr<MindLifetimeMgmtOp> context
)
{
std::cout << "Mrntt: All mind threads JOLTed for finalization." << "\n";
parent.exitAllPuppetThreadsReq(
{context, std::bind(
&MindLifetimeMgmtOp::finalizeReq4,
context.get(), context)});
}
void finalizeReq4(
[[maybe_unused]] std::shared_ptr<MindLifetimeMgmtOp> context
)
{
std::cout << "Mrntt: All mind threads exited." << "\n";
callOriginalCb(true);
}
};
void Mind::initializeReq(sscl::Callback<mindLifetimeMgmtOpCbFn> callback)
{
/* Distribute threads across available CPUs */
try
{
distributeAndPinThreadsAcrossCpus();
}
catch (const std::exception& e)
{
std::cerr << "Salmanoff couldn't distribute the mind threads across "
"the CPUs, so performance may be suboptimal.\n"
"Error: " << e.what() << "\n";
}
const auto& caller = sscl::ComponentThread::getSelf();
auto request = std::make_shared<MindLifetimeMgmtOp>(
*this, caller, callback);
mrntt::mrntt.thread->getIoService().post(
STC(std::bind(
&MindLifetimeMgmtOp::initializeReq1_posted,
request.get(), request)));
co_return bodyInitialized;
}
void Mind::finalizeReq(sscl::Callback<mindLifetimeMgmtOpCbFn> callback)
mrntt::MrnttViralNonPostingInvokerT<bool> Mind::finalizeCReq()
{
const auto& caller = sscl::ComponentThread::getSelf();
auto request = std::make_shared<MindLifetimeMgmtOp>(
*this, caller, callback);
bool bodyFinalized = co_await body.finalizeCReq();
if (!bodyFinalized) {
std::cerr << "Mrntt: Body component failed to finalize." << "\n";
} else {
std::cout << "Mrntt: Body component finalized." << "\n";
}
mrntt::mrntt.thread->getIoService().post(
STC(std::bind(
&MindLifetimeMgmtOp::finalizeReq1_posted,
request.get(), request)));
co_await joltAllPuppetThreadsCReq();
std::cout << "Mrntt: All mind threads JOLTed for finalization." << "\n";
co_await exitAllPuppetThreadsCReq();
std::cout << "Mrntt: All mind threads exited." << "\n";
co_return bodyFinalized;
}
} // namespace smo