DevMgr: Move at/detachSenseDevs[FromSpecs] into DeviceMgr::

This is logically cleaner and it begins preparing our next set
of restructuring changes. To wit: we're revamping the device
manager to distinguish between devices and their roles.
This commit is contained in:
2025-09-27 23:16:46 -04:00
parent 52567406ca
commit e6b8d3e85d
5 changed files with 366 additions and 359 deletions
+336 -1
View File
@@ -8,9 +8,11 @@
#include <opts.h>
#include <asynchronousContinuation.h>
#include <callback.h>
#include <componentThread.h>
#include <deviceManager/deviceManager.h>
#include <senseApis/senseApiManager.h>
#include <marionette/marionette.h>
#include <mind.h>
namespace smo {
namespace device {
@@ -60,7 +62,7 @@ public:
[[maybe_unused]] std::shared_ptr<NewDeviceAttachmentSpecInd> context
)
{
sense_api::SenseApiManager::getInstance().attachSenseDeviceReq(
DeviceManager::getInstance().attachSenseDeviceReq(
spec,
{context, std::bind(
&NewDeviceAttachmentSpecInd::newDeviceAttachmentSpecInd2,
@@ -148,5 +150,338 @@ void DeviceManager::newDeviceAttachmentSpecInd(
continuation.get(), continuation));
}
class DeviceManager::AttachSenseDeviceReq
: public PostedAsynchronousContinuation<attachSenseDeviceReqCbFn>
{
public:
AttachSenseDeviceReq(
const std::shared_ptr<DeviceAttachmentSpec>& spec,
const std::shared_ptr<ComponentThread> &caller,
Callback<attachSenseDeviceReqCbFn> cb)
: PostedAsynchronousContinuation<attachSenseDeviceReqCbFn>(
caller, cb),
spec(spec)
{}
public:
void attachSenseDeviceReq1_posted(
[[maybe_unused]] std::shared_ptr<AttachSenseDeviceReq> context
)
{
if (caller->id != ComponentThread::MRNTT)
{
std::cerr << std::string(__func__)
<< ": executed on non-mrntt thread: "
<< caller->name << std::endl;
callOriginalCb(false, spec);
return;
}
/** FIXME:
* We should acquire a spinlock here to ensure that the device isn't
* added in the interim while the async op executes.
*/
auto libOpt = sense_api::SenseApiManager::getInstance()
.getSenseApiLibByApiName(spec->api);
if (!libOpt)
{
std::cerr << std::string(__func__) + ": No library found for API '"
<< spec->api << "'" << std::endl;
callOriginalCb(false, spec);
return;
}
auto& lib = *libOpt.value();
if (!lib.senseApiDesc.sal_mgmt_libOps.attachDeviceReq)
{
std::cerr << std::string(__func__) + ": attachDeviceReq() is NULL "
"for library '" << lib.libraryPath << "'" << std::endl;
callOriginalCb(false, spec);
return;
}
/** EXPLANATION:
* We pass in either the body or world thread here, depending on whether
* the device is an introspector (idev) or extrospector (edev).
*
* Introspectors are attached to the body thread; extrospectors are
* attached to the world thread.
*/
std::shared_ptr<ComponentThread> threadForAttachment;
if (spec->sensorType == 'e')
{
threadForAttachment = mind::globalMind->world.thread;
std::cout << __func__ << ": Attaching edev "
<< spec->deviceIdentifier << " to world thread" << "\n";
}
else
{
threadForAttachment = mind::globalMind->body.thread;
std::cout << __func__ << ": Attaching non-edev "
<< spec->deviceIdentifier << " to body thread" << "\n";
}
lib.senseApiDesc.sal_mgmt_libOps.attachDeviceReq(
spec, threadForAttachment,
{context, std::bind(
&AttachSenseDeviceReq::attachSenseDeviceReq2,
context.get(), context,
std::placeholders::_1, std::placeholders::_2)});
}
void attachSenseDeviceReq2(
[[maybe_unused]] std::shared_ptr<AttachSenseDeviceReq> context,
bool success,
std::shared_ptr<DeviceAttachmentSpec> deviceSpec
)
{
callOriginalCb(success, deviceSpec);
}
void detachSenseDeviceReq1_posted(
[[maybe_unused]] std::shared_ptr<DetachSenseDeviceReq> context
)
{
if (caller->id != ComponentThread::MRNTT)
{
std::cerr << std::string(__func__)
<< ": executed on non-mrntt thread: "
<< caller->name << std::endl;
callOriginalCb(false, spec);
return;
}
/** FIXME:
* We should acquire a spinlock here to ensure that the device isn't
* removed in the interim while the async op executes.
*/
auto libOpt = sense_api::SenseApiManager::getInstance()
.getSenseApiLibByApiName(spec->api);
if (!libOpt)
{
std::cerr << std::string(__func__) + ": No library found for API '"
<< spec->api << "'" << std::endl;
callOriginalCb(false, spec);
return;
}
auto& lib = *libOpt.value();
if (!lib.senseApiDesc.sal_mgmt_libOps.detachDeviceReq)
{
std::cerr << std::string(__func__) + ": detachDeviceReq() is NULL "
"for library '" << lib.libraryPath << "'" << std::endl;
callOriginalCb(false, spec);
return;
}
lib.senseApiDesc.sal_mgmt_libOps.detachDeviceReq(
spec,
{context, std::bind(
&DetachSenseDeviceReq::detachSenseDeviceReq2,
context.get(), context,
std::placeholders::_1, std::placeholders::_2)});
}
void detachSenseDeviceReq2(
[[maybe_unused]] std::shared_ptr<DetachSenseDeviceReq> context,
bool success,
std::shared_ptr<DeviceAttachmentSpec> deviceSpec
)
{
callOriginalCb(success, deviceSpec);
}
public:
std::shared_ptr<DeviceAttachmentSpec> spec;
};
void DeviceManager::attachSenseDeviceReq(
const std::shared_ptr<DeviceAttachmentSpec>& spec,
Callback<attachSenseDeviceReqCbFn> cb
)
{
const auto& caller = ComponentThread::getSelf();
auto request = std::make_shared<AttachSenseDeviceReq>(
spec, caller, cb);
mrntt::mrntt.thread->getIoService().post(
std::bind(
&AttachSenseDeviceReq::attachSenseDeviceReq1_posted,
request.get(), request));
}
void DeviceManager::detachSenseDeviceReq(
const std::shared_ptr<DeviceAttachmentSpec>& spec,
Callback<detachSenseDeviceReqCbFn> cb
)
{
const auto& caller = ComponentThread::getSelf();
auto request = std::make_shared<DetachSenseDeviceReq>(
spec, caller, cb);
mrntt::mrntt.thread->getIoService().post(
std::bind(
&DetachSenseDeviceReq::detachSenseDeviceReq1_posted,
request.get(), request));
}
class DeviceManager::AttachAllSenseDevicesFromSpecsReq
: public PostedAsynchronousContinuation<
attachAllSenseDevicesFromSpecsReqCbFn>
{
public:
AttachAllSenseDevicesFromSpecsReq(
const unsigned int totalNSpecs,
const std::shared_ptr<ComponentThread>& caller,
Callback<attachAllSenseDevicesFromSpecsReqCbFn> cb)
: PostedAsynchronousContinuation<attachAllSenseDevicesFromSpecsReqCbFn>(
caller, cb),
loop(totalNSpecs)
{}
public:
void attachAllSenseDevicesFromSpecsReq1_posted(
[[maybe_unused]] std::shared_ptr<AttachAllSenseDevicesFromSpecsReq>
context
)
{
for (const auto& spec : DeviceManager::deviceAttachmentSpecs)
{
DeviceManager::getInstance().attachSenseDeviceReq(
spec,
{context, std::bind(
&AttachAllSenseDevicesFromSpecsReq::attachAllSenseDevicesFromSpecsReq2,
context.get(), context,
std::placeholders::_1, std::placeholders::_2)});
}
}
// Callback methods for the attachment sequence
void attachAllSenseDevicesFromSpecsReq2(
std::shared_ptr<AttachAllSenseDevicesFromSpecsReq> context,
bool success, std::shared_ptr<DeviceAttachmentSpec> spec
)
{
if (!success)
{
std::cerr << __func__ << ": Failed to attach device: "
<< spec->deviceIdentifier << "\n";
// Fallthrough.
}
if (!context->loop.incrementSuccessOrFailureAndTestForCompletionDueTo(
success))
{
return;
}
if (OptionParser::getOptions().verbose)
{
std::cout << __func__ << ": " << context->loop.nSucceeded.load()
<< " devices attached, "
<< context->loop.nFailed.load() << " devices failed\n";
}
context->callOriginalCb(loop);
}
public:
AsynchronousLoop loop;
};
void DeviceManager::attachAllSenseDevicesFromSpecsReq(
Callback<attachAllSenseDevicesFromSpecsReqCbFn> cb
)
{
if (DeviceManager::getInstance().deviceAttachmentSpecs.size() == 0)
{
AsynchronousLoop tmp(0);
cb.callbackFn(tmp);
return;
}
const auto& caller = ComponentThread::getSelf();
auto request = std::make_shared<AttachAllSenseDevicesFromSpecsReq>(
DeviceManager::getInstance().deviceAttachmentSpecs.size(),
caller, std::move(cb));
mrntt::mrntt.thread->getIoService().post(
std::bind(
&AttachAllSenseDevicesFromSpecsReq::attachAllSenseDevicesFromSpecsReq1_posted,
request.get(), request));
}
class DeviceManager::DetachAllSenseDevicesReq
: public AttachAllSenseDevicesFromSpecsReq
{
public:
using AttachAllSenseDevicesFromSpecsReq::AttachAllSenseDevicesFromSpecsReq;
void detachAllSenseDevicesReq1_posted(
[[maybe_unused]] std::shared_ptr<DetachAllSenseDevicesReq> context
)
{
for (const auto& spec : DeviceManager::deviceAttachmentSpecs)
{
DeviceManager::getInstance().detachSenseDeviceReq(
spec,
{context, std::bind(
&DetachAllSenseDevicesReq::detachAllSenseDevicesReq2,
context.get(), context,
std::placeholders::_1, std::placeholders::_2)});
}
}
void detachAllSenseDevicesReq2(
std::shared_ptr<DetachAllSenseDevicesReq> context,
bool success, std::shared_ptr<DeviceAttachmentSpec> spec
)
{
if (!success)
{
std::cerr << __func__ << ": Failed to detach device: "
<< spec->deviceIdentifier << "\n";
// Fallthrough.
}
if (!context->loop.incrementSuccessOrFailureAndTestForCompletionDueTo(
success))
{
return;
}
if (OptionParser::getOptions().verbose)
{
std::cout << __func__ << ": " << context->loop.nSucceeded.load()
<< " devices detached, "
<< context->loop.nFailed.load() << " devices failed\n";
}
context->callOriginalCb(loop);
}
};
void DeviceManager::detachAllSenseDevicesReq(
Callback<detachAllSenseDevicesReqCbFn> cb
)
{
if (DeviceManager::getInstance().deviceAttachmentSpecs.size() == 0)
{
AsynchronousLoop tmp(0);
cb.callbackFn(tmp);
return;
}
const auto& caller = ComponentThread::getSelf();
auto request = std::make_shared<DetachAllSenseDevicesReq>(
DeviceManager::getInstance().deviceAttachmentSpecs.size(),
caller, std::move(cb));
mrntt::mrntt.thread->getIoService().post(
std::bind(
&DetachAllSenseDevicesReq::detachAllSenseDevicesReq1_posted,
request.get(), request));
}
} // namespace device
} // namespace smo