|
16 | 16 | #include <qdmi/device.h> |
17 | 17 | #include <spdlog/spdlog.h> |
18 | 18 |
|
| 19 | +#include <algorithm> |
19 | 20 | #include <array> |
20 | 21 | #include <cassert> |
21 | 22 | #include <cstddef> |
@@ -169,8 +170,9 @@ DynamicDeviceLibrary::~DynamicDeviceLibrary() { |
169 | 170 | } // namespace qdmi |
170 | 171 |
|
171 | 172 | QDMI_Device_impl_d::QDMI_Device_impl_d( |
172 | | - std::unique_ptr<qdmi::DeviceLibrary>&& lib, |
173 | | - const qdmi::DeviceSessionConfig& config) |
| 173 | + std::shared_ptr<qdmi::DeviceLibrary> lib, |
| 174 | + const qdmi::DeviceSessionConfig& config, |
| 175 | + QDMI_Child_Device_impl_d* const childDevice) |
174 | 176 | : library_(std::move(lib)) { |
175 | 177 | if (library_->device_session_alloc(&deviceSession_) != QDMI_SUCCESS) { |
176 | 178 | throw std::runtime_error("Failed to allocate device session"); |
@@ -213,10 +215,77 @@ QDMI_Device_impl_d::QDMI_Device_impl_d( |
213 | 215 | setParameter(config.custom4, QDMI_DEVICE_SESSION_PARAMETER_CUSTOM4); |
214 | 216 | setParameter(config.custom5, QDMI_DEVICE_SESSION_PARAMETER_CUSTOM5); |
215 | 217 |
|
| 218 | + if (childDevice != nullptr) { |
| 219 | + const auto status = |
| 220 | + static_cast<QDMI_STATUS>(library_->device_session_set_parameter( |
| 221 | + deviceSession_, QDMI_DEVICE_SESSION_PARAMETER_CHILDDEVICE, |
| 222 | + sizeof(QDMI_Child_Device), static_cast<const void*>(&childDevice))); |
| 223 | + if (status != QDMI_SUCCESS) { |
| 224 | + library_->device_session_free(deviceSession_); |
| 225 | + deviceSession_ = nullptr; |
| 226 | + std::ostringstream ss; |
| 227 | + ss << "Failed to select child device: " << qdmi::toString(status); |
| 228 | + throw std::runtime_error(ss.str()); |
| 229 | + } |
| 230 | + } |
| 231 | + |
216 | 232 | if (library_->device_session_init(deviceSession_) != QDMI_SUCCESS) { |
217 | 233 | library_->device_session_free(deviceSession_); |
| 234 | + deviceSession_ = nullptr; |
218 | 235 | throw std::runtime_error("Failed to initialize device session"); |
219 | 236 | } |
| 237 | + |
| 238 | + // Child sessions represent leaf devices in the QDMI multicore |
| 239 | + // workflow. Only top-level sessions discover and wrap child handles. |
| 240 | + if (childDevice != nullptr) { |
| 241 | + return; |
| 242 | + } |
| 243 | + |
| 244 | + size_t childrenSize = 0; |
| 245 | + auto status = |
| 246 | + static_cast<QDMI_STATUS>(library_->device_session_query_device_property( |
| 247 | + deviceSession_, QDMI_DEVICE_PROPERTY_CHILDDEVICES, 0, nullptr, |
| 248 | + &childrenSize)); |
| 249 | + if (status == QDMI_ERROR_NOTSUPPORTED) { |
| 250 | + return; |
| 251 | + } |
| 252 | + if (status != QDMI_SUCCESS || childrenSize % sizeof(QDMI_Child_Device) != 0) { |
| 253 | + library_->device_session_free(deviceSession_); |
| 254 | + deviceSession_ = nullptr; |
| 255 | + if (status != QDMI_SUCCESS) { |
| 256 | + throw std::runtime_error("Failed to query child devices: " + |
| 257 | + std::string(qdmi::toString(status))); |
| 258 | + } |
| 259 | + throw std::runtime_error("Device returned an invalid child device list"); |
| 260 | + } |
| 261 | + |
| 262 | + std::vector<QDMI_Child_Device> children(childrenSize / |
| 263 | + sizeof(QDMI_Child_Device)); |
| 264 | + if (childrenSize != 0) { |
| 265 | + status = |
| 266 | + static_cast<QDMI_STATUS>(library_->device_session_query_device_property( |
| 267 | + deviceSession_, QDMI_DEVICE_PROPERTY_CHILDDEVICES, childrenSize, |
| 268 | + static_cast<void*>(children.data()), nullptr)); |
| 269 | + if (status != QDMI_SUCCESS) { |
| 270 | + library_->device_session_free(deviceSession_); |
| 271 | + deviceSession_ = nullptr; |
| 272 | + throw std::runtime_error("Failed to query child devices: " + |
| 273 | + std::string(qdmi::toString(status))); |
| 274 | + } |
| 275 | + } |
| 276 | + |
| 277 | + try { |
| 278 | + childDevices_.reserve(children.size()); |
| 279 | + for (auto* const child : children) { |
| 280 | + childDevices_.emplace_back( |
| 281 | + std::make_unique<QDMI_Device_impl_d>(library_, config, child)); |
| 282 | + } |
| 283 | + } catch (...) { |
| 284 | + childDevices_.clear(); |
| 285 | + library_->device_session_free(deviceSession_); |
| 286 | + deviceSession_ = nullptr; |
| 287 | + throw; |
| 288 | + } |
220 | 289 | } |
221 | 290 |
|
222 | 291 | auto QDMI_Device_impl_d::createJob(QDMI_Job* job) -> int { |
@@ -244,6 +313,25 @@ auto QDMI_Device_impl_d::freeJob(QDMI_Job job) -> void { |
244 | 313 | auto QDMI_Device_impl_d::queryDeviceProperty(QDMI_Device_Property prop, |
245 | 314 | const size_t size, void* value, |
246 | 315 | size_t* sizeRet) const -> int { |
| 316 | + if (prop == QDMI_DEVICE_PROPERTY_CHILDDEVICES) { |
| 317 | + if (childDevices_.empty()) { |
| 318 | + return QDMI_ERROR_NOTSUPPORTED; |
| 319 | + } |
| 320 | + const auto requiredSize = childDevices_.size() * sizeof(QDMI_Device); |
| 321 | + if (value != nullptr) { |
| 322 | + if (size < requiredSize) { |
| 323 | + return QDMI_ERROR_INVALIDARGUMENT; |
| 324 | + } |
| 325 | + auto* devices = static_cast<QDMI_Device*>(value); |
| 326 | + std::ranges::transform( |
| 327 | + childDevices_, devices, |
| 328 | + [](const auto& child) -> QDMI_Device { return child.get(); }); |
| 329 | + } |
| 330 | + if (sizeRet != nullptr) { |
| 331 | + *sizeRet = requiredSize; |
| 332 | + } |
| 333 | + return QDMI_SUCCESS; |
| 334 | + } |
247 | 335 | return library_->device_session_query_device_property(deviceSession_, prop, |
248 | 336 | size, value, sizeRet); |
249 | 337 | } |
@@ -424,7 +512,7 @@ auto Driver::addDynamicDeviceLibrary(const std::string& libName, |
424 | 512 | const DeviceSessionConfig& config) |
425 | 513 | -> QDMI_Device { |
426 | 514 | devices_.emplace_back(std::make_unique<QDMI_Device_impl_d>( |
427 | | - std::make_unique<DynamicDeviceLibrary>(libName, prefix), config)); |
| 515 | + std::make_shared<DynamicDeviceLibrary>(libName, prefix), config)); |
428 | 516 | return devices_.back().get(); |
429 | 517 | } |
430 | 518 |
|
|
0 commit comments