cde2737876
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.
148 lines
3.6 KiB
C++
148 lines
3.6 KiB
C++
#include <config.h>
|
|
#include <chrono>
|
|
#include <iostream>
|
|
#include <functional>
|
|
#include <componentThread.h>
|
|
#include <deviceManager/deviceReattacher.h>
|
|
#include <deviceManager/deviceManager.h>
|
|
#include <marionette/marionetteThread.h>
|
|
|
|
namespace smo {
|
|
namespace device {
|
|
|
|
namespace {
|
|
|
|
constexpr unsigned int reattachInFlightStaleThresholdMultiplier = 4;
|
|
|
|
} // namespace
|
|
|
|
DeviceReattacher::DeviceReattacher(
|
|
DeviceManager& parent, std::shared_ptr<sscl::ComponentThread> ioThread)
|
|
: parent(parent), ioThread(ioThread), shouldContinue(false),
|
|
timer(ioThread->getIoService())
|
|
{
|
|
}
|
|
|
|
mrntt::MrnttNonViralPostingInvoker DeviceReattacher::reattachKnownListCReq(
|
|
[[maybe_unused]] std::exception_ptr &exceptionPtr,
|
|
[[maybe_unused]] std::function<void()> callback)
|
|
{
|
|
sscl::MultiOperationResultSet results = co_await
|
|
parent.attachAllUnattachedDevicesFromKnownListCReq();
|
|
if (results.nTotal > 0)
|
|
{
|
|
std::cout << "DeviceReattacher: Successfully reattached "
|
|
<< results.nSucceeded << " of " << results.nTotal
|
|
<< " devices" << std::endl;
|
|
}
|
|
|
|
co_return;
|
|
}
|
|
|
|
void DeviceReattacher::start()
|
|
{
|
|
shouldContinue = true;
|
|
scheduleNextTimeout();
|
|
}
|
|
|
|
void DeviceReattacher::stop()
|
|
{
|
|
{
|
|
sscl::SpinLock::Guard lock(shouldContinueLock);
|
|
shouldContinue = false;
|
|
reattachOpInFlight = false;
|
|
/** EXPLANATION:
|
|
* Do not call reattachCReqInvoker.reset() here. Forcibly destroying
|
|
* the invoker would tear down an in-flight reattach coroutine frame
|
|
* mid-operation. During normal program teardown the optional (and
|
|
* its invoker) are destroyed with the rest of the binary anyway; leave
|
|
* a running reattach time to finish if shutdown races with it.
|
|
*/
|
|
}
|
|
|
|
timer.cancel();
|
|
}
|
|
|
|
void DeviceReattacher::scheduleNextTimeout()
|
|
{
|
|
if (!shouldContinue) {
|
|
return;
|
|
}
|
|
|
|
// Schedule the next timeout using the configured period
|
|
timer.expires_from_now(
|
|
boost::posix_time::milliseconds(
|
|
CONFIG_MRNTT_DEVMGR_REATTACHER_PERIOD_MS));
|
|
|
|
timer.async_wait(
|
|
std::bind(&DeviceReattacher::onTimeout, this, std::placeholders::_1));
|
|
}
|
|
|
|
void DeviceReattacher::holdReattachCReq()
|
|
{
|
|
reattachOpInFlight = true;
|
|
lastReattachReqTimestamp = std::chrono::steady_clock::now();
|
|
|
|
reattachCReqInvoker.reset();
|
|
reattachCReqInvoker.emplace(reattachKnownListCReq(
|
|
reattachLifetimeExceptionPtr,
|
|
[this]()
|
|
{
|
|
sscl::SpinLock::Guard lock(shouldContinueLock);
|
|
reattachOpInFlight = false;
|
|
}));
|
|
}
|
|
|
|
void DeviceReattacher::onTimeout(const boost::system::error_code& error)
|
|
{
|
|
// Timer was cancelled, which is expected when stopping
|
|
if (error == boost::asio::error::operation_aborted) {
|
|
return;
|
|
}
|
|
|
|
if (error)
|
|
{
|
|
std::cerr << "DeviceReattacher: Timer error: " << error.message()
|
|
<< std::endl;
|
|
return;
|
|
}
|
|
|
|
sscl::SpinLock::Guard lock(shouldContinueLock);
|
|
if (!shouldContinue) {
|
|
return;
|
|
}
|
|
|
|
const auto staleThreshold = std::chrono::milliseconds(
|
|
reattachInFlightStaleThresholdMultiplier
|
|
* CONFIG_MRNTT_DEVMGR_REATTACHER_PERIOD_MS);
|
|
|
|
// Attempt to reattach all unattached devices from the known list
|
|
if (!reattachOpInFlight)
|
|
{
|
|
holdReattachCReq();
|
|
}
|
|
else
|
|
{
|
|
const auto elapsedSinceLastReattachReq =
|
|
std::chrono::steady_clock::now() - lastReattachReqTimestamp;
|
|
|
|
if (elapsedSinceLastReattachReq >= staleThreshold)
|
|
{
|
|
std::cerr << "DeviceReattacher: Reattach op still in flight after "
|
|
<< std::chrono::duration_cast<std::chrono::milliseconds>(
|
|
elapsedSinceLastReattachReq).count()
|
|
<< "ms (threshold "
|
|
<< staleThreshold.count()
|
|
<< "ms); forcing a new reattach request."
|
|
<< std::endl;
|
|
holdReattachCReq();
|
|
}
|
|
}
|
|
|
|
// Schedule the next timeout
|
|
scheduleNextTimeout();
|
|
}
|
|
|
|
} // namespace device
|
|
} // namespace smo
|