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:
2025-09-30 22:01:34 -04:00
parent 274143e41d
commit ac3d97b3ec
+88 -85
View File
@@ -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(