From 0c78649f7a8327c5c7393038e163ef11db0bb643 Mon Sep 17 00:00:00 2001 From: Adrian Stanea Date: Thu, 21 Sep 2023 17:28:04 +0300 Subject: [PATCH] ContextBuilder: solve context close bug using reference count - added reference count to ContextBuilder to keep track of how many external references to the M2k context are present. When the last reference is removed, the M2k context can be closed. - contexts should be closed in the reverse order they were opened: contextClose() -> iio_context_destroy() to avoid pointer errors. - based on context ownership, the user of the API is responsible of deinitalizing resources. Signed-off-by: Adrian Stanea --- include/libm2k/contextbuilder.hpp | 3 ++ src/context_impl.cpp | 6 ++++ src/context_impl.hpp | 1 + src/contextbuilder.cpp | 57 ++++++++++++++++++++++++------- 4 files changed, 55 insertions(+), 12 deletions(-) diff --git a/include/libm2k/contextbuilder.hpp b/include/libm2k/contextbuilder.hpp index de4633d3..cd5d321b 100644 --- a/include/libm2k/contextbuilder.hpp +++ b/include/libm2k/contextbuilder.hpp @@ -114,6 +114,9 @@ class LIBM2K_API ContextBuilder { bool ownsContext = false); static bool m_disable_logging; + static std::map reference_count; + static void updateReferenceCount(std::string uri); + static Context* sarchInConnectedDevices(std::string uri); }; /** diff --git a/src/context_impl.cpp b/src/context_impl.cpp index 3a6edd7d..6cdb326f 100644 --- a/src/context_impl.cpp +++ b/src/context_impl.cpp @@ -460,3 +460,9 @@ void ContextImpl::setContextOwnership(bool ownsContext) { m_ownsContext = ownsContext; } + +bool ContextImpl::getContextOwnership() +{ + return m_ownsContext; +} + diff --git a/src/context_impl.hpp b/src/context_impl.hpp index 6d046c5a..1cc6b742 100644 --- a/src/context_impl.hpp +++ b/src/context_impl.hpp @@ -91,6 +91,7 @@ class ContextImpl : public virtual Context { struct iio_context *getIioContext() override; void setTimeout(unsigned int timeout) override; void setContextOwnership(bool ownsContext); + bool getContextOwnership(); protected: struct iio_context* m_context; diff --git a/src/contextbuilder.cpp b/src/contextbuilder.cpp index 8b09e59d..2cae944a 100644 --- a/src/contextbuilder.cpp +++ b/src/contextbuilder.cpp @@ -56,6 +56,7 @@ std::map ContextBuilder::m_dev_name_map = { }; bool ContextBuilder::m_disable_logging = true; +std::map ContextBuilder::reference_count = {}; ContextBuilder::ContextBuilder() { @@ -135,6 +136,7 @@ Context* ContextBuilder::buildContext(ContextTypes type, std::string uri, struct iio_context* ctx, bool sync, bool ownsContext) // enum Device Name { std::string name = m_dev_name_map.at(type); + updateReferenceCount(uri); switch (type) { case CtxM2K: { @@ -158,17 +160,38 @@ Context* ContextBuilder::buildContext(ContextTypes type, std::string uri, } } +void ContextBuilder::updateReferenceCount(std::string uri) +{ + if(reference_count.find(uri) == reference_count.end()) { + reference_count[uri] = 1; + } else { + reference_count[uri]++; + } +} + +Context* ContextBuilder::sarchInConnectedDevices(std::string uri) +{ + for (Context* dev : s_connectedDevices) { + if (dev->getUri() == std::string(uri)) { + updateReferenceCount(uri); + return dev; + } + } + return nullptr; +} + + Context* ContextBuilder::contextOpen(const char *uri) { + Context* dev = nullptr; if (m_disable_logging) { enableLogging(false); } LIBM2K_LOG(INFO, "libm2k version: " + getVersion()); - for (Context* dev : s_connectedDevices) { - if (dev->getUri() == std::string(uri)) { - return dev; - } + dev = sarchInConnectedDevices(uri); + if (dev) { + return dev; } struct iio_context* ctx = iio_create_context_from_uri(uri); @@ -192,7 +215,7 @@ Context* ContextBuilder::contextOpen(const char *uri) ContextTypes dev_type = ContextBuilder::identifyContext(ctx); - Context* dev = buildContext(dev_type, std::string(uri), ctx, true, true); + dev = buildContext(dev_type, std::string(uri), ctx, true, true); s_connectedDevices.push_back(dev); return dev; @@ -200,6 +223,7 @@ Context* ContextBuilder::contextOpen(const char *uri) Context* ContextBuilder::contextOpen(struct iio_context* ctx, const char* uri) { + Context* dev = nullptr; if (m_disable_logging) { enableLogging(false); } @@ -221,10 +245,9 @@ Context* ContextBuilder::contextOpen(struct iio_context* ctx, const char* uri) LIBM2K_LOG(INFO, "Firmware version: " + std::string(hw_fw_version)); } - for (Context* dev : s_connectedDevices) { - if (dev->getUri() == std::string(uri)) { - return dev; - } + dev = sarchInConnectedDevices(uri); + if (dev) { + return dev; } if (!ctx) { @@ -233,7 +256,7 @@ Context* ContextBuilder::contextOpen(struct iio_context* ctx, const char* uri) ContextTypes dev_type = ContextBuilder::identifyContext(ctx); - Context* dev = buildContext(dev_type, std::string(uri), ctx, true); + dev = buildContext(dev_type, std::string(uri), ctx, true); s_connectedDevices.push_back(dev); return dev; @@ -298,13 +321,23 @@ M2k *ContextBuilder::m2kOpen() void ContextBuilder::contextClose(Context* device, bool deinit) { + std::string uri = device->getUri(); + bool isDeviceCached = reference_count.find(uri) != reference_count.end(); + if(isDeviceCached) { + reference_count[uri]--; + if(reference_count[uri] != 0) + return; + } + s_connectedDevices.erase(std::remove(s_connectedDevices.begin(), s_connectedDevices.end(), device), s_connectedDevices.end()); try { - if (deinit) { + ContextImpl* ctx_impl = dynamic_cast(device); + if (deinit && !ctx_impl->getContextOwnership()) + device->deinitialize(); + else if (deinit) device->deinitialize(); - } } catch (std::exception &e ){ delete device; THROW_M2K_EXCEPTION("Context deinit: " + std::string(e.what()), libm2k::EXC_RUNTIME_ERROR);