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
|
class DeviceManager::NewDeviceAttachmentSpecInd
|
||||||
: public PostedAsynchronousContinuation<newDeviceAttachmentSpecIndCbFn>
|
: public SerializedAsynchronousContinuation<newDeviceAttachmentSpecIndCbFn>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NewDeviceAttachmentSpecInd(
|
NewDeviceAttachmentSpecInd(
|
||||||
const std::shared_ptr<DeviceAttachmentSpec> &s,
|
const DeviceAttachmentSpec &spec,
|
||||||
const std::shared_ptr<Device> &d,
|
|
||||||
const std::shared_ptr<ComponentThread> &caller,
|
const std::shared_ptr<ComponentThread> &caller,
|
||||||
Callback<newDeviceAttachmentSpecIndCbFn> cb)
|
Callback<newDeviceAttachmentSpecIndCbFn> cb,
|
||||||
: PostedAsynchronousContinuation<newDeviceAttachmentSpecIndCbFn>(
|
std::vector<std::reference_wrapper<Qutex>> requiredLocks)
|
||||||
caller, cb),
|
: SerializedAsynchronousContinuation<newDeviceAttachmentSpecIndCbFn>(
|
||||||
spec(s), device(d)
|
caller, cb, requiredLocks),
|
||||||
|
spec(spec)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
std::shared_ptr<DeviceAttachmentSpec> spec;
|
DeviceAttachmentSpec spec;
|
||||||
|
std::shared_ptr<DeviceAttachmentSpec> specPtr;
|
||||||
std::shared_ptr<Device> device;
|
std::shared_ptr<Device> device;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -66,8 +67,73 @@ public:
|
|||||||
[[maybe_unused]] std::shared_ptr<NewDeviceAttachmentSpecInd> context
|
[[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(
|
DeviceManager::getInstance().attachSenseDeviceReq(
|
||||||
spec,
|
specPtr,
|
||||||
{context, std::bind(
|
{context, std::bind(
|
||||||
&NewDeviceAttachmentSpecInd::newDeviceAttachmentSpecInd2,
|
&NewDeviceAttachmentSpecInd::newDeviceAttachmentSpecInd2,
|
||||||
context.get(), context,
|
context.get(), context,
|
||||||
@@ -90,15 +156,15 @@ public:
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// Create DeviceRole and add it to both DeviceManager's and Device's collections
|
// 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);
|
device->deviceRoles.push_back(deviceRole);
|
||||||
attachedDeviceRoles.push_back(deviceRole);
|
DeviceManager::attachedDeviceRoles.push_back(deviceRole);
|
||||||
|
|
||||||
// Callback with success
|
// Callback with success
|
||||||
callOriginalCb(true, deviceRole, spec);
|
callOriginalCb(true, deviceRole, specPtr);
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
// Attach failed, callback with error
|
// Attach failed, callback with error
|
||||||
callOriginalCb(false, nullptr, spec);
|
callOriginalCb(false, nullptr, specPtr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -205,82 +271,19 @@ void DeviceManager::newDeviceAttachmentSpecInd(
|
|||||||
const DeviceAttachmentSpec &spec,
|
const DeviceAttachmentSpec &spec,
|
||||||
Callback<newDeviceAttachmentSpecIndCbFn> callback)
|
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();
|
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(
|
std::bind(
|
||||||
&NewDeviceAttachmentSpecInd::newDeviceAttachmentSpecInd1_posted,
|
&NewDeviceAttachmentSpecInd::newDeviceAttachmentSpecInd1_posted,
|
||||||
continuation.get(), continuation));
|
request.get(), request));
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeviceManager::removeDeviceAttachmentSpecReq(
|
void DeviceManager::removeDeviceAttachmentSpecReq(
|
||||||
|
|||||||
Reference in New Issue
Block a user