From 4144d506bbe1b34b17093f5bbeb9135b986492d8 Mon Sep 17 00:00:00 2001 From: Ariadne Conill Date: Wed, 6 Oct 2021 11:48:13 -0600 Subject: [PATCH] implement dependency refcounting --- libpkgconf/dependency.c | 52 +++++++++++++++++++++++++++++++++++++---- libpkgconf/libpkgconf.h | 5 ++++ 2 files changed, 53 insertions(+), 4 deletions(-) diff --git a/libpkgconf/dependency.c b/libpkgconf/dependency.c index 616c0c2..e5b29c2 100644 --- a/libpkgconf/dependency.c +++ b/libpkgconf/dependency.c @@ -92,7 +92,7 @@ add_or_replace_dependency_node(const pkgconf_client_t *client, pkgconf_dependenc { PKGCONF_TRACE(client, "dropping dependency [%s]@%p because of collision", depbuf, dep); - free(dep); + pkgconf_dependency_unref(dep->owner, dep); return NULL; } else if (dep2->flags && dep->flags == 0) @@ -100,7 +100,7 @@ add_or_replace_dependency_node(const pkgconf_client_t *client, pkgconf_dependenc PKGCONF_TRACE(client, "dropping dependency [%s]@%p because of collision", depbuf2, dep2); pkgconf_node_delete(&dep2->iter, list); - free(dep2); + pkgconf_dependency_unref(dep2->owner, dep2); } else /* If both dependencies have equal strength, we keep both, because of situations like: @@ -115,7 +115,7 @@ add_or_replace_dependency_node(const pkgconf_client_t *client, pkgconf_dependenc PKGCONF_TRACE(client, "added dependency [%s] to list @%p; flags=%x", dependency_to_str(dep, depbuf, sizeof depbuf), list, dep->flags); pkgconf_node_insert_tail(&dep->iter, dep, list); - return dep; + return pkgconf_dependency_ref(dep->owner, dep); } static inline pkgconf_dependency_t * @@ -131,6 +131,8 @@ pkgconf_dependency_addraw(const pkgconf_client_t *client, pkgconf_list_t *list, dep->compare = compare; dep->flags = flags; + dep->owner = client; + dep->refcount = 0; return add_or_replace_dependency_node(client, dep, list); } @@ -202,6 +204,48 @@ pkgconf_dependency_free_one(pkgconf_dependency_t *dep) free(dep); } +/* + * !doc + * + * .. c:function:: pkgconf_dependency_t *pkgconf_dependency_ref(pkgconf_client_t *owner, pkgconf_dependency_t *dep) + * + * Increases a dependency node's refcount. + * + * :param pkgconf_client_t* owner: The client object which owns the memory of this dependency node. + * :param pkgconf_dependency_t* dep: The dependency to increase the refcount of. + * :return: the dependency node on success, else NULL + */ +pkgconf_dependency_t * +pkgconf_dependency_ref(pkgconf_client_t *client, pkgconf_dependency_t *dep) +{ + if (client != dep->owner) + return NULL; + + dep->refcount++; + return dep; +} + +/* + * !doc + * + * .. c:function:: void pkgconf_dependency_unref(pkgconf_client_t *owner, pkgconf_dependency_t *dep) + * + * Decreases a dependency node's refcount and frees it if necessary. + * + * :param pkgconf_client_t* owner: The client object which owns the memory of this dependency node. + * :param pkgconf_dependency_t* dep: The dependency to decrease the refcount of. + * :return: nothing + */ +void +pkgconf_dependency_unref(pkgconf_client_t *client, pkgconf_dependency_t *dep) +{ + if (client != dep->owner) + return; + + if (--dep->refcount <= 0) + pkgconf_dependency_free_one(dep); +} + /* * !doc * @@ -222,7 +266,7 @@ pkgconf_dependency_free(pkgconf_list_t *list) pkgconf_dependency_t *dep = node->data; pkgconf_node_delete(&dep->iter, list); - pkgconf_dependency_free_one(dep); + pkgconf_dependency_unref(dep->owner, dep); } } diff --git a/libpkgconf/libpkgconf.h b/libpkgconf/libpkgconf.h index d0f5f3d..9ee5e30 100644 --- a/libpkgconf/libpkgconf.h +++ b/libpkgconf/libpkgconf.h @@ -100,6 +100,9 @@ struct pkgconf_dependency_ { pkgconf_pkg_t *match; unsigned int flags; + + int refcount; + pkgconf_client_t *owner; }; struct pkgconf_tuple_ { @@ -322,6 +325,8 @@ PKGCONF_API void pkgconf_dependency_append(pkgconf_list_t *list, pkgconf_depende PKGCONF_API void pkgconf_dependency_free(pkgconf_list_t *list); PKGCONF_API void pkgconf_dependency_free_one(pkgconf_dependency_t *dep); PKGCONF_API pkgconf_dependency_t *pkgconf_dependency_add(const pkgconf_client_t *client, pkgconf_list_t *list, const char *package, const char *version, pkgconf_pkg_comparator_t compare, unsigned int flags); +PKGCONF_API pkgconf_dependency_t *pkgconf_dependency_ref(pkgconf_client_t *client, pkgconf_dependency_t *dep); +PKGCONF_API void pkgconf_dependency_unref(pkgconf_client_t *client, pkgconf_dependency_t *dep); /* argvsplit.c */ PKGCONF_API int pkgconf_argv_split(const char *src, int *argc, char ***argv);