#include #include #include #include #include #include namespace sscl { PuppetApplication::PuppetApplication( const std::vector> &threads) : componentThreads(threads) { } class PuppetApplication::PuppetThreadLifetimeMgmtOp : public NonPostedAsynchronousContinuation { public: PuppetThreadLifetimeMgmtOp( PuppetApplication &parent, unsigned int nThreads, Callback callback) : NonPostedAsynchronousContinuation(callback), loop(nThreads), parent(parent) {} public: AsynchronousLoop loop; PuppetApplication &parent; public: void joltAllPuppetThreadsReq1( [[maybe_unused]] std::shared_ptr context ) { loop.incrementSuccessOrFailureDueTo(true); if (!loop.isComplete()) { return; } parent.threadsHaveBeenJolted = true; callOriginalCb(); } void executeGenericOpOnAllPuppetThreadsReq1( [[maybe_unused]] std::shared_ptr context ) { loop.incrementSuccessOrFailureDueTo(true); if (!loop.isComplete()) { return; } callOriginalCb(); } void exitAllPuppetThreadsReq1( [[maybe_unused]] std::shared_ptr context ) { loop.incrementSuccessOrFailureDueTo(true); if (!loop.isComplete()) { return; } for (auto& thread : parent.componentThreads) { thread->thread.join(); } callOriginalCb(); } }; void PuppetApplication::joltAllPuppetThreadsReq( Callback callback ) { if (threadsHaveBeenJolted) { std::cout << "Mrntt: All puppet threads already JOLTed. " << "Skipping JOLT request." << "\n"; callback.callbackFn(); return; } // If no threads, set flag and call callback immediately if (componentThreads.size() == 0 && callback.callbackFn) { threadsHaveBeenJolted = true; callback.callbackFn(); return; } // Create a counter to track when all threads have been jolted auto request = std::make_shared( *this, componentThreads.size(), callback); for (auto& thread : componentThreads) { thread->joltThreadReq( thread, {request, std::bind( &PuppetThreadLifetimeMgmtOp::joltAllPuppetThreadsReq1, request.get(), request)}); } } void PuppetApplication::startAllPuppetThreadsReq( Callback callback ) { // If no threads, call callback immediately if (componentThreads.size() == 0 && callback.callbackFn) { callback.callbackFn(); return; } // Create a counter to track when all threads have started auto request = std::make_shared( *this, componentThreads.size(), callback); for (auto& thread : componentThreads) { thread->startThreadReq( {request, std::bind( &PuppetThreadLifetimeMgmtOp::executeGenericOpOnAllPuppetThreadsReq1, request.get(), request)}); } } void PuppetApplication::pauseAllPuppetThreadsReq( Callback callback ) { // If no threads, call callback immediately if (componentThreads.size() == 0 && callback.callbackFn) { callback.callbackFn(); return; } // Create a counter to track when all threads have paused auto request = std::make_shared( *this, componentThreads.size(), callback); for (auto& thread : componentThreads) { thread->pauseThreadReq( {request, std::bind( &PuppetThreadLifetimeMgmtOp::executeGenericOpOnAllPuppetThreadsReq1, request.get(), request)}); } } void PuppetApplication::resumeAllPuppetThreadsReq( Callback callback ) { // If no threads, call callback immediately if (componentThreads.size() == 0 && callback.callbackFn) { callback.callbackFn(); return; } // Create a counter to track when all threads have resumed auto request = std::make_shared( *this, componentThreads.size(), callback); for (auto& thread : componentThreads) { thread->resumeThreadReq( {request, std::bind( &PuppetThreadLifetimeMgmtOp::executeGenericOpOnAllPuppetThreadsReq1, request.get(), request)}); } } void PuppetApplication::exitAllPuppetThreadsReq( Callback callback ) { // If no threads, call callback immediately if (componentThreads.size() == 0 && callback.callbackFn) { callback.callbackFn(); return; } // Create a counter to track when all threads have exited auto request = std::make_shared( *this, componentThreads.size(), callback); for (auto& thread : componentThreads) { thread->exitThreadReq( {request, std::bind( &PuppetThreadLifetimeMgmtOp::executeGenericOpOnAllPuppetThreadsReq1, request.get(), request)}); } } void PuppetApplication::distributeAndPinThreadsAcrossCpus() { int cpuCount = ComponentThread::getAvailableCpuCount(); // Distribute and pin threads across CPUs int threadIndex = 0; for (auto& thread : componentThreads) { int targetCpu = threadIndex % cpuCount; thread->pinToCpu(targetCpu); ++threadIndex; } std::cout << __func__ << ": Distributed " << threadIndex << " threads " << "across " << cpuCount << " CPUs\n"; } } // namespace sscl