X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=glib%2Fgslice.c;h=0563d8092dd173d3907dcea8f46d41243da9b211;hb=7e3d32b7053b47ca7feecf185abac96b619770c2;hp=396ce48af30fd44731eb321a767c0cddf4cce3c0;hpb=45f221c32f7c88e487fe260eefb3be8d1c2443af;p=platform%2Fupstream%2Fglib.git diff --git a/glib/gslice.c b/glib/gslice.c index 396ce48..0563d80 100644 --- a/glib/gslice.c +++ b/glib/gslice.c @@ -12,9 +12,7 @@ * 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, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * License along with this library; if not, see . */ /* MT safe */ @@ -32,7 +30,7 @@ #include #include -#ifdef HAVE_UNISTD_H +#ifdef G_OS_UNIX #include /* sysconf() */ #endif #ifdef G_OS_WIN32 @@ -53,6 +51,87 @@ #include "gthread.h" #include "glib_trace.h" +#include "valgrind.h" + +/** + * SECTION:memory_slices + * @title: Memory Slices + * @short_description: efficient way to allocate groups of equal-sized + * chunks of memory + * + * Memory slices provide a space-efficient and multi-processing scalable + * way to allocate equal-sized pieces of memory, just like the original + * #GMemChunks (from GLib 2.8), while avoiding their excessive + * memory-waste, scalability and performance problems. + * + * To achieve these goals, the slice allocator uses a sophisticated, + * layered design that has been inspired by Bonwick's slab allocator + * ([Bonwick94](http://citeseer.ist.psu.edu/bonwick94slab.html) + * Jeff Bonwick, The slab allocator: An object-caching kernel + * memory allocator. USENIX 1994, and + * [Bonwick01](http://citeseer.ist.psu.edu/bonwick01magazines.html) + * Bonwick and Jonathan Adams, Magazines and vmem: Extending the + * slab allocator to many cpu's and arbitrary resources. USENIX 2001) + * + * It uses posix_memalign() to optimize allocations of many equally-sized + * chunks, and has per-thread free lists (the so-called magazine layer) + * to quickly satisfy allocation requests of already known structure sizes. + * This is accompanied by extra caching logic to keep freed memory around + * for some time before returning it to the system. Memory that is unused + * due to alignment constraints is used for cache colorization (random + * distribution of chunk addresses) to improve CPU cache utilization. The + * caching layer of the slice allocator adapts itself to high lock contention + * to improve scalability. + * + * The slice allocator can allocate blocks as small as two pointers, and + * unlike malloc(), it does not reserve extra space per block. For large block + * sizes, g_slice_new() and g_slice_alloc() will automatically delegate to the + * system malloc() implementation. For newly written code it is recommended + * to use the new `g_slice` API instead of g_malloc() and + * friends, as long as objects are not resized during their lifetime and the + * object size used at allocation time is still available when freeing. + * + * Here is an example for using the slice allocator: + * |[ + * 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: + * |[ + * 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); + * ]| + */ + /* the GSlice allocator is split up into 4 layers, roughly modelled after the slab * allocator and magazine extensions as outlined in: * + [Bonwick94] Jeff Bonwick, The slab allocator: An object-caching kernel @@ -279,40 +358,39 @@ g_slice_get_config_state (GSliceConfig ckey, } } -static const gchar * -getenv_nomalloc (const gchar *variable, - gchar buffer[1024]) -{ - const gchar *retval = getenv (variable); - if (retval && retval[0]) - { - gint l = strlen (retval); - if (l < 1024) - { - strncpy (buffer, retval, l); - buffer[l] = 0; - return buffer; - } - } - return NULL; -} - static void slice_config_init (SliceConfig *config) { - /* don't use g_malloc/g_message here */ - gchar buffer[1024]; - const gchar *val = getenv_nomalloc ("G_SLICE", buffer); - const GDebugKey keys[] = { - { "always-malloc", 1 << 0 }, - { "debug-blocks", 1 << 1 }, - }; - gint flags = !val ? 0 : g_parse_debug_string (val, keys, G_N_ELEMENTS (keys)); + const gchar *val; + *config = slice_config; - if (flags & (1 << 0)) /* always-malloc */ - config->always_malloc = TRUE; - if (flags & (1 << 1)) /* debug-blocks */ - config->debug_blocks = TRUE; + + val = getenv ("G_SLICE"); + if (val != NULL) + { + gint flags; + const GDebugKey keys[] = { + { "always-malloc", 1 << 0 }, + { "debug-blocks", 1 << 1 }, + }; + + flags = g_parse_debug_string (val, keys, G_N_ELEMENTS (keys)); + if (flags & (1 << 0)) + config->always_malloc = TRUE; + if (flags & (1 << 1)) + config->debug_blocks = TRUE; + } + else + { + /* G_SLICE was not specified, so check if valgrind is running and + * disable ourselves if it is. + * + * This way it's possible to force gslice to be enabled under + * valgrind just by setting G_SLICE to the empty string. + */ + if (RUNNING_ON_VALGRIND) + config->always_malloc = TRUE; + } } static void @@ -341,7 +419,7 @@ g_slice_init_nomessage (void) * fit less than 8 times (see [4]) into 4KB pages. * we allow very small page sizes here, to reduce wastage in * threads if only small allocations are required (this does - * bear the risk of incresing allocation times and fragmentation + * bear the risk of increasing allocation times and fragmentation * though). */ allocator->min_page_size = MAX (allocator->min_page_size, 4096); @@ -364,11 +442,9 @@ g_slice_init_nomessage (void) allocator->slab_stack = g_new0 (SlabInfo*, MAX_SLAB_INDEX (allocator)); } - g_mutex_init (&allocator->magazine_mutex); allocator->mutex_counter = 0; allocator->stamp_counter = MAX_STAMP_COUNTER; /* force initial update */ allocator->last_stamp = 0; - g_mutex_init (&allocator->slab_mutex); allocator->color_accu = 0; magazine_cache_update_stamp(); /* values cached for performance reasons */ @@ -783,6 +859,115 @@ thread_memory_magazine2_free (ThreadMemory *tmem, } /* --- 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. Note that the underlying slice allocation + * mechanism can be changed with the [`G_SLICE=always-malloc`][G_SLICE] + * environment variable. + * + * Returns: 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. + * Note that the underlying slice allocation mechanism can + * be changed with the [`G_SLICE=always-malloc`][G_SLICE] + * environment variable. + * + * Since: 2.10 + */ + +/** + * g_slice_dup: + * @type: the type to duplicate, typically a structure name + * @mem: 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. + * Note that the underlying slice allocation mechanism can + * be changed with the [`G_SLICE=always-malloc`][G_SLICE] + * environment variable. + * + * Returns: 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: 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, also see + * [`G_SLICE`][G_SLICE] for related debugging options. + * + * Since: 2.10 + */ + +/** + * g_slice_free_chain: + * @type: the type of the @mem_chain blocks + * @mem_chain: 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, also see + * [`G_SLICE`][G_SLICE] for related debugging options. + * + * Since: 2.10 + */ + +/** + * g_slice_alloc: + * @block_size: the number of bytes to allocate + * + * Allocates a block of memory from the slice allocator. + * The block adress handed out can be expected to be aligned + * to at least 1 * sizeof (void*), + * though in general slices are 2 * sizeof (void*) bytes aligned, + * if a malloc() fallback implementation is used instead, + * the alignment may be reduced in a libc dependent fashion. + * Note that the underlying slice allocation mechanism can + * be changed with the [`G_SLICE=always-malloc`][G_SLICE] + * environment variable. + * + * Returns: a pointer to the allocated memory block + * + * Since: 2.10 + */ gpointer g_slice_alloc (gsize mem_size) { @@ -828,6 +1013,19 @@ g_slice_alloc (gsize 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. Note that the underlying slice allocation + * mechanism can be changed with the [`G_SLICE=always-malloc`][G_SLICE] + * environment variable. + * + * Returns: a pointer to the allocated block + * + * Since: 2.10 + */ gpointer g_slice_alloc0 (gsize mem_size) { @@ -837,6 +1035,18 @@ g_slice_alloc0 (gsize 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. + * + * Returns: a pointer to the allocated memory block + * + * Since: 2.14 + */ gpointer g_slice_copy (gsize mem_size, gconstpointer mem_block) @@ -847,6 +1057,21 @@ g_slice_copy (gsize mem_size, return mem; } +/** + * g_slice_free1: + * @block_size: the size of the block + * @mem_block: 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, also see [`G_SLICE`][G_SLICE] for related debugging options. + * + * Since: 2.10 + */ void g_slice_free1 (gsize mem_size, gpointer mem_block) @@ -889,6 +1114,24 @@ g_slice_free1 (gsize 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: 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, also see + * [`G_SLICE`][G_SLICE] for related debugging options. + * + * Since: 2.10 + */ void g_slice_free_chain_with_offset (gsize mem_size, gpointer mem_chain, @@ -1011,10 +1254,7 @@ allocator_add_slab (Allocator *allocator, guint i; if (!mem) { - const gchar *syserr = "unknown error"; -#if HAVE_STRERROR - syserr = strerror (errno); -#endif + const gchar *syserr = strerror (errno); mem_error ("failed to allocate %u bytes (alignment: %u): %s\n", (guint) (page_size - NATIVE_MALLOC_PADDING), (guint) page_size, syserr); } @@ -1266,7 +1506,7 @@ smc_notify_free (void *pointer, /* --- g-slice memory checker tree implementation --- */ #define SMC_TRUNK_COUNT (4093 /* 16381 */) /* prime, to distribute trunk collisions (big, allocated just once) */ #define SMC_BRANCH_COUNT (511) /* prime, to distribute branch collisions */ -#define SMC_TRUNK_EXTENT (SMC_BRANCH_COUNT * 2039) /* key adress space per trunk, should distribute uniformly across BRANCH_COUNT */ +#define SMC_TRUNK_EXTENT (SMC_BRANCH_COUNT * 2039) /* key address space per trunk, should distribute uniformly across BRANCH_COUNT */ #define SMC_TRUNK_HASH(k) ((k / SMC_TRUNK_EXTENT) % SMC_TRUNK_COUNT) /* generate new trunk hash per megabyte (roughly) */ #define SMC_BRANCH_HASH(k) (k % SMC_BRANCH_COUNT) @@ -1280,10 +1520,7 @@ static SmcBranch **smc_tree_root = NULL; static void smc_tree_abort (int errval) { - const char *syserr = "unknown error"; -#if HAVE_STRERROR - syserr = strerror (errval); -#endif + const char *syserr = strerror (errval); mem_error ("MemChecker: failure in debugging tree: %s", syserr); } @@ -1299,7 +1536,7 @@ smc_tree_branch_grow_L (SmcBranch *branch, if (!branch->entries) smc_tree_abort (errno); entry = branch->entries + index; - g_memmove (entry + 1, entry, (branch->n_entries - index) * sizeof (entry[0])); + memmove (entry + 1, entry, (branch->n_entries - index) * sizeof (entry[0])); branch->n_entries += 1; return entry; } @@ -1398,7 +1635,7 @@ smc_tree_remove (SmcKType key) { unsigned int i = entry - smc_tree_root[ix0][ix1].entries; smc_tree_root[ix0][ix1].n_entries -= 1; - g_memmove (entry, entry + 1, (smc_tree_root[ix0][ix1].n_entries - i) * sizeof (entry[0])); + memmove (entry, entry + 1, (smc_tree_root[ix0][ix1].n_entries - i) * sizeof (entry[0])); if (!smc_tree_root[ix0][ix1].n_entries) { /* avoid useless pressure on the memory system */