Files
salmanoff/smocore/deviceManager/deviceReattacher.cpp
T
hayodea 87a8de9a2b StimProd,DevReattacher: use CDaemon nonviral nursery coro
We ported these two daemons over to the new nursery mechanism and
they work nicely.
2026-06-09 19:47:44 -04:00

126 lines
3.3 KiB
C++

#include <config.h>
#include <iostream>
#include <chrono>
#include <functional>
#include <componentThread.h>
#include <adapters/boostAsio/deadlineTimerAReq.h>
#include <deviceManager/deviceReattacher.h>
#include <deviceManager/deviceManager.h>
#include <spinscale/co/nonViralCompletion.h>
namespace smo {
namespace device {
namespace {
long computeTimesliceResidueMs(
long workDurationMs, long periodMs)
{
if (workDurationMs >= periodMs) {
return 0;
}
return periodMs - workDurationMs;
}
long durationMsSince(
const std::chrono::high_resolution_clock::time_point &startStamp,
const std::chrono::high_resolution_clock::time_point &endStamp)
{
const auto duration = endStamp - startStamp;
return std::chrono::duration_cast<std::chrono::milliseconds>(
duration).count();
}
} // namespace
DeviceReattacher::DeviceReattacher(
DeviceManager& parent, std::shared_ptr<sscl::ComponentThread> ioThread)
: parent(parent),
ioThread(ioThread), daemonTimer(ioThread->getIoContext())
{
/** EXPLANATION:
* deviceReattacherCDaemon is a dynamic posting non-viral coroutine: start()
* passes ExplicitPostTarget{ioThread->getIoContext()} so the daemon body
* always runs on ioThread. daemonTimer is reused each loop iteration.
* Each timeslice runs attach work first, then sleeps only the period
* residue so reattach polls stay on a wall-clock cadence.
*/
}
sscl::co::DynamicNonViralPostingInvoker
DeviceReattacher::deviceReattacherCDaemon(
[[maybe_unused]] sscl::co::ExplicitPostTarget postTarget,
[[maybe_unused]] std::exception_ptr &exceptionPtr,
[[maybe_unused]] std::function<void()> callback,
sscl::SyncCancelerForAsyncWork &canceler)
{
boost::asio::io_context &timerIoContext =
sscl::ComponentThread::getSelf()->getIoContext();
const long reattacherPeriodMs = CONFIG_MRNTT_DEVMGR_REATTACHER_PERIOD_MS;
while (!canceler.isCancellationRequested())
{
const auto workStartStamp =
std::chrono::high_resolution_clock::now();
co_await parent.attachAllUnattachedDevicesFromKnownListCReq();
const auto workEndStamp =
std::chrono::high_resolution_clock::now();
const long workDurationMs = durationMsSince(
workStartStamp, workEndStamp);
const long residueMs = computeTimesliceResidueMs(
workDurationMs, reattacherPeriodMs);
const bool expiredNormally = co_await
adapters::boostAsio::getDeadlineTimerAReqAwaiter(
timerIoContext, daemonTimer,
boost::posix_time::milliseconds(residueMs));
if (!expiredNormally) {
break;
}
}
co_return;
}
void DeviceReattacher::start()
{
taskNursery.openAdmission();
taskNursery.launch(
[this](sscl::co::NonViralTaskNursery::Slot::Lease &lease)
{
return deviceReattacherCDaemon(
sscl::co::ExplicitPostTarget{ioThread->getIoContext()},
lease.getExceptionStorage(),
lease.getCallerLambda(),
lease.getSyncCanceler());
},
[](std::exception_ptr &exceptionPtr)
{
sscl::co::NonViralCompletion nvc(exceptionPtr);
if (nvc.hasException())
{
try {
nvc.checkAndRethrowException();
} catch (const std::exception &e) {
std::cerr << "DeviceReattacher: "
<< e.what() << std::endl;
}
}
});
}
void DeviceReattacher::stop()
{
daemonTimer.cancel();
taskNursery.requestCancelOnAll();
taskNursery.closeAdmission();
taskNursery.syncAwaitAllSettlements(ioThread->getIoContext());
}
} // namespace device
} // namespace smo