DevMgr:newDASpecInd: now lockvoked, acquires DevMgr qutex
We now acquire the DevMgr qutex when doing the newDASpecInd async op. The qutex is held across an async sequence with potentially a real hardware blocking bottleneck.
This commit is contained in:
@@ -44,21 +44,22 @@ const std::string DeviceManager::stringifyDeviceSpecs(void)
|
||||
}
|
||||
|
||||
class DeviceManager::NewDeviceAttachmentSpecInd
|
||||
: public PostedAsynchronousContinuation<newDeviceAttachmentSpecIndCbFn>
|
||||
: public SerializedAsynchronousContinuation<newDeviceAttachmentSpecIndCbFn>
|
||||
{
|
||||
public:
|
||||
NewDeviceAttachmentSpecInd(
|
||||
const std::shared_ptr<DeviceAttachmentSpec> &s,
|
||||
const std::shared_ptr<Device> &d,
|
||||
const DeviceAttachmentSpec &spec,
|
||||
const std::shared_ptr<ComponentThread> &caller,
|
||||
Callback<newDeviceAttachmentSpecIndCbFn> cb)
|
||||
: PostedAsynchronousContinuation<newDeviceAttachmentSpecIndCbFn>(
|
||||
caller, cb),
|
||||
spec(s), device(d)
|
||||
Callback<newDeviceAttachmentSpecIndCbFn> cb,
|
||||
std::vector<std::reference_wrapper<Qutex>> requiredLocks)
|
||||
: SerializedAsynchronousContinuation<newDeviceAttachmentSpecIndCbFn>(
|
||||
caller, cb, requiredLocks),
|
||||
spec(spec)
|
||||
{}
|
||||
|
||||
public:
|
||||
std::shared_ptr<DeviceAttachmentSpec> spec;
|
||||
DeviceAttachmentSpec spec;
|
||||
std::shared_ptr<DeviceAttachmentSpec> specPtr;
|
||||
std::shared_ptr<Device> device;
|
||||
|
||||
public:
|
||||
@@ -66,8 +67,73 @@ public:
|
||||
[[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().attachSenseDeviceReq(
|
||||
spec,
|
||||
specPtr,
|
||||
{context, std::bind(
|
||||
&NewDeviceAttachmentSpecInd::newDeviceAttachmentSpecInd2,
|
||||
context.get(), context,
|
||||
@@ -90,15 +156,15 @@ public:
|
||||
|
||||
try {
|
||||
// Create DeviceRole and add it to both DeviceManager's and Device's collections
|
||||
auto deviceRole = std::make_shared<DeviceRole>(*device, spec);
|
||||
auto deviceRole = std::make_shared<DeviceRole>(*device, specPtr);
|
||||
device->deviceRoles.push_back(deviceRole);
|
||||
attachedDeviceRoles.push_back(deviceRole);
|
||||
DeviceManager::attachedDeviceRoles.push_back(deviceRole);
|
||||
|
||||
// Callback with success
|
||||
callOriginalCb(true, deviceRole, spec);
|
||||
callOriginalCb(true, deviceRole, specPtr);
|
||||
} catch (const std::exception& e) {
|
||||
// Attach failed, callback with error
|
||||
callOriginalCb(false, nullptr, spec);
|
||||
callOriginalCb(false, nullptr, specPtr);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -205,82 +271,19 @@ void DeviceManager::newDeviceAttachmentSpecInd(
|
||||
const DeviceAttachmentSpec &spec,
|
||||
Callback<newDeviceAttachmentSpecIndCbFn> callback)
|
||||
{
|
||||
// First, add the spec to deviceAttachmentSpecs if it's not already there
|
||||
bool specExists = false;
|
||||
std::shared_ptr<DeviceAttachmentSpec> specPtr = nullptr;
|
||||
for (const auto& existingSpec : deviceAttachmentSpecs)
|
||||
{
|
||||
if (*existingSpec == spec)
|
||||
{
|
||||
specExists = true;
|
||||
specPtr = existingSpec;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!specExists)
|
||||
{
|
||||
specPtr = std::make_shared<DeviceAttachmentSpec>(spec);
|
||||
deviceAttachmentSpecs.push_back(specPtr);
|
||||
}
|
||||
|
||||
bool deviceExists = false;
|
||||
std::shared_ptr<Device> device = nullptr;
|
||||
for (const auto& existingDevice : 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);
|
||||
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 : 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
|
||||
callback.callbackFn(true, existingDeviceRole, specPtr);
|
||||
return;
|
||||
}
|
||||
|
||||
// Create async continuation
|
||||
const auto& caller = ComponentThread::getSelf();
|
||||
auto continuation = std::make_shared<NewDeviceAttachmentSpecInd>(
|
||||
specPtr, device, caller, callback);
|
||||
|
||||
mrntt::mrntt.thread->getIoService().post(
|
||||
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,
|
||||
continuation.get(), continuation));
|
||||
request.get(), request));
|
||||
}
|
||||
|
||||
void DeviceManager::removeDeviceAttachmentSpecReq(
|
||||
|
||||
Reference in New Issue
Block a user