mirror of
https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git
synced 2026-10-24 00:48:53 +03:00
core: keep memory usage of struct line_config in check
We keep a single instance of a struct gpiod_line_settings object shared
by all offsets using it. Everytime gpiod_line_config_add_line_settings()
is called, we append it to the per-line-config linked list and reference
it from every per-offset structure.
However we don't keep track of the offsets referencing a settings object
and don't remove it when there are no more offsets associated with it -
we only do it when the user frees or resets the line-config object.
Extend the settings_node structure: make it a doubly-linked list -
allowing to easily remove individual nodes - and add a reference count.
Keep track of how many offsets reference a line-settings object and when
that reference count drops to 0, remove it.
Fixes: b7ba732e6a ("treewide: libgpiod v2 implementation")
Closes: https://github.com/brgl/libgpiod/issues/130
Link: https://lore.kernel.org/r/20250424-line_config_mem_use-v1-1-fa0abdcf0cdf@linaro.org
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
This commit is contained in:
@@ -13,8 +13,10 @@
|
||||
#define LINES_MAX (GPIO_V2_LINES_MAX)
|
||||
|
||||
struct settings_node {
|
||||
struct settings_node *prev;
|
||||
struct settings_node *next;
|
||||
struct gpiod_line_settings *settings;
|
||||
unsigned int refcnt;
|
||||
};
|
||||
|
||||
struct per_line_config {
|
||||
@@ -93,7 +95,7 @@ GPIOD_API int gpiod_line_config_add_line_settings(
|
||||
size_t num_offsets, struct gpiod_line_settings *settings)
|
||||
{
|
||||
struct per_line_config *per_line;
|
||||
struct settings_node *node;
|
||||
struct settings_node *node, *old;
|
||||
size_t i;
|
||||
|
||||
assert(config);
|
||||
@@ -121,14 +123,29 @@ GPIOD_API int gpiod_line_config_add_line_settings(
|
||||
return -1;
|
||||
}
|
||||
|
||||
node->refcnt = 0;
|
||||
node->next = config->sref_list;
|
||||
if (config->sref_list)
|
||||
config->sref_list->prev = node;
|
||||
node->prev = NULL;
|
||||
config->sref_list = node;
|
||||
|
||||
for (i = 0; i < num_offsets; i++) {
|
||||
per_line = find_config(config, offsets[i]);
|
||||
|
||||
node->refcnt++;
|
||||
per_line->offset = offsets[i];
|
||||
old = per_line->node;
|
||||
per_line->node = node;
|
||||
|
||||
if (old && !(--old->refcnt)) {
|
||||
if (old->prev)
|
||||
old->prev->next = old->next;
|
||||
if (old->next)
|
||||
old->next->prev = old->prev;
|
||||
free(old->settings);
|
||||
free(old);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user