diff --git a/docs/reference/girepository/migrating-gi.md b/docs/reference/girepository/migrating-gi.md index 54f12b227..ad49e1b45 100644 --- a/docs/reference/girepository/migrating-gi.md +++ b/docs/reference/girepository/migrating-gi.md @@ -72,6 +72,7 @@ your code if integer type warnings are enabled. | `g_type_info_get_array_length` and `g_type_info_get_array_fixed_size` | Split success and failure return values out into a new out-argument and return value | | `g_type_info_get_array_length` | [method@GIRepository.TypeInfo.get_array_length_index] | | `g_typelib_new_from_*` | All replaced with `gi_typelib_new_from_bytes()` | +| `g_typelib_free` | [type@GIRepository.Typelib] is now a refcounted and boxed type, so use [method@GIRepository.Typelib.unref] | | `GI_FUNCTION_THROWS` and `GI_VFUNC_THROWS` | [method@GIRepository.CallableInfo.can_throw_gerror] | | `g_union_info_get_copy_function` | [method@GIRepository.UnionInfo.get_copy_function_name] | | `g_union_info_get_free_function` | [method@GIRepository.UnionInfo.get_free_function_name] | diff --git a/girepository/compiler/compiler.c b/girepository/compiler/compiler.c index 4920c6b63..120b474a7 100644 --- a/girepository/compiler/compiler.c +++ b/girepository/compiler/compiler.c @@ -218,7 +218,7 @@ main (int argc, char **argv) g_debug ("[building] start"); { - GITypelib *typelib; + GITypelib *typelib = NULL; if (shlibs) { @@ -238,8 +238,8 @@ main (int argc, char **argv) if (!write_out_typelib (NULL, typelib)) return 1; - gi_typelib_free (typelib); - typelib = NULL; + + g_clear_pointer (&typelib, gi_typelib_unref); } g_debug ("[building] done"); diff --git a/girepository/girepository.c b/girepository/girepository.c index 7c3dff21c..1185ff2ba 100644 --- a/girepository/girepository.c +++ b/girepository/girepository.c @@ -185,11 +185,11 @@ gi_repository_init (GIRepository *repository) repository->typelibs = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, - (GDestroyNotify) gi_typelib_free); + (GDestroyNotify) gi_typelib_unref); repository->lazy_typelibs = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, - (GDestroyNotify) NULL); + (GDestroyNotify) gi_typelib_unref); repository->info_by_gtype = g_hash_table_new_full (g_direct_hash, g_direct_equal, (GDestroyNotify) NULL, @@ -519,7 +519,7 @@ register_internal (GIRepository *repository, g_assert (!g_hash_table_lookup (repository->lazy_typelibs, namespace)); g_hash_table_insert (repository->lazy_typelibs, - build_typelib_key (namespace, source), (void *)typelib); + build_typelib_key (namespace, source), gi_typelib_ref (typelib)); } else { @@ -540,7 +540,7 @@ register_internal (GIRepository *repository, g_hash_table_insert (repository->typelibs, g_steal_pointer (&key), - (void *)typelib); + gi_typelib_ref (typelib)); } /* These types might be resolved now, clear the cache */ @@ -709,7 +709,7 @@ gi_repository_get_dependencies (GIRepository *repository, /** * gi_repository_load_typelib: * @repository: A #GIRepository - * @typelib: the typelib to load + * @typelib: (transfer none): the typelib to load * @flags: flags affecting the loading operation * @error: return location for a [type@GLib.Error], or `NULL` * @@ -1745,6 +1745,7 @@ require_internal (GIRepository *repository, GITypelib *ret = NULL; Header *header; GITypelib *typelib = NULL; + GITypelib *typelib_owned = NULL; const char *typelib_namespace, *typelib_version; gboolean allow_lazy = (flags & GI_REPOSITORY_LOAD_FLAG_LAZY) > 0; gboolean is_lazy; @@ -1801,7 +1802,7 @@ require_internal (GIRepository *repository, GBytes *bytes = NULL; bytes = g_mapped_file_get_bytes (mfile); - typelib = gi_typelib_new_from_bytes (bytes, &temp_error); + typelib_owned = typelib = gi_typelib_new_from_bytes (bytes, &temp_error); g_bytes_unref (bytes); g_clear_pointer (&mfile, g_mapped_file_unref); @@ -1828,7 +1829,6 @@ require_internal (GIRepository *repository, "Typelib file %s for namespace '%s' contains " "namespace '%s' which doesn't match the file name", path, namespace, typelib_namespace); - gi_typelib_free (typelib); goto out; } if (version != NULL && strcmp (typelib_version, version) != 0) @@ -1838,18 +1838,15 @@ require_internal (GIRepository *repository, "Typelib file %s for namespace '%s' contains " "version '%s' which doesn't match the expected version '%s'", path, namespace, typelib_version, version); - gi_typelib_free (typelib); goto out; } if (!register_internal (repository, path, allow_lazy, typelib, error)) - { - gi_typelib_free (typelib); - goto out; - } + goto out; ret = typelib; out: + g_clear_pointer (&typelib_owned, gi_typelib_unref); g_free (tmp_version); g_free (path); return ret; diff --git a/girepository/gitypelib-internal.h b/girepository/gitypelib-internal.h index 2639c0e1f..dd3aacaf3 100644 --- a/girepository/gitypelib-internal.h +++ b/girepository/gitypelib-internal.h @@ -1313,6 +1313,7 @@ typedef struct { struct _GITypelib { /*< private >*/ + gatomicrefcount ref_count; const uint8_t *data; /* just a cached pointer to inside @bytes */ size_t len; GBytes *bytes; /* (owned) */ diff --git a/girepository/gitypelib.c b/girepository/gitypelib.c index b47c1015f..3c88a79e6 100644 --- a/girepository/gitypelib.c +++ b/girepository/gitypelib.c @@ -41,6 +41,8 @@ * Since: 2.80 */ +G_DEFINE_BOXED_TYPE (GITypelib, gi_typelib, gi_typelib_ref, gi_typelib_unref) + typedef struct { GITypelib *typelib; GSList *context_stack; @@ -2353,6 +2355,7 @@ gi_typelib_new_from_bytes (GBytes *bytes, return NULL; meta = g_slice_new0 (GITypelib); + g_atomic_ref_count_init (&meta->ref_count); meta->bytes = g_bytes_ref (bytes); meta->data = data; meta->len = len; @@ -2362,26 +2365,52 @@ gi_typelib_new_from_bytes (GBytes *bytes, } /** - * gi_typelib_free: + * gi_typelib_ref: + * @typelib: (transfer none): a #GITypelib + * + * Increment the reference count of a [type@GIRepository.Typelib]. + * + * Returns: (transfer full): the same @typelib pointer + * Since: 2.80 + */ +GITypelib * +gi_typelib_ref (GITypelib *typelib) +{ + g_return_val_if_fail (typelib != NULL, NULL); + + g_atomic_ref_count_inc (&typelib->ref_count); + + return typelib; +} + +/** + * gi_typelib_unref: * @typelib: (transfer full): a #GITypelib * - * Free a [type@GIRepository.Typelib]. + * Decrement the reference count of a [type@GIRepository.Typelib]. + * + * Once the reference count reaches zero, the typelib is freed. * * Since: 2.80 */ void -gi_typelib_free (GITypelib *typelib) +gi_typelib_unref (GITypelib *typelib) { - g_clear_pointer (&typelib->bytes, g_bytes_unref); + g_return_if_fail (typelib != NULL); - g_clear_pointer (&typelib->library_paths, g_ptr_array_unref); - - if (typelib->modules) + if (g_atomic_ref_count_dec (&typelib->ref_count)) { - g_list_foreach (typelib->modules, (GFunc) (void *) g_module_close, NULL); - g_list_free (typelib->modules); + g_clear_pointer (&typelib->bytes, g_bytes_unref); + + g_clear_pointer (&typelib->library_paths, g_ptr_array_unref); + + if (typelib->modules) + { + g_list_foreach (typelib->modules, (GFunc) (void *) g_module_close, NULL); + g_list_free (typelib->modules); + } + g_slice_free (GITypelib, typelib); } - g_slice_free (GITypelib, typelib); } /** diff --git a/girepository/gitypelib.h b/girepository/gitypelib.h index 17bbd0020..add5804de 100644 --- a/girepository/gitypelib.h +++ b/girepository/gitypelib.h @@ -36,12 +36,18 @@ G_BEGIN_DECLS typedef struct _GITypelib GITypelib; +#define GI_TYPE_TYPELIB (gi_typelib_get_type ()) +GI_AVAILABLE_IN_ALL +GType gi_typelib_get_type (void) G_GNUC_CONST; + GI_AVAILABLE_IN_ALL GITypelib * gi_typelib_new_from_bytes (GBytes *bytes, GError **error); GI_AVAILABLE_IN_ALL -void gi_typelib_free (GITypelib *typelib); +GITypelib * gi_typelib_ref (GITypelib *typelib); +GI_AVAILABLE_IN_ALL +void gi_typelib_unref (GITypelib *typelib); GI_AVAILABLE_IN_ALL gboolean gi_typelib_symbol (GITypelib *typelib,