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 <pwithnall@endlessos.org>
This commit is contained in:
Philip Withnall 2023-01-25 14:12:20 +00:00
parent 0f7797d76d
commit 329843f682
5 changed files with 107 additions and 1 deletions

View File

@ -1082,6 +1082,7 @@ g_try_realloc_n
<SUBSECTION>
g_free
g_free_sized
g_clear_pointer
g_steal_pointer
g_mem_gc_friendly
@ -1096,6 +1097,7 @@ g_newa0
g_aligned_alloc
g_aligned_alloc0
g_aligned_free
g_aligned_free_sized
<SUBSECTION>
g_memmove

View File

@ -220,6 +220,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.
*/
@ -230,6 +233,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 doesnt match the size passed when @mem was
* allocated. @size is passed to this function to allow optimizations in the
* allocator. If you dont know the allocation size, use g_free() instead.
*
* Since: 2.76
*/
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: (nullable) (not optional) (inout) (transfer full): a pointer to a
@ -578,7 +608,7 @@ g_mem_profile (void)
* the program is terminated.
*
* 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
*
@ -702,3 +732,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 doesnt match the size, or @alignment doesnt match
* the alignment, passed when @mem was allocated. @size and @alignment are
* passed to this function to allow optimizations in the allocator. If you
* dont know either of them, use g_aligned_free() instead.
*
* Since: 2.76
*/
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
}

View File

@ -72,6 +72,9 @@ typedef struct _GMemVTable GMemVTable;
GLIB_AVAILABLE_IN_ALL
void g_free (gpointer mem);
GLIB_AVAILABLE_IN_2_76
void g_free_sized (gpointer mem,
size_t size);
GLIB_AVAILABLE_IN_2_34
void g_clear_pointer (gpointer *pp,
@ -123,6 +126,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_76
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) \

View File

@ -1142,6 +1142,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)
{
@ -1317,6 +1350,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);

View File

@ -614,6 +614,8 @@ functions = [
'fchmod',
'fchown',
'fdwalk',
'free_aligned_sized',
'free_sized',
'fsync',
'getauxval',
'getc_unlocked',