CompThreads: create execOpOnAllMindThreads common helper
This allows us to execute an op on all mind threads without having to repeatedly write loops. We've implemented wrappers to handle start, pause, resume, exit and JOLT sequences.
This commit is contained in:
+155
-35
@@ -214,11 +214,152 @@ void ComponentThread::resumeThreadReq(std::function<void()> callback)
|
||||
});
|
||||
}
|
||||
|
||||
static int threadsKilledCount;
|
||||
void ComponentThread::joltThreadReq(std::function<void()> callback)
|
||||
{
|
||||
this->getIoService().post([this, caller = getSelf(), callback]()
|
||||
{
|
||||
std::cout << "Thread '" << name << "': handling JOLT request." << "\n";
|
||||
|
||||
// Stop the main io_service to jolt the thread
|
||||
io_service.stop();
|
||||
|
||||
if (callback) {
|
||||
caller->getIoService().post(callback);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
struct AllMindThreadsOpReqContext {
|
||||
AllMindThreadsOpReqContext() : nThreadsProcessed(0) {}
|
||||
|
||||
int nThreadsProcessed;
|
||||
};
|
||||
|
||||
static const std::string getOpName(ComponentThread::ThreadOp op)
|
||||
{
|
||||
if (op < (ComponentThread::ThreadOp)0
|
||||
|| op > ComponentThread::ThreadOp::JOLT)
|
||||
{
|
||||
throw std::runtime_error(std::string(__func__)
|
||||
+ ": Invalid operation");
|
||||
}
|
||||
|
||||
switch (op)
|
||||
{
|
||||
case ComponentThread::ThreadOp::START: return "starting";
|
||||
case ComponentThread::ThreadOp::PAUSE: return "pausing";
|
||||
case ComponentThread::ThreadOp::RESUME: return "resuming";
|
||||
case ComponentThread::ThreadOp::EXIT: return "exiting";
|
||||
case ComponentThread::ThreadOp::JOLT: return "jolting";
|
||||
default: return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
void ComponentThread::execOpOnAllMindThreadsReq(
|
||||
ThreadOp op, std::function<void()> callback
|
||||
)
|
||||
{
|
||||
std::shared_ptr<ComponentThread> self = getSelf();
|
||||
// Check that we're being called from the marionette thread
|
||||
if (self->id != MRNTT)
|
||||
{
|
||||
throw std::runtime_error(std::string(__func__)
|
||||
+ ": invoked on non-mrntt thread " + self->name);
|
||||
}
|
||||
|
||||
std::cout << "Mrntt: " << getOpName(op) << " all mind threads." << "\n";
|
||||
|
||||
auto context = std::make_shared<AllMindThreadsOpReqContext>();
|
||||
const int N_THREADS_EXCEPT_MRNTT = ComponentThread::N_ITEMS - 1;
|
||||
|
||||
for (auto &currThread : ComponentThread::componentThreads)
|
||||
{
|
||||
if (currThread->id == ComponentThread::MRNTT)
|
||||
{ continue; }
|
||||
|
||||
auto threadCallback = [context, callback, N_THREADS_EXCEPT_MRNTT, op]()
|
||||
{
|
||||
++context->nThreadsProcessed;
|
||||
if (context->nThreadsProcessed < N_THREADS_EXCEPT_MRNTT)
|
||||
{ return; }
|
||||
|
||||
if (op == ThreadOp::EXIT)
|
||||
{
|
||||
// Special cleanup for exit operations
|
||||
for (auto &currThreadJ : ComponentThread::componentThreads)
|
||||
{
|
||||
if (currThreadJ->id == ComponentThread::MRNTT)
|
||||
{ continue; }
|
||||
|
||||
currThreadJ->thread.join();
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "Mrntt: all mind threads done " << getOpName(op) << "."
|
||||
<< "\n";
|
||||
|
||||
if (callback) { callback(); }
|
||||
};
|
||||
|
||||
switch (op) {
|
||||
case ThreadOp::START:
|
||||
currThread->startThreadReq(threadCallback);
|
||||
break;
|
||||
case ThreadOp::PAUSE:
|
||||
currThread->pauseThreadReq(threadCallback);
|
||||
break;
|
||||
case ThreadOp::RESUME:
|
||||
currThread->resumeThreadReq(threadCallback);
|
||||
break;
|
||||
case ThreadOp::EXIT:
|
||||
currThread->exitThreadReq(threadCallback);
|
||||
break;
|
||||
case ThreadOp::JOLT:
|
||||
currThread->joltThreadReq(threadCallback);
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("Invalid operation");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ComponentThread::startAllMindThreadsReq(std::function<void()> callback)
|
||||
{
|
||||
execOpOnAllMindThreadsReq(ThreadOp::START, callback);
|
||||
}
|
||||
|
||||
void ComponentThread::pauseAllMindThreadsReq(std::function<void()> callback)
|
||||
{
|
||||
execOpOnAllMindThreadsReq(ThreadOp::PAUSE, callback);
|
||||
}
|
||||
|
||||
void ComponentThread::resumeAllMindThreadsReq(std::function<void()> callback)
|
||||
{
|
||||
execOpOnAllMindThreadsReq(ThreadOp::RESUME, callback);
|
||||
}
|
||||
|
||||
void ComponentThread::exitAllMindThreadsReq(std::function<void()> callback)
|
||||
{
|
||||
execOpOnAllMindThreadsReq(ThreadOp::EXIT, callback);
|
||||
}
|
||||
|
||||
void ComponentThread::joltAllMindThreadsReq(std::function<void()> callback)
|
||||
{
|
||||
execOpOnAllMindThreadsReq(ThreadOp::JOLT, callback);
|
||||
}
|
||||
|
||||
/* This shouldn't take a callback because the caller shouldn't expect to
|
||||
* Mrntt to send a reply signal to it. Sending this Indication means that
|
||||
* Mrntt will send the calling thread an exitThreadReq. When the caller
|
||||
* processes that exitThreadReq(), the caller will exit its event loop and then
|
||||
* terminate.
|
||||
*
|
||||
* Even if Mrntt sent a RDY response, the caller shouldn't actually be executing
|
||||
* any longer to receive it anyway.
|
||||
*/
|
||||
void ComponentThread::exceptionInd(ComponentThread& thread)
|
||||
{
|
||||
if (this->id != MRNTT)
|
||||
if (this->id != ComponentThread::MRNTT)
|
||||
{
|
||||
throw std::runtime_error(std::string(__func__)
|
||||
+ ": invoked on non-mrntt thread " + thread.name);
|
||||
@@ -226,40 +367,19 @@ void ComponentThread::exceptionInd(ComponentThread& thread)
|
||||
|
||||
// Post the exception to the mrntt thread.
|
||||
this->getIoService().post(
|
||||
[&thread]()
|
||||
[&thread]()
|
||||
{
|
||||
std::cerr << "Mrntt: Exception occurred: in thread "
|
||||
<< thread.name << ". Killing Salmanoff." << "\n";
|
||||
|
||||
ComponentThread::exitAllMindThreadsReq(
|
||||
[]()
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
mrntt::mrntt->keepLooping = false;
|
||||
mrntt::mrntt->getIoService().stop();
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
mrntt::mrntt->keepLooping = false;
|
||||
mrntt::mrntt->getIoService().stop();
|
||||
std::cout << "Mrntt: Signaled main loop to exit." << "\n";
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace smo
|
||||
|
||||
Reference in New Issue
Block a user