457d0f9345
This class and its macro allow us to trace the invocation of callbacks as they're invoked by Boost.asio.
834 lines
23 KiB
C++
834 lines
23 KiB
C++
#include <iostream>
|
|
#include <fstream>
|
|
#include <stdexcept>
|
|
#include <string>
|
|
#include <vector>
|
|
#include <sstream>
|
|
#include <memory>
|
|
#include <opts.h>
|
|
#include <asynchronousContinuation.h>
|
|
#include <serializedAsynchronousContinuation.h>
|
|
#include <callback.h>
|
|
#include <callableTracer.h>
|
|
#include <componentThread.h>
|
|
#include <deviceManager/deviceManager.h>
|
|
#include <deviceManager/deviceReattacher.h>
|
|
#include <stimBuffApis/stimBuffApiManager.h>
|
|
#include <marionette/marionette.h>
|
|
#include <mind.h>
|
|
|
|
namespace smo {
|
|
namespace device {
|
|
|
|
std::vector<std::shared_ptr<DeviceAttachmentSpec>>
|
|
DeviceManager::deviceAttachmentSpecs;
|
|
std::vector<std::shared_ptr<Device>>
|
|
DeviceManager::devices;
|
|
std::vector<std::shared_ptr<DeviceRole>>
|
|
DeviceManager::attachedDeviceRoles;
|
|
std::vector<DeviceAttachmentSpec>
|
|
DeviceManager::commandLineDASpecs;
|
|
|
|
DeviceManager::~DeviceManager()
|
|
{
|
|
}
|
|
|
|
const std::string DeviceManager::stringifyDeviceSpecs(void)
|
|
{
|
|
std::ostringstream oss;
|
|
|
|
for (const auto& spec : DeviceManager::deviceAttachmentSpecs) {
|
|
oss << "Device Attachment Spec: " << spec->stringify();
|
|
}
|
|
|
|
return oss.str();
|
|
}
|
|
|
|
class DeviceManager::NewDeviceAttachmentSpecInd
|
|
: public SerializedAsynchronousContinuation<newDeviceAttachmentSpecIndCbFn>
|
|
{
|
|
public:
|
|
NewDeviceAttachmentSpecInd(
|
|
const DeviceAttachmentSpec &spec,
|
|
const std::shared_ptr<ComponentThread> &caller,
|
|
Callback<newDeviceAttachmentSpecIndCbFn> cb,
|
|
std::vector<std::reference_wrapper<Qutex>> requiredLocks)
|
|
: SerializedAsynchronousContinuation<newDeviceAttachmentSpecIndCbFn>(
|
|
caller, cb, requiredLocks),
|
|
spec(spec)
|
|
{}
|
|
|
|
public:
|
|
DeviceAttachmentSpec spec;
|
|
std::shared_ptr<DeviceAttachmentSpec> specPtr;
|
|
std::shared_ptr<Device> device;
|
|
|
|
public:
|
|
void newDeviceAttachmentSpecInd1_posted(
|
|
[[maybe_unused]] std::shared_ptr<NewDeviceAttachmentSpecInd> context
|
|
)
|
|
{
|
|
// First, add the spec to deviceAttachmentSpecs if it's not already there
|
|
bool specExists = false;
|
|
for (const auto& existingSpec : DeviceManager::deviceAttachmentSpecs)
|
|
{
|
|
if (*existingSpec == spec)
|
|
{
|
|
specExists = true;
|
|
specPtr = existingSpec;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!specExists)
|
|
{
|
|
specPtr = std::make_shared<DeviceAttachmentSpec>(spec);
|
|
DeviceManager::deviceAttachmentSpecs.push_back(specPtr);
|
|
}
|
|
|
|
bool deviceExists = false;
|
|
for (const auto& existingDevice : DeviceManager::devices)
|
|
{
|
|
if (existingDevice->deviceIdentifier != spec.deviceIdentifier)
|
|
{ continue; }
|
|
|
|
device = existingDevice;
|
|
deviceExists = true;
|
|
break;
|
|
}
|
|
|
|
// If device doesn't exist, create a new one and add it
|
|
if (!device)
|
|
{
|
|
device = std::make_shared<Device>(spec.deviceIdentifier);
|
|
DeviceManager::devices.push_back(device);
|
|
}
|
|
|
|
// Check if a DeviceRole w/ this spec already exists in attachedDeviceRoles
|
|
bool deviceRoleExists = false;
|
|
std::shared_ptr<DeviceRole> existingDeviceRole = nullptr;
|
|
for (const auto& role : DeviceManager::attachedDeviceRoles)
|
|
{
|
|
if (*role->deviceAttachmentSpec == spec)
|
|
{
|
|
deviceRoleExists = true;
|
|
existingDeviceRole = role;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// If DeviceRole exists, both spec and device must also exist
|
|
if (deviceRoleExists)
|
|
{
|
|
if (!specExists || !deviceExists)
|
|
{
|
|
throw std::runtime_error(
|
|
"Program error: DeviceRole exists but spec or device doesn't "
|
|
"pre-exist. specExists=" + std::to_string(specExists) +
|
|
", deviceExists=" + std::to_string(deviceExists));
|
|
}
|
|
|
|
// Already attached, callback with success and return
|
|
callOriginalCb(true, existingDeviceRole, specPtr);
|
|
return;
|
|
}
|
|
|
|
DeviceManager::getInstance().attachStimBuffDeviceReq(
|
|
specPtr,
|
|
{context, std::bind(
|
|
&NewDeviceAttachmentSpecInd::newDeviceAttachmentSpecInd2,
|
|
context.get(), context,
|
|
std::placeholders::_1, std::placeholders::_2)});
|
|
}
|
|
|
|
void newDeviceAttachmentSpecInd2(
|
|
[[maybe_unused]] std::shared_ptr<NewDeviceAttachmentSpecInd> context,
|
|
bool success,
|
|
std::shared_ptr<DeviceAttachmentSpec> deviceSpec
|
|
)
|
|
{
|
|
if (!success)
|
|
{
|
|
std::cerr << __func__ << ": Attach failed for device spec "
|
|
<< deviceSpec->stringify() << std::endl;
|
|
callOriginalCb(false, nullptr, deviceSpec);
|
|
return;
|
|
}
|
|
|
|
try {
|
|
// Create DeviceRole and add it to both DeviceManager's and Device's collections
|
|
auto deviceRole = std::make_shared<DeviceRole>(*device, specPtr);
|
|
device->deviceRoles.push_back(deviceRole);
|
|
DeviceManager::attachedDeviceRoles.push_back(deviceRole);
|
|
|
|
// Callback with success
|
|
callOriginalCb(true, deviceRole, specPtr);
|
|
} catch (const std::exception& e) {
|
|
// Attach failed, callback with error
|
|
callOriginalCb(false, nullptr, specPtr);
|
|
}
|
|
}
|
|
};
|
|
|
|
class DeviceManager::RemoveDeviceAttachmentSpecReq
|
|
: public SerializedAsynchronousContinuation<removeDeviceAttachmentSpecReqCbFn>
|
|
{
|
|
public:
|
|
RemoveDeviceAttachmentSpecReq(
|
|
const DeviceAttachmentSpec &spec,
|
|
const std::shared_ptr<ComponentThread> &caller,
|
|
Callback<removeDeviceAttachmentSpecReqCbFn> cb,
|
|
std::vector<std::reference_wrapper<Qutex>> requiredLocks)
|
|
: SerializedAsynchronousContinuation<removeDeviceAttachmentSpecReqCbFn>(
|
|
caller, cb, requiredLocks),
|
|
spec(spec)
|
|
{}
|
|
|
|
public:
|
|
DeviceAttachmentSpec spec;
|
|
std::shared_ptr<DeviceAttachmentSpec> specPtr;
|
|
|
|
public:
|
|
void removeDeviceAttachmentSpecReq1_posted(
|
|
[[maybe_unused]] std::shared_ptr<RemoveDeviceAttachmentSpecReq> context
|
|
)
|
|
{
|
|
// Find the shared_ptr to the spec in the collection
|
|
for (const auto& existingSpec : DeviceManager::deviceAttachmentSpecs)
|
|
{
|
|
if (*existingSpec == spec)
|
|
{
|
|
specPtr = existingSpec;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!specPtr)
|
|
{
|
|
// Spec not found, callback with failure and return
|
|
callOriginalCb(false, nullptr);
|
|
return;
|
|
}
|
|
|
|
// Call detachStimBuffDeviceReq first - only clean up metadata if this succeeds
|
|
DeviceManager::getInstance().detachStimBuffDeviceReq(
|
|
specPtr,
|
|
{context, std::bind(
|
|
&RemoveDeviceAttachmentSpecReq::removeDeviceAttachmentSpecReq2,
|
|
context.get(), context,
|
|
std::placeholders::_1, std::placeholders::_2)});
|
|
}
|
|
|
|
void removeDeviceAttachmentSpecReq2(
|
|
[[maybe_unused]] std::shared_ptr<RemoveDeviceAttachmentSpecReq> context,
|
|
bool success,
|
|
std::shared_ptr<DeviceAttachmentSpec> deviceSpec
|
|
)
|
|
{
|
|
if (!success)
|
|
{
|
|
// Detach failed, callback with failure (metadata remains intact)
|
|
callOriginalCb(false, deviceSpec);
|
|
return;
|
|
}
|
|
|
|
// Detach succeeded, now find and clean up metadata
|
|
try {
|
|
// Find the DeviceRole in attachedDeviceRoles
|
|
auto deviceRoleIt = std::find_if(
|
|
DeviceManager::attachedDeviceRoles.begin(),
|
|
DeviceManager::attachedDeviceRoles.end(),
|
|
[&specPtr = specPtr](const std::shared_ptr<DeviceRole> &role) {
|
|
return *role->deviceAttachmentSpec == *specPtr;
|
|
}
|
|
);
|
|
|
|
if (deviceRoleIt == DeviceManager::attachedDeviceRoles.end())
|
|
{
|
|
// DeviceRole not found, callback with failure
|
|
callOriginalCb(false, deviceSpec);
|
|
return;
|
|
}
|
|
|
|
auto deviceRole = *deviceRoleIt;
|
|
auto& device = deviceRole->parentDevice;
|
|
|
|
// Remove DeviceRole from DeviceManager's collection
|
|
DeviceManager::attachedDeviceRoles.erase(deviceRoleIt);
|
|
|
|
// Remove DeviceRole from Device's collection
|
|
auto deviceRoleIt2 = std::find(
|
|
device.deviceRoles.begin(),
|
|
device.deviceRoles.end(),
|
|
deviceRole);
|
|
if (deviceRoleIt2 != device.deviceRoles.end())
|
|
{
|
|
device.deviceRoles.erase(deviceRoleIt2);
|
|
}
|
|
|
|
// Remove DeviceAttachmentSpec from deviceAttachmentSpecs collection
|
|
auto specIt = std::find_if(
|
|
DeviceManager::deviceAttachmentSpecs.begin(),
|
|
DeviceManager::deviceAttachmentSpecs.end(),
|
|
[&specPtr = specPtr](
|
|
const std::shared_ptr<DeviceAttachmentSpec> &existingSpec)
|
|
{
|
|
return *existingSpec == *specPtr;
|
|
}
|
|
);
|
|
|
|
if (specIt != DeviceManager::deviceAttachmentSpecs.end())
|
|
{
|
|
DeviceManager::deviceAttachmentSpecs.erase(specIt);
|
|
}
|
|
|
|
// Callback with success
|
|
callOriginalCb(true, deviceSpec);
|
|
} catch (const std::exception& e) {
|
|
// Cleanup failed, callback with error
|
|
callOriginalCb(false, deviceSpec);
|
|
}
|
|
}
|
|
};
|
|
|
|
void DeviceManager::newDeviceAttachmentSpecInd(
|
|
const DeviceAttachmentSpec &spec,
|
|
Callback<newDeviceAttachmentSpecIndCbFn> callback)
|
|
{
|
|
const auto& caller = ComponentThread::getSelf();
|
|
|
|
auto request = std::make_shared<NewDeviceAttachmentSpecInd>(
|
|
spec, caller, callback,
|
|
LockSet<newDeviceAttachmentSpecIndCbFn>::Set{
|
|
std::ref(DeviceManager::getInstance().qutex)
|
|
});
|
|
|
|
NewDeviceAttachmentSpecInd::LockerAndInvoker lockvoker(
|
|
*request, mrntt::mrntt.thread,
|
|
std::bind(
|
|
&NewDeviceAttachmentSpecInd::newDeviceAttachmentSpecInd1_posted,
|
|
request.get(), request));
|
|
}
|
|
|
|
void DeviceManager::removeDeviceAttachmentSpecReq(
|
|
const DeviceAttachmentSpec &spec,
|
|
Callback<removeDeviceAttachmentSpecReqCbFn> callback)
|
|
{
|
|
const auto& caller = ComponentThread::getSelf();
|
|
|
|
auto request = std::make_shared<RemoveDeviceAttachmentSpecReq>(
|
|
spec, caller, callback,
|
|
LockSet<removeDeviceAttachmentSpecReqCbFn>::Set{
|
|
std::ref(DeviceManager::getInstance().qutex)
|
|
});
|
|
|
|
RemoveDeviceAttachmentSpecReq::LockerAndInvoker lockvoker(
|
|
*request, mrntt::mrntt.thread,
|
|
std::bind(
|
|
&RemoveDeviceAttachmentSpecReq
|
|
::removeDeviceAttachmentSpecReq1_posted,
|
|
request.get(), request));
|
|
}
|
|
|
|
class DeviceManager::AttachStimBuffDeviceReq
|
|
: public SerializedAsynchronousContinuation<
|
|
DeviceManager::attachStimBuffDeviceReqCbFn>
|
|
{
|
|
public:
|
|
AttachStimBuffDeviceReq(
|
|
const std::shared_ptr<DeviceAttachmentSpec>& spec,
|
|
const std::shared_ptr<ComponentThread> &caller,
|
|
Callback<DeviceManager::attachStimBuffDeviceReqCbFn> cb,
|
|
std::shared_ptr<stim_buff::StimBuffApiLib> &stimBuffApiLib,
|
|
std::vector<std::reference_wrapper<Qutex>> requiredLocks)
|
|
: SerializedAsynchronousContinuation<attachStimBuffDeviceReqCbFn>(
|
|
caller, cb, requiredLocks),
|
|
spec(spec), stimBuffApiLib(stimBuffApiLib)
|
|
{}
|
|
|
|
public:
|
|
void attachStimBuffDeviceReq1_posted(
|
|
[[maybe_unused]] std::shared_ptr<AttachStimBuffDeviceReq> context
|
|
)
|
|
{
|
|
if (caller->id != ComponentThread::MRNTT)
|
|
{
|
|
std::cerr << std::string(__func__)
|
|
<< ": executed on non-mrntt thread: "
|
|
<< caller->name << std::endl;
|
|
callOriginalCb(false, spec);
|
|
return;
|
|
}
|
|
|
|
if (stimBuffApiLib->isBeingDestroyed.load())
|
|
{
|
|
std::cerr << std::string(__func__) + ": Library is being destroyed"
|
|
<< " for API '" << spec->stimBuffApi << "'. Bailing out.\n";
|
|
callOriginalCb(false, spec);
|
|
return;
|
|
}
|
|
|
|
if (!stimBuffApiLib->stimBuffApiDesc.sal_mgmt_libOps.attachDeviceReq)
|
|
{
|
|
std::cerr << std::string(__func__) + ": attachDeviceReq() is NULL "
|
|
"for library '" << stimBuffApiLib->libraryPath << "'"
|
|
<< std::endl;
|
|
callOriginalCb(false, spec);
|
|
return;
|
|
}
|
|
|
|
releaseQutexEarly(stim_buff::StimBuffApiManager::getInstance().qutex);
|
|
|
|
/** 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";
|
|
}
|
|
|
|
stimBuffApiLib->stimBuffApiDesc.sal_mgmt_libOps.attachDeviceReq(
|
|
spec, threadForAttachment,
|
|
{context, std::bind(
|
|
&AttachStimBuffDeviceReq::attachStimBuffDeviceReq2,
|
|
context.get(), context,
|
|
std::placeholders::_1, std::placeholders::_2)});
|
|
}
|
|
|
|
void attachStimBuffDeviceReq2(
|
|
[[maybe_unused]] std::shared_ptr<AttachStimBuffDeviceReq> context,
|
|
bool success,
|
|
std::shared_ptr<DeviceAttachmentSpec> deviceSpec
|
|
)
|
|
{
|
|
callOriginalCb(success, deviceSpec);
|
|
}
|
|
|
|
void detachStimBuffDeviceReq1_posted(
|
|
[[maybe_unused]] std::shared_ptr<AttachStimBuffDeviceReq> context
|
|
)
|
|
{
|
|
if (caller->id != ComponentThread::MRNTT)
|
|
{
|
|
std::cerr << std::string(__func__)
|
|
<< ": executed on non-mrntt thread: "
|
|
<< caller->name << std::endl;
|
|
callOriginalCb(false, spec);
|
|
return;
|
|
}
|
|
|
|
if (stimBuffApiLib->isBeingDestroyed.load())
|
|
{
|
|
std::cerr << std::string(__func__) + ": Library is being destroyed"
|
|
<< " for API '" << spec->stimBuffApi << "'. Bailing out.\n";
|
|
callOriginalCb(false, spec);
|
|
return;
|
|
}
|
|
|
|
if (!stimBuffApiLib->stimBuffApiDesc.sal_mgmt_libOps.detachDeviceReq)
|
|
{
|
|
std::cerr << std::string(__func__) + ": detachDeviceReq() is NULL "
|
|
"for library '" << stimBuffApiLib->libraryPath << "'"
|
|
<< std::endl;
|
|
callOriginalCb(false, spec);
|
|
return;
|
|
}
|
|
|
|
releaseQutexEarly(stim_buff::StimBuffApiManager::getInstance().qutex);
|
|
|
|
stimBuffApiLib->stimBuffApiDesc.sal_mgmt_libOps.detachDeviceReq(
|
|
spec,
|
|
{context, std::bind(
|
|
&AttachStimBuffDeviceReq::detachStimBuffDeviceReq2,
|
|
context.get(), context,
|
|
std::placeholders::_1, std::placeholders::_2)});
|
|
}
|
|
|
|
void detachStimBuffDeviceReq2(
|
|
[[maybe_unused]] std::shared_ptr<AttachStimBuffDeviceReq> context,
|
|
bool success,
|
|
std::shared_ptr<DeviceAttachmentSpec> deviceSpec
|
|
)
|
|
{
|
|
callOriginalCb(success, deviceSpec);
|
|
}
|
|
|
|
public:
|
|
std::shared_ptr<DeviceAttachmentSpec> spec;
|
|
std::shared_ptr<stim_buff::StimBuffApiLib> stimBuffApiLib;
|
|
};
|
|
|
|
void DeviceManager::attachStimBuffDeviceReq(
|
|
const std::shared_ptr<DeviceAttachmentSpec>& spec,
|
|
Callback<attachStimBuffDeviceReqCbFn> cb
|
|
)
|
|
{
|
|
const auto& caller = ComponentThread::getSelf();
|
|
|
|
// Get the stim buff API lib's qutex
|
|
auto libOpt = stim_buff::StimBuffApiManager::getInstance()
|
|
.getStimBuffApiLibByApiName(spec->stimBuffApi);
|
|
|
|
if (!libOpt)
|
|
{
|
|
std::cerr << "attachStimBuffDeviceReq: No library found for API '"
|
|
<< spec->stimBuffApi << "'" << std::endl;
|
|
cb.callbackFn(false, spec);
|
|
return;
|
|
}
|
|
|
|
auto& lib = *libOpt.value();
|
|
|
|
auto request = std::make_shared<AttachStimBuffDeviceReq>(
|
|
spec, caller, cb, libOpt.value(),
|
|
LockSet<attachStimBuffDeviceReqCbFn>::Set{
|
|
std::ref(stim_buff::StimBuffApiManager::getInstance().qutex),
|
|
std::ref(lib.qutex)
|
|
});
|
|
|
|
AttachStimBuffDeviceReq::LockerAndInvoker lockvoker(
|
|
*request, mrntt::mrntt.thread,
|
|
std::bind(
|
|
&AttachStimBuffDeviceReq::attachStimBuffDeviceReq1_posted,
|
|
request.get(), request));
|
|
}
|
|
|
|
void DeviceManager::detachStimBuffDeviceReq(
|
|
const std::shared_ptr<DeviceAttachmentSpec>& spec,
|
|
Callback<detachStimBuffDeviceReqCbFn> cb
|
|
)
|
|
{
|
|
const auto& caller = ComponentThread::getSelf();
|
|
|
|
// Get the stim buff API lib's qutex
|
|
auto libOpt = stim_buff::StimBuffApiManager::getInstance()
|
|
.getStimBuffApiLibByApiName(spec->stimBuffApi);
|
|
|
|
if (!libOpt)
|
|
{
|
|
std::cerr << "detachStimBuffDeviceReq: No library found for API '"
|
|
<< spec->stimBuffApi << "'" << std::endl;
|
|
cb.callbackFn(false, spec);
|
|
return;
|
|
}
|
|
|
|
auto& lib = *libOpt.value();
|
|
|
|
auto request = std::make_shared<DetachStimBuffDeviceReq>(
|
|
spec, caller, cb, libOpt.value(),
|
|
LockSet<detachStimBuffDeviceReqCbFn>::Set{
|
|
std::ref(stim_buff::StimBuffApiManager::getInstance().qutex),
|
|
std::ref(lib.qutex)
|
|
});
|
|
|
|
DetachStimBuffDeviceReq::LockerAndInvoker lockvoker(
|
|
*request, mrntt::mrntt.thread,
|
|
std::bind(
|
|
&DetachStimBuffDeviceReq::detachStimBuffDeviceReq1_posted,
|
|
request.get(), request));
|
|
}
|
|
|
|
class DeviceManager::AttachAllUnattachedDevicesFromReq
|
|
: public PostedAsynchronousContinuation<
|
|
attachAllUnattachedDevicesFromReqCbFn>
|
|
{
|
|
public:
|
|
AttachAllUnattachedDevicesFromReq(
|
|
const unsigned int totalNSpecs,
|
|
const std::shared_ptr<std::vector<DeviceAttachmentSpec>>& specs,
|
|
const std::shared_ptr<ComponentThread>& caller,
|
|
Callback<attachAllUnattachedDevicesFromReqCbFn> cb)
|
|
: PostedAsynchronousContinuation<attachAllUnattachedDevicesFromReqCbFn>(
|
|
caller, cb),
|
|
loop(totalNSpecs), specs(specs)
|
|
{}
|
|
|
|
public:
|
|
void attachAllUnattachedDevicesFromReq1_posted(
|
|
[[maybe_unused]] std::shared_ptr<AttachAllUnattachedDevicesFromReq>
|
|
context
|
|
)
|
|
{
|
|
for (const auto& spec : *specs)
|
|
{
|
|
DeviceManager::getInstance().newDeviceAttachmentSpecInd(
|
|
spec,
|
|
{context, std::bind(
|
|
&AttachAllUnattachedDevicesFromReq
|
|
::attachAllUnattachedDevicesFromReq2,
|
|
context.get(), context,
|
|
std::placeholders::_1, std::placeholders::_2,
|
|
std::placeholders::_3)});
|
|
}
|
|
}
|
|
|
|
// Callback methods for the attachment sequence
|
|
void attachAllUnattachedDevicesFromReq2(
|
|
std::shared_ptr<AttachAllUnattachedDevicesFromReq> context,
|
|
bool success, [[maybe_unused]] std::shared_ptr<DeviceRole> deviceRole,
|
|
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;
|
|
std::shared_ptr<std::vector<DeviceAttachmentSpec>> specs;
|
|
};
|
|
|
|
void DeviceManager::attachAllUnattachedDevicesFromReq(
|
|
const std::shared_ptr<std::vector<DeviceAttachmentSpec>> &specs,
|
|
Callback<attachAllUnattachedDevicesFromReqCbFn> cb
|
|
)
|
|
{
|
|
if (specs->size() == 0)
|
|
{
|
|
AsynchronousLoop tmp(0);
|
|
cb.callbackFn(tmp);
|
|
return;
|
|
}
|
|
|
|
const auto& caller = ComponentThread::getSelf();
|
|
auto request = std::make_shared<AttachAllUnattachedDevicesFromReq>(
|
|
specs->size(), specs, caller, std::move(cb));
|
|
|
|
mrntt::mrntt.thread->getIoService().post(
|
|
STC(std::bind(
|
|
&AttachAllUnattachedDevicesFromReq
|
|
::attachAllUnattachedDevicesFromReq1_posted,
|
|
request.get(), request)));
|
|
}
|
|
|
|
void DeviceManager::attachAllUnattachedDevicesFromCmdlineReq(
|
|
Callback<attachAllUnattachedDevicesFromReqCbFn> cb
|
|
)
|
|
{
|
|
auto specs = std::make_shared<std::vector<DeviceAttachmentSpec>>(
|
|
commandLineDASpecs);
|
|
attachAllUnattachedDevicesFromReq(specs, std::move(cb));
|
|
}
|
|
|
|
class DeviceManager::AttachAllUnattachedDevicesFromKnownListReq
|
|
: public SerializedAsynchronousContinuation<
|
|
attachAllUnattachedDevicesFromReqCbFn>
|
|
{
|
|
public:
|
|
AttachAllUnattachedDevicesFromKnownListReq(
|
|
const std::shared_ptr<ComponentThread> &caller,
|
|
Callback<attachAllUnattachedDevicesFromReqCbFn> cb,
|
|
std::vector<std::reference_wrapper<Qutex>> requiredLocks)
|
|
: SerializedAsynchronousContinuation<
|
|
attachAllUnattachedDevicesFromReqCbFn>(
|
|
caller, cb, requiredLocks)
|
|
{}
|
|
|
|
public:
|
|
void attachAllUnattachedDevicesFromKnownListReq1_posted(
|
|
[[maybe_unused]]
|
|
std::shared_ptr<AttachAllUnattachedDevicesFromKnownListReq> context
|
|
)
|
|
{
|
|
// Create a vector to hold unattached device specs
|
|
auto unattachedSpecs = std::make_shared<
|
|
std::vector<DeviceAttachmentSpec>>();
|
|
|
|
// Cycle through all DA specs in deviceAttachmentSpecs
|
|
for (const auto& spec : DeviceManager::deviceAttachmentSpecs)
|
|
{
|
|
bool isAttached = false;
|
|
|
|
// Cross reference with attachedDeviceRoles
|
|
for (const auto& role : DeviceManager::attachedDeviceRoles)
|
|
{
|
|
if (*role->deviceAttachmentSpec == *spec)
|
|
{
|
|
isAttached = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// If spec doesn't appear in attachedDeviceRoles, add it to vector
|
|
if (!isAttached) {
|
|
unattachedSpecs->push_back(*spec);
|
|
}
|
|
}
|
|
|
|
// Release the DeviceManager qutex early before calling the inner method
|
|
releaseQutexEarly(DeviceManager::getInstance().qutex);
|
|
|
|
// Pass the vector to the existing function
|
|
DeviceManager::getInstance().attachAllUnattachedDevicesFromReq(
|
|
unattachedSpecs,
|
|
{context, std::bind(
|
|
&AttachAllUnattachedDevicesFromKnownListReq
|
|
::attachAllUnattachedDevicesFromKnownListReq2,
|
|
context.get(), context,
|
|
std::placeholders::_1)});
|
|
}
|
|
|
|
void attachAllUnattachedDevicesFromKnownListReq2(
|
|
[[maybe_unused]]
|
|
std::shared_ptr<AttachAllUnattachedDevicesFromKnownListReq> context,
|
|
AsynchronousLoop loop
|
|
)
|
|
{
|
|
callOriginalCb(loop);
|
|
}
|
|
};
|
|
|
|
void DeviceManager::attachAllUnattachedDevicesFromKnownListReq(
|
|
Callback<attachAllUnattachedDevicesFromReqCbFn> cb
|
|
)
|
|
{
|
|
const auto& caller = ComponentThread::getSelf();
|
|
|
|
auto request = std::make_shared<AttachAllUnattachedDevicesFromKnownListReq>(
|
|
caller, cb,
|
|
LockSet<attachAllUnattachedDevicesFromReqCbFn>::Set{
|
|
std::ref(DeviceManager::getInstance().qutex)
|
|
});
|
|
|
|
AttachAllUnattachedDevicesFromKnownListReq::LockerAndInvoker lockvoker(
|
|
*request, mrntt::mrntt.thread,
|
|
std::bind(
|
|
&AttachAllUnattachedDevicesFromKnownListReq
|
|
::attachAllUnattachedDevicesFromKnownListReq1_posted,
|
|
request.get(), request));
|
|
}
|
|
|
|
class DeviceManager::DetachAllAttachedDeviceRoles
|
|
: public PostedAsynchronousContinuation<
|
|
detachAllAttachedDeviceRolesCbFn>
|
|
{
|
|
public:
|
|
DetachAllAttachedDeviceRoles(
|
|
const unsigned int totalNSpecs,
|
|
const std::shared_ptr<ComponentThread>& caller,
|
|
Callback<detachAllAttachedDeviceRolesCbFn> cb)
|
|
: PostedAsynchronousContinuation<detachAllAttachedDeviceRolesCbFn>(
|
|
caller, cb),
|
|
loop(totalNSpecs)
|
|
{}
|
|
|
|
void detachAllAttachedDeviceRoles1_posted(
|
|
[[maybe_unused]] std::shared_ptr<DetachAllAttachedDeviceRoles> context
|
|
)
|
|
{
|
|
for (const auto& deviceRole : DeviceManager::attachedDeviceRoles)
|
|
{
|
|
DeviceManager::getInstance().detachStimBuffDeviceReq(
|
|
deviceRole->deviceAttachmentSpec,
|
|
{context, std::bind(
|
|
&DetachAllAttachedDeviceRoles::detachAllAttachedDeviceRoles2,
|
|
context.get(), context,
|
|
std::placeholders::_1, std::placeholders::_2)});
|
|
}
|
|
}
|
|
|
|
void detachAllAttachedDeviceRoles2(
|
|
std::shared_ptr<DetachAllAttachedDeviceRoles> 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);
|
|
}
|
|
|
|
public:
|
|
AsynchronousLoop loop;
|
|
};
|
|
|
|
void DeviceManager::detachAllAttachedDeviceRoles(
|
|
Callback<detachAllAttachedDeviceRolesCbFn> cb
|
|
)
|
|
{
|
|
if (DeviceManager::getInstance().attachedDeviceRoles.size() == 0)
|
|
{
|
|
AsynchronousLoop tmp(0);
|
|
cb.callbackFn(tmp);
|
|
return;
|
|
}
|
|
|
|
const auto& caller = ComponentThread::getSelf();
|
|
auto request = std::make_shared<DetachAllAttachedDeviceRoles>(
|
|
DeviceManager::getInstance().attachedDeviceRoles.size(),
|
|
caller, std::move(cb));
|
|
|
|
mrntt::mrntt.thread->getIoService().post(
|
|
STC(std::bind(
|
|
&DetachAllAttachedDeviceRoles::detachAllAttachedDeviceRoles1_posted,
|
|
request.get(), request)));
|
|
}
|
|
|
|
void DeviceManager::initializeDeviceReattacher()
|
|
{
|
|
deviceReattacher = std::make_unique<DeviceReattacher>(
|
|
*this, mrntt::mrntt.thread);
|
|
|
|
deviceReattacher->start();
|
|
}
|
|
|
|
void DeviceManager::finalizeDeviceReattacher()
|
|
{
|
|
if (!deviceReattacher) { return; }
|
|
|
|
deviceReattacher->stop();
|
|
deviceReattacher.reset();
|
|
}
|
|
|
|
} // namespace device
|
|
} // namespace smo
|