Merge branch 'migrate-to-gi-docgen12' into 'main'

gdir, gstrvbuilder: Add refcounting support and a boxed type

See merge request GNOME/glib!3722
This commit is contained in:
Philip Withnall 2023-11-28 11:47:11 +00:00
commit e4fe837bae
6 changed files with 142 additions and 16 deletions

View File

@ -56,6 +56,7 @@
struct _GDir
{
gatomicrefcount ref_count;
#ifdef G_OS_WIN32
_WDIR *wdirp;
#else
@ -89,10 +90,13 @@ GDir *
g_dir_open_with_errno (const gchar *path,
guint flags)
{
GDir dir;
#ifdef G_OS_WIN32
GDir *dir;
_WDIR *wdirp;
gint saved_errno;
wchar_t *wpath;
#else
DIR *dirp;
#endif
g_return_val_if_fail (path != NULL, NULL);
@ -102,21 +106,27 @@ g_dir_open_with_errno (const gchar *path,
g_return_val_if_fail (wpath != NULL, NULL);
dir.wdirp = _wopendir (wpath);
wdirp = _wopendir (wpath);
saved_errno = errno;
g_free (wpath);
errno = saved_errno;
if (dir.wdirp == NULL)
if (wdirp == NULL)
return NULL;
dir = g_new0 (GDir, 1);
g_atomic_ref_count_init (&dir->ref_count);
dir->wdirp = wdirp;
return g_steal_pointer (&dir);
#else
dir.dirp = opendir (path);
dirp = opendir (path);
if (dir.dirp == NULL)
if (dirp == NULL)
return NULL;
#endif
return g_memdup2 (&dir, sizeof dir);
return g_dir_new_from_dirp (dirp);
#endif
}
/**
@ -187,7 +197,8 @@ g_dir_new_from_dirp (gpointer dirp)
g_return_val_if_fail (dirp != NULL, NULL);
dir = g_new (GDir, 1);
dir = g_new0 (GDir, 1);
g_atomic_ref_count_init (&dir->ref_count);
dir->dirp = dirp;
return dir;
@ -287,23 +298,84 @@ g_dir_rewind (GDir *dir)
#endif
}
static void
g_dir_actually_close (GDir *dir)
{
#ifdef G_OS_WIN32
g_clear_pointer (&dir->wdirp, _wclosedir);
#else
g_clear_pointer (&dir->dirp, closedir);
#endif
}
/**
* g_dir_close:
* @dir: (transfer full): a #GDir* created by g_dir_open()
*
* Closes the directory and deallocates all related resources.
* Closes the directory immediately and decrements the reference count.
*
* Once the reference count reaches zero, the `GDir` structure itself will be
* freed. Prior to GLib 2.80, `GDir` was not reference counted.
*
* It is an error to call any of the `GDir` methods other than
* [method@GLib.Dir.ref] and [method@GLib.Dir.unref] on a `GDir` after calling
* [method@GLib.Dir.close] on it.
**/
void
g_dir_close (GDir *dir)
{
g_return_if_fail (dir != NULL);
#ifdef G_OS_WIN32
_wclosedir (dir->wdirp);
#else
closedir (dir->dirp);
#endif
g_dir_actually_close (dir);
g_dir_unref (dir);
}
/**
* g_dir_ref:
* @dir: (transfer none): a `GDir`
*
* Increment the reference count of `dir`.
*
* Returns: (transfer full): the same pointer as `dir`
* Since: 2.80
*/
GDir *
g_dir_ref (GDir *dir)
{
g_return_val_if_fail (dir != NULL, NULL);
g_atomic_ref_count_inc (&dir->ref_count);
return dir;
}
/**
* g_dir_unref:
* @dir: (transfer full): a `GDir`
*
* Decrements the reference count of `dir`.
*
* Once the reference count reaches zero, the directory will be closed and all
* resources associated with it will be freed. If [method@GLib.Dir.close] is
* called when the reference count is greater than zero, the directory is closed
* but the `GDir` structure will not be freed until its reference count reaches
* zero.
*
* It is an error to call any of the `GDir` methods other than
* [method@GLib.Dir.ref] and [method@GLib.Dir.unref] on a `GDir` after calling
* [method@GLib.Dir.close] on it.
*
* Since: 2.80
*/
void
g_dir_unref (GDir *dir)
{
g_return_if_fail (dir != NULL);
if (g_atomic_ref_count_dec (&dir->ref_count))
{
g_dir_actually_close (dir);
g_free (dir);
}
}
#ifdef G_OS_WIN32

View File

@ -49,6 +49,11 @@ void g_dir_rewind (GDir *dir);
GLIB_AVAILABLE_IN_ALL
void g_dir_close (GDir *dir);
GLIB_AVAILABLE_IN_2_80
GDir * g_dir_ref (GDir *dir);
GLIB_AVAILABLE_IN_2_80
void g_dir_unref (GDir *dir);
G_END_DECLS
#endif /* __G_DIR_H__ */

View File

@ -57,7 +57,7 @@ typedef struct stat GStatBuf;
#endif
#if defined(G_OS_UNIX) && !defined(G_STDIO_WRAP_ON_UNIX)
#if defined(G_OS_UNIX) && !defined(G_STDIO_WRAP_ON_UNIX) && !defined(__GI_SCANNER__)
/* Just pass on to the system functions, so there's no potential for data
* format mismatches, especially with large file interfaces.

View File

@ -41,6 +41,29 @@ test_dir_nonexisting (void)
g_error_free (error);
}
static void
test_dir_refcounting (void)
{
GDir *dir;
GError *local_error = NULL;
g_test_summary ("Test refcounting interactions with g_dir_close()");
/* Try keeping the `GDir` struct alive after closing it. */
dir = g_dir_open (".", 0, &local_error);
g_assert_no_error (local_error);
g_dir_ref (dir);
g_dir_close (dir);
g_dir_unref (dir);
/* Test that dropping the last ref closes it. Any leak here should be caught
* when the test is run under valgrind. */
dir = g_dir_open (".", 0, &local_error);
g_assert_no_error (local_error);
g_dir_unref (dir);
}
int
main (int argc, char *argv[])
{
@ -48,6 +71,7 @@ main (int argc, char *argv[])
g_test_add_func ("/dir/read", test_dir_read);
g_test_add_func ("/dir/nonexisting", test_dir_nonexisting);
g_test_add_func ("/dir/refcounting", test_dir_refcounting);
return g_test_run ();
}

View File

@ -139,6 +139,7 @@ G_DEFINE_BOXED_TYPE (GKeyFile, g_key_file, g_key_file_ref, g_key_file_unref)
G_DEFINE_BOXED_TYPE (GMappedFile, g_mapped_file, g_mapped_file_ref, g_mapped_file_unref)
G_DEFINE_BOXED_TYPE (GBookmarkFile, g_bookmark_file, g_bookmark_file_copy, g_bookmark_file_free)
G_DEFINE_BOXED_TYPE (GHmac, g_hmac, g_hmac_ref, g_hmac_unref)
G_DEFINE_BOXED_TYPE (GDir, g_dir, g_dir_ref, g_dir_unref)
G_DEFINE_BOXED_TYPE (GMainLoop, g_main_loop, g_main_loop_ref, g_main_loop_unref)
G_DEFINE_BOXED_TYPE (GMainContext, g_main_context, g_main_context_ref, g_main_context_unref)
@ -153,6 +154,8 @@ G_DEFINE_BOXED_TYPE (GUri, g_uri, g_uri_ref, g_uri_unref)
G_DEFINE_BOXED_TYPE (GOptionGroup, g_option_group, g_option_group_ref, g_option_group_unref)
G_DEFINE_BOXED_TYPE (GPatternSpec, g_pattern_spec, g_pattern_spec_copy, g_pattern_spec_free);
G_DEFINE_BOXED_TYPE (GStrvBuilder, g_strv_builder, g_strv_builder_ref, g_strv_builder_unref);
/* This one can't use G_DEFINE_BOXED_TYPE (GStrv, g_strv, g_strdupv, g_strfreev) */
GType
g_strv_get_type (void)

View File

@ -345,6 +345,24 @@ typedef gsize GType;
*/
#define G_TYPE_HMAC (g_hmac_get_type ())
/**
* G_TYPE_DIR:
*
* The #GType for a boxed type holding a #GDir.
*
* Since: 2.80
*/
#define G_TYPE_DIR (g_dir_get_type ())
/**
* G_TYPE_STRV_BUILDER:
*
* The #GType for a boxed type holding a #GStrvBuilder.
*
* Since: 2.80
*/
#define G_TYPE_STRV_BUILDER (g_strv_builder_get_type ())
GOBJECT_AVAILABLE_IN_ALL
GType g_date_get_type (void) G_GNUC_CONST;
GOBJECT_AVAILABLE_IN_ALL
@ -411,6 +429,10 @@ GOBJECT_AVAILABLE_IN_2_76
GType g_bookmark_file_get_type (void) G_GNUC_CONST;
GOBJECT_AVAILABLE_IN_2_80
GType g_hmac_get_type (void) G_GNUC_CONST;
GOBJECT_AVAILABLE_IN_2_80
GType g_dir_get_type (void) G_GNUC_CONST;
GOBJECT_AVAILABLE_IN_2_80
GType g_strv_builder_get_type (void) G_GNUC_CONST;
GOBJECT_DEPRECATED_FOR('G_TYPE_VARIANT')
GType g_variant_get_gtype (void) G_GNUC_CONST;