From 329843f682d1216d4f41aab7b5711f21ef280b71 Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Wed, 25 Jan 2023 14:12:20 +0000 Subject: [PATCH] gmem: Add g_free_sized() and g_aligned_free_sized() These wrap `free_sized()` and `free_aligned_sized()`, which are present in C23[1]. This means that user code can start to use them without checking for C23 support everywhere first. It also means we can use them internally in GSlice to get a bit of performance for the code which still uses it. See https://en.cppreference.com/w/c/memory/free_aligned_sized and https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2699.htm. [1]: Specifically, section 7.24.3.4 of the latest C23 draft at https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3088.pdf. Signed-off-by: Philip Withnall Conflict:NA Reference:https://gitlab.gnome.org/GNOME/glib/-/commit/329843f682d1216d4f41aab7b5711f21ef280b71 diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt index 3532d28..ac93ae6 100644 --- a/docs/reference/glib/glib-sections.txt +++ b/docs/reference/glib/glib-sections.txt @@ -1397,6 +1397,7 @@ g_try_realloc_n g_free +g_free_sized g_clear_pointer g_steal_pointer g_mem_gc_friendly @@ -1411,6 +1412,7 @@ g_newa0 g_aligned_alloc g_aligned_alloc0 g_aligned_free +g_aligned_free_sized g_memmove diff --git a/glib/gmem.c b/glib/gmem.c index 060e91a..e94268a 100644 --- a/glib/gmem.c +++ b/glib/gmem.c @@ -209,6 +209,9 @@ g_realloc (gpointer mem, * * Frees the memory pointed to by @mem. * + * If you know the allocated size of @mem, calling g_free_sized() may be faster, + * depending on the libc implementation in use. + * * If @mem is %NULL it simply returns, so there is no need to check @mem * against %NULL before calling this function. */ @@ -219,6 +222,33 @@ g_free (gpointer mem) TRACE(GLIB_MEM_FREE((void*) mem)); } +/** + * g_free_sized: + * @mem: (nullable): the memory to free + * @size: size of @mem, in bytes + * + * Frees the memory pointed to by @mem, assuming it is has the given @size. + * + * If @mem is %NULL this is a no-op (and @size is ignored). + * + * It is an error if @size doesn鈥檛 match the size passed when @mem was + * allocated. @size is passed to this function to allow optimizations in the + * allocator. If you don鈥檛 know the allocation size, use g_free() instead. + * + * Since: 2.72 + */ +void +g_free_sized (void *mem, + size_t size) +{ +#ifdef HAVE_FREE_SIZED + free_sized (mem, size); +#else + free (mem); +#endif + TRACE (GLIB_MEM_FREE ((void*) mem)); +} + /** * g_clear_pointer: (skip) * @pp: (not nullable): a pointer to a variable, struct member etc. holding a @@ -555,7 +585,7 @@ g_mem_profile (void) * multiplication. * * Aligned memory allocations returned by this function can only be - * freed using g_aligned_free(). + * freed using g_aligned_free_sized() or g_aligned_free(). * * Returns: (transfer full): the allocated memory * @@ -679,3 +709,33 @@ g_aligned_free (gpointer mem) { aligned_free (mem); } + +/** + * g_aligned_free_sized: + * @mem: (nullable): the memory to free + * @alignment: alignment of @mem + * @size: size of @mem, in bytes + * + * Frees the memory pointed to by @mem, assuming it is has the given @size and + * @alignment. + * + * If @mem is %NULL this is a no-op (and @size is ignored). + * + * It is an error if @size doesn鈥檛 match the size, or @alignment doesn鈥檛 match + * the alignment, passed when @mem was allocated. @size and @alignment are + * passed to this function to allow optimizations in the allocator. If you + * don鈥檛 know either of them, use g_aligned_free() instead. + * + * Since: 2.72 + */ +void +g_aligned_free_sized (void *mem, + size_t alignment, + size_t size) +{ +#ifdef HAVE_FREE_ALIGNED_SIZED + free_aligned_sized (mem, alignment, size); +#else + aligned_free (mem); +#endif +} diff --git a/glib/gmem.h b/glib/gmem.h index d29907a..7b306b3 100644 --- a/glib/gmem.h +++ b/glib/gmem.h @@ -70,6 +70,9 @@ typedef struct _GMemVTable GMemVTable; GLIB_AVAILABLE_IN_ALL void g_free (gpointer mem); +GLIB_AVAILABLE_IN_2_72 +void g_free_sized (gpointer mem, + size_t size); GLIB_AVAILABLE_IN_2_34 void g_clear_pointer (gpointer *pp, @@ -121,6 +124,10 @@ gpointer g_aligned_alloc0 (gsize n_blocks, gsize alignment) G_GNUC_WARN_UNUSED_RESULT G_GNUC_ALLOC_SIZE2(1,2); GLIB_AVAILABLE_IN_2_72 void g_aligned_free (gpointer mem); +GLIB_AVAILABLE_IN_2_72 +void g_aligned_free_sized (gpointer mem, + size_t alignment, + size_t size); #if defined(glib_typeof) && GLIB_VERSION_MAX_ALLOWED >= GLIB_VERSION_2_58 #define g_clear_pointer(pp, destroy) \ diff --git a/glib/tests/utils.c b/glib/tests/utils.c index dcdc5a6..602abe1 100644 --- a/glib/tests/utils.c +++ b/glib/tests/utils.c @@ -1000,6 +1000,39 @@ test_aligned_mem_zeroed (void) g_aligned_free (p); } +static void +test_aligned_mem_free_sized (void) +{ + gsize n_blocks = 10; + guint *p; + + g_test_summary ("Check that g_aligned_free_sized() works"); + + p = g_aligned_alloc (n_blocks, sizeof (*p), 16); + g_assert_nonnull (p); + + g_aligned_free_sized (p, sizeof (*p), n_blocks * 16); + + /* NULL should be ignored */ + g_aligned_free_sized (NULL, sizeof (*p), n_blocks * 16); +} + +static void +test_free_sized (void) +{ + gpointer p; + + g_test_summary ("Check that g_free_sized() works"); + + p = g_malloc (123); + g_assert_nonnull (p); + + g_free_sized (p, 123); + + /* NULL should be ignored */ + g_free_sized (NULL, 123); +} + static void test_nullify (void) { @@ -1174,6 +1207,8 @@ main (int argc, g_test_add_func ("/utils/aligned-mem/subprocess/aligned_alloc_nmov", aligned_alloc_nmov); g_test_add_func ("/utils/aligned-mem/alignment", test_aligned_mem_alignment); g_test_add_func ("/utils/aligned-mem/zeroed", test_aligned_mem_zeroed); + g_test_add_func ("/utils/aligned-mem/free-sized", test_aligned_mem_free_sized); + g_test_add_func ("/utils/free-sized", test_free_sized); g_test_add_func ("/utils/nullify", test_nullify); g_test_add_func ("/utils/atexit", test_atexit); g_test_add_func ("/utils/check-setuid", test_check_setuid); diff --git a/meson.build b/meson.build index 657e9f6..3f32ef7 100644 --- a/meson.build +++ b/meson.build @@ -535,6 +535,8 @@ functions = [ 'fchmod', 'fchown', 'fdwalk', + 'free_aligned_sized', + 'free_sized', 'fsync', 'getauxval', 'getc_unlocked', -- 2.33.0