mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-02-10 04:45:48 +01:00
GSlice can handle NULL arguments or return NULL values, but we did not properly mark them all the times.
385 lines
11 KiB
C
385 lines
11 KiB
C
/* GLIB sliced memory - fast concurrent memory chunk allocator
|
||
* Copyright (C) 2005 Tim Janik
|
||
*
|
||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||
*
|
||
* This library is free software; you can redistribute it and/or
|
||
* modify it under the terms of the GNU Lesser General Public
|
||
* License as published by the Free Software Foundation; either
|
||
* version 2.1 of the License, or (at your option) any later version.
|
||
*
|
||
* This library is distributed in the hope that it will be useful,
|
||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
* Lesser General Public License for more details.
|
||
*
|
||
* You should have received a copy of the GNU Lesser General Public
|
||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||
*/
|
||
/* MT safe */
|
||
|
||
#include "config.h"
|
||
#include "glibconfig.h"
|
||
|
||
#include <stdio.h>
|
||
#include <string.h>
|
||
|
||
#include "gslice.h"
|
||
|
||
#include "gmem.h" /* gslice.h */
|
||
#include "glib_trace.h"
|
||
#include "gprintf.h"
|
||
|
||
/**
|
||
* SECTION:memory_slices
|
||
* @title: Memory Slices
|
||
* @short_description: efficient way to allocate groups of equal-sized
|
||
* chunks of memory
|
||
*
|
||
* GSlice was a space-efficient and multi-processing scalable way to allocate
|
||
* equal sized pieces of memory. Since GLib 2.76, its implementation has been
|
||
* removed and it calls g_malloc() and g_free_sized(), because the performance
|
||
* of the system-default allocators has improved on all platforms since GSlice
|
||
* was written.
|
||
*
|
||
* The GSlice APIs have not been deprecated, as they are widely in use and doing
|
||
* so would be very disruptive for little benefit.
|
||
*
|
||
* New code should be written using g_new()/g_malloc() and g_free_sized() or
|
||
* g_free(). There is no particular benefit in porting existing code away from
|
||
* g_slice_new()/g_slice_free() unless it’s being rewritten anyway.
|
||
*
|
||
* Here is an example for using the slice allocator:
|
||
* |[<!-- language="C" -->
|
||
* gchar *mem[10000];
|
||
* gint i;
|
||
*
|
||
* // Allocate 10000 blocks.
|
||
* for (i = 0; i < 10000; i++)
|
||
* {
|
||
* mem[i] = g_slice_alloc (50);
|
||
*
|
||
* // Fill in the memory with some junk.
|
||
* for (j = 0; j < 50; j++)
|
||
* mem[i][j] = i * j;
|
||
* }
|
||
*
|
||
* // Now free all of the blocks.
|
||
* for (i = 0; i < 10000; i++)
|
||
* g_slice_free1 (50, mem[i]);
|
||
* ]|
|
||
*
|
||
* And here is an example for using the using the slice allocator
|
||
* with data structures:
|
||
* |[<!-- language="C" -->
|
||
* GRealArray *array;
|
||
*
|
||
* // Allocate one block, using the g_slice_new() macro.
|
||
* array = g_slice_new (GRealArray);
|
||
*
|
||
* // We can now use array just like a normal pointer to a structure.
|
||
* array->data = NULL;
|
||
* array->len = 0;
|
||
* array->alloc = 0;
|
||
* array->zero_terminated = (zero_terminated ? 1 : 0);
|
||
* array->clear = (clear ? 1 : 0);
|
||
* array->elt_size = elt_size;
|
||
*
|
||
* // We can free the block, so it can be reused.
|
||
* g_slice_free (GRealArray, array);
|
||
* ]|
|
||
*/
|
||
|
||
/* --- auxiliary functions --- */
|
||
void
|
||
g_slice_set_config (GSliceConfig ckey,
|
||
gint64 value)
|
||
{
|
||
/* deprecated, no implementation */
|
||
}
|
||
|
||
gint64
|
||
g_slice_get_config (GSliceConfig ckey)
|
||
{
|
||
/* deprecated, no implementation */
|
||
return 0;
|
||
}
|
||
|
||
gint64*
|
||
g_slice_get_config_state (GSliceConfig ckey,
|
||
gint64 address,
|
||
guint *n_values)
|
||
{
|
||
/* deprecated, no implementation */
|
||
return NULL;
|
||
}
|
||
|
||
/* --- API functions --- */
|
||
|
||
/**
|
||
* g_slice_new:
|
||
* @type: the type to allocate, typically a structure name
|
||
*
|
||
* A convenience macro to allocate a block of memory from the
|
||
* slice allocator.
|
||
*
|
||
* It calls g_slice_alloc() with `sizeof (@type)` and casts the
|
||
* returned pointer to a pointer of the given type, avoiding a type
|
||
* cast in the source code.
|
||
*
|
||
* This can never return %NULL as the minimum allocation size from
|
||
* `sizeof (@type)` is 1 byte.
|
||
*
|
||
* Since GLib 2.76 this always uses the system malloc() implementation
|
||
* internally.
|
||
*
|
||
* Returns: (not nullable): a pointer to the allocated block, cast to a pointer
|
||
* to @type
|
||
*
|
||
* Since: 2.10
|
||
*/
|
||
|
||
/**
|
||
* g_slice_new0:
|
||
* @type: the type to allocate, typically a structure name
|
||
*
|
||
* A convenience macro to allocate a block of memory from the
|
||
* slice allocator and set the memory to 0.
|
||
*
|
||
* It calls g_slice_alloc0() with `sizeof (@type)`
|
||
* and casts the returned pointer to a pointer of the given type,
|
||
* avoiding a type cast in the source code.
|
||
*
|
||
* This can never return %NULL as the minimum allocation size from
|
||
* `sizeof (@type)` is 1 byte.
|
||
*
|
||
* Since GLib 2.76 this always uses the system malloc() implementation
|
||
* internally.
|
||
*
|
||
* Returns: (not nullable): a pointer to the allocated block, cast to a pointer
|
||
* to @type
|
||
*
|
||
* Since: 2.10
|
||
*/
|
||
|
||
/**
|
||
* g_slice_dup:
|
||
* @type: the type to duplicate, typically a structure name
|
||
* @mem: (not nullable): the memory to copy into the allocated block
|
||
*
|
||
* A convenience macro to duplicate a block of memory using
|
||
* the slice allocator.
|
||
*
|
||
* It calls g_slice_copy() with `sizeof (@type)`
|
||
* and casts the returned pointer to a pointer of the given type,
|
||
* avoiding a type cast in the source code.
|
||
*
|
||
* This can never return %NULL.
|
||
*
|
||
* Since GLib 2.76 this always uses the system malloc() implementation
|
||
* internally.
|
||
*
|
||
* Returns: (not nullable): a pointer to the allocated block, cast to a pointer
|
||
* to @type
|
||
*
|
||
* Since: 2.14
|
||
*/
|
||
|
||
/**
|
||
* g_slice_free:
|
||
* @type: the type of the block to free, typically a structure name
|
||
* @mem: (nullable): a pointer to the block to free
|
||
*
|
||
* A convenience macro to free a block of memory that has
|
||
* been allocated from the slice allocator.
|
||
*
|
||
* It calls g_slice_free1() using `sizeof (type)`
|
||
* as the block size.
|
||
* Note that the exact release behaviour can be changed with the
|
||
* [`G_DEBUG=gc-friendly`][G_DEBUG] environment variable.
|
||
*
|
||
* If @mem is %NULL, this macro does nothing.
|
||
*
|
||
* Since GLib 2.76 this always uses the system free() implementation internally.
|
||
*
|
||
* Since: 2.10
|
||
*/
|
||
|
||
/**
|
||
* g_slice_free_chain:
|
||
* @type: the type of the @mem_chain blocks
|
||
* @mem_chain: (nullable): a pointer to the first block of the chain
|
||
* @next: the field name of the next pointer in @type
|
||
*
|
||
* Frees a linked list of memory blocks of structure type @type.
|
||
*
|
||
* The memory blocks must be equal-sized, allocated via
|
||
* g_slice_alloc() or g_slice_alloc0() and linked together by
|
||
* a @next pointer (similar to #GSList). The name of the
|
||
* @next field in @type is passed as third argument.
|
||
* Note that the exact release behaviour can be changed with the
|
||
* [`G_DEBUG=gc-friendly`][G_DEBUG] environment variable.
|
||
*
|
||
* If @mem_chain is %NULL, this function does nothing.
|
||
*
|
||
* Since GLib 2.76 this always uses the system free() implementation internally.
|
||
*
|
||
* Since: 2.10
|
||
*/
|
||
|
||
/**
|
||
* g_slice_alloc:
|
||
* @block_size: the number of bytes to allocate
|
||
*
|
||
* Allocates a block of memory from the libc allocator.
|
||
*
|
||
* The block address handed out can be expected to be aligned
|
||
* to at least `1 * sizeof (void*)`.
|
||
*
|
||
* Since GLib 2.76 this always uses the system malloc() implementation
|
||
* internally.
|
||
*
|
||
* Returns: (nullable): a pointer to the allocated memory block, which will
|
||
* be %NULL if and only if @mem_size is 0
|
||
*
|
||
* Since: 2.10
|
||
*/
|
||
gpointer
|
||
g_slice_alloc (gsize mem_size)
|
||
{
|
||
gpointer mem;
|
||
|
||
mem = g_malloc (mem_size);
|
||
TRACE (GLIB_SLICE_ALLOC((void*)mem, mem_size));
|
||
|
||
return mem;
|
||
}
|
||
|
||
/**
|
||
* g_slice_alloc0:
|
||
* @block_size: the number of bytes to allocate
|
||
*
|
||
* Allocates a block of memory via g_slice_alloc() and initializes
|
||
* the returned memory to 0.
|
||
*
|
||
* Since GLib 2.76 this always uses the system malloc() implementation
|
||
* internally.
|
||
*
|
||
* Returns: (nullable): a pointer to the allocated block, which will be %NULL
|
||
* if and only if @mem_size is 0
|
||
*
|
||
* Since: 2.10
|
||
*/
|
||
gpointer
|
||
g_slice_alloc0 (gsize mem_size)
|
||
{
|
||
gpointer mem = g_slice_alloc (mem_size);
|
||
if (mem)
|
||
memset (mem, 0, mem_size);
|
||
return mem;
|
||
}
|
||
|
||
/**
|
||
* g_slice_copy:
|
||
* @block_size: the number of bytes to allocate
|
||
* @mem_block: the memory to copy
|
||
*
|
||
* Allocates a block of memory from the slice allocator
|
||
* and copies @block_size bytes into it from @mem_block.
|
||
*
|
||
* @mem_block must be non-%NULL if @block_size is non-zero.
|
||
*
|
||
* Since GLib 2.76 this always uses the system malloc() implementation
|
||
* internally.
|
||
*
|
||
* Returns: (nullable): a pointer to the allocated memory block,
|
||
* which will be %NULL if and only if @mem_size is 0
|
||
*
|
||
* Since: 2.14
|
||
*/
|
||
gpointer
|
||
g_slice_copy (gsize mem_size,
|
||
gconstpointer mem_block)
|
||
{
|
||
gpointer mem = g_slice_alloc (mem_size);
|
||
if (mem)
|
||
memcpy (mem, mem_block, mem_size);
|
||
return mem;
|
||
}
|
||
|
||
/**
|
||
* g_slice_free1:
|
||
* @block_size: the size of the block
|
||
* @mem_block: (nullable): a pointer to the block to free
|
||
*
|
||
* Frees a block of memory.
|
||
*
|
||
* The memory must have been allocated via g_slice_alloc() or
|
||
* g_slice_alloc0() and the @block_size has to match the size
|
||
* specified upon allocation. Note that the exact release behaviour
|
||
* can be changed with the [`G_DEBUG=gc-friendly`][G_DEBUG] environment
|
||
* variable.
|
||
*
|
||
* If @mem_block is %NULL, this function does nothing.
|
||
*
|
||
* Since GLib 2.76 this always uses the system free_sized() implementation
|
||
* internally.
|
||
*
|
||
* Since: 2.10
|
||
*/
|
||
void
|
||
g_slice_free1 (gsize mem_size,
|
||
gpointer mem_block)
|
||
{
|
||
if (G_UNLIKELY (g_mem_gc_friendly && mem_block))
|
||
memset (mem_block, 0, mem_size);
|
||
g_free_sized (mem_block, mem_size);
|
||
TRACE (GLIB_SLICE_FREE((void*)mem_block, mem_size));
|
||
}
|
||
|
||
/**
|
||
* g_slice_free_chain_with_offset:
|
||
* @block_size: the size of the blocks
|
||
* @mem_chain: (nullable): a pointer to the first block of the chain
|
||
* @next_offset: the offset of the @next field in the blocks
|
||
*
|
||
* Frees a linked list of memory blocks of structure type @type.
|
||
*
|
||
* The memory blocks must be equal-sized, allocated via
|
||
* g_slice_alloc() or g_slice_alloc0() and linked together by a
|
||
* @next pointer (similar to #GSList). The offset of the @next
|
||
* field in each block is passed as third argument.
|
||
* Note that the exact release behaviour can be changed with the
|
||
* [`G_DEBUG=gc-friendly`][G_DEBUG] environment variable.
|
||
*
|
||
* If @mem_chain is %NULL, this function does nothing.
|
||
*
|
||
* Since GLib 2.76 this always uses the system free_sized() implementation
|
||
* internally.
|
||
*
|
||
* Since: 2.10
|
||
*/
|
||
void
|
||
g_slice_free_chain_with_offset (gsize mem_size,
|
||
gpointer mem_chain,
|
||
gsize next_offset)
|
||
{
|
||
gpointer slice = mem_chain;
|
||
while (slice)
|
||
{
|
||
guint8 *current = slice;
|
||
slice = *(gpointer *) (current + next_offset);
|
||
if (G_UNLIKELY (g_mem_gc_friendly))
|
||
memset (current, 0, mem_size);
|
||
g_free_sized (current, mem_size);
|
||
}
|
||
}
|
||
|
||
#ifdef G_ENABLE_DEBUG
|
||
void
|
||
g_slice_debug_tree_statistics (void)
|
||
{
|
||
g_fprintf (stderr, "GSlice: Implementation dropped in GLib 2.76\n");
|
||
}
|
||
#endif /* G_ENABLE_DEBUG */
|