Skip to content

Commit

Permalink
ContextBuilder: solve context close bug using reference count
Browse files Browse the repository at this point in the history
- 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 <[email protected]>
  • Loading branch information
Adrian-Stanea committed Sep 27, 2023
1 parent 7b31a3d commit 0c78649
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 12 deletions.
3 changes: 3 additions & 0 deletions include/libm2k/contextbuilder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,9 @@ class LIBM2K_API ContextBuilder {
bool ownsContext = false);
static bool m_disable_logging;

static std::map<std::string, int> reference_count;
static void updateReferenceCount(std::string uri);
static Context* sarchInConnectedDevices(std::string uri);
};

/**
Expand Down
6 changes: 6 additions & 0 deletions src/context_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -460,3 +460,9 @@ void ContextImpl::setContextOwnership(bool ownsContext)
{
m_ownsContext = ownsContext;
}

bool ContextImpl::getContextOwnership()
{
return m_ownsContext;
}

1 change: 1 addition & 0 deletions src/context_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
57 changes: 45 additions & 12 deletions src/contextbuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ std::map<ContextTypes, std::string> ContextBuilder::m_dev_name_map = {
};

bool ContextBuilder::m_disable_logging = true;
std::map<std::string, int> ContextBuilder::reference_count = {};

ContextBuilder::ContextBuilder()
{
Expand Down Expand Up @@ -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:
{
Expand All @@ -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);
Expand All @@ -192,14 +215,15 @@ 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;
}

Context* ContextBuilder::contextOpen(struct iio_context* ctx, const char* uri)
{
Context* dev = nullptr;
if (m_disable_logging) {
enableLogging(false);
}
Expand All @@ -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) {
Expand All @@ -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;
Expand Down Expand Up @@ -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<ContextImpl*>(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);
Expand Down

0 comments on commit 0c78649

Please sign in to comment.