Merge branch '3234-libgirepository-refcount-cycle' into 'main'

gibaseinfo: Break refcount cycle with GIRepository

Closes #3234

See merge request GNOME/glib!3852
This commit is contained in:
Philip Withnall 2024-01-25 22:52:17 +00:00
commit 7262f5ab14
3 changed files with 20 additions and 5 deletions

View File

@ -126,9 +126,6 @@ gi_base_info_finalize (GIBaseInfo *self)
if (self->ref_count != INVALID_REFCOUNT && if (self->ref_count != INVALID_REFCOUNT &&
self->container && self->container->ref_count != INVALID_REFCOUNT) self->container && self->container->ref_count != INVALID_REFCOUNT)
gi_base_info_unref (self->container); gi_base_info_unref (self->container);
if (self->ref_count != INVALID_REFCOUNT)
g_clear_object (&self->repository);
} }
static void static void
@ -356,7 +353,14 @@ gi_info_new_full (GIInfoType type,
if (container && container->ref_count != INVALID_REFCOUNT) if (container && container->ref_count != INVALID_REFCOUNT)
gi_base_info_ref (info->container); gi_base_info_ref (info->container);
info->repository = g_object_ref (repository); /* Dont keep a strong ref, since the repository keeps a cache of #GIBaseInfos
* and holds refs on them. If we kept a ref here, thered be a cycle.
* Dont keep a weak ref either, as that would make creating/destroying a
* #GIBaseInfo noticeably more expensive, and infos are performance critical
* for bindings.
* As stated in the documentation, the mitigation here is to require the user
* to keep the #GIRepository alive longer than any of its #GIBaseInfos. */
info->repository = repository;
return (GIBaseInfo*)info; return (GIBaseInfo*)info;
} }

View File

@ -48,8 +48,9 @@ struct _GIBaseInfo
GTypeInstance parent_instance; GTypeInstance parent_instance;
gatomicrefcount ref_count; gatomicrefcount ref_count;
/* these are both reffed if the GIBaseInfo is heap-allocated, but not reffed if its stack-allocated */ /* @repository is never reffed, as that would lead to a refcount cycle with the repository */
GIRepository *repository; GIRepository *repository;
/* @container is reffed if the GIBaseInfo is heap-allocated, but not reffed if its stack-allocated */
GIBaseInfo *container; GIBaseInfo *container;
GITypelib *typelib; GITypelib *typelib;

View File

@ -42,6 +42,16 @@
* `GIRepository` is used to manage repositories of namespaces. Namespaces * `GIRepository` is used to manage repositories of namespaces. Namespaces
* are represented on disk by type libraries (`.typelib` files). * are represented on disk by type libraries (`.typelib` files).
* *
* The individual pieces of API within a type library are represented by
* subclasses of [class@GIRepository.BaseInfo]. These can be found using
* methods like [method@GIRepository.Repository.find_by_name] or
* [method@GIRepository.Repository.get_info].
*
* You are responsible for ensuring that the lifetime of the
* [class@GIRepository.Repository] exceeds that of the lifetime of any of its
* [class@GIRepository.BaseInfo]s. This cannot be guaranteed by using internal
* references within libgirepository as that would affect performance.
*
* ### Discovery of type libraries * ### Discovery of type libraries
* *
* `GIRepository` will typically look for a `girepository-1.0` directory * `GIRepository` will typically look for a `girepository-1.0` directory