gitypelib: Switch to refcounting

Since `GITypelib` is exposed in the public libgirepository API, it needs
to be a boxed type. So we either need to add a `copy` method to mirror
the existing `free` method, or switch to refcounting. The latter option
seems better, since a `GITypelib` contains internal state about open
`GModule`s and the semantics for copying that would be potentially
complex.

Signed-off-by: Philip Withnall <pwithnall@gnome.org>

Helps: #3155
This commit is contained in:
Philip Withnall 2024-02-07 14:38:05 +00:00
parent 702719dee9
commit 5cc5f413f5
6 changed files with 54 additions and 26 deletions

View File

@ -71,6 +71,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] |

View File

@ -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");

View File

@ -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,
@ -513,7 +513,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
{
@ -534,7 +534,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 */
@ -685,7 +685,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`
*
@ -1706,6 +1706,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;
@ -1762,7 +1763,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);
@ -1789,7 +1790,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)
@ -1799,18 +1799,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;
}
ret = typelib;
out:
g_clear_pointer (&typelib_owned, gi_typelib_unref);
g_free (tmp_version);
g_free (path);
return ret;

View File

@ -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) */

View File

@ -2353,6 +2353,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,15 +2363,40 @@ 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_return_if_fail (typelib != NULL);
if (g_atomic_ref_count_dec (&typelib->ref_count))
{
g_clear_pointer (&typelib->bytes, g_bytes_unref);
@ -2383,6 +2409,7 @@ gi_typelib_free (GITypelib *typelib)
}
g_slice_free (GITypelib, typelib);
}
}
/**
* gi_typelib_get_namespace:

View File

@ -41,7 +41,9 @@ 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,