2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3 * <2005> Wim Taymans <wim@fluendo.com>
5 * gstmemchunk.c: implementation of lockfree allocation of fixed
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
23 #include "gst_private.h"
25 #include <string.h> /* memset */
27 #include "gstmemchunk.h"
28 #include "gsttrashstack.h"
31 #include <valgrind/valgrind.h>
34 #define GST_MEM_CHUNK_AREA(chunk) (((GstMemChunkElement*)(chunk))->area)
35 #define GST_MEM_CHUNK_DATA(chunk) ((gpointer)(((GstMemChunkElement*)(chunk)) + 1))
36 #define GST_MEM_CHUNK_LINK(mem) ((GstMemChunkElement*)((guint8*)(mem) - sizeof (GstMemChunkElement)))
38 typedef struct _GstMemChunkElement GstMemChunkElement;
40 struct _GstMemChunkElement
42 GstTrashStackElement elem; /* make sure we can safely push it on the trashstack */
43 gpointer area; /* pointer to data areas */
57 /*******************************************************
59 * +-------------------------------------------------------+
63 * !next!area|data... !next!area!data.... !next!area!data...
65 * +------------------+ +-----------------+ +--------> NULL
69 populate (GstMemChunk * mem_chunk)
74 if (mem_chunk->cleanup)
77 /* FIXME: if we don't do this here and use g_malloc, valgrind crashes */
79 if (__gst_in_valgrind ()) {
80 /* copied from valgrind example */
82 (guint8 *) mmap (0, mem_chunk->area_size,
83 PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANON, -1, 0);
87 area = g_malloc0 (mem_chunk->area_size);
90 for (i = 0; i < mem_chunk->area_size; i += mem_chunk->chunk_size) {
91 GST_MEM_CHUNK_AREA (area + i) = area;
92 gst_trash_stack_push (&mem_chunk->stack, area + i);
100 * @name: the name of the chunk
101 * @atom_size: the size of the allocated atoms
102 * @area_size: the initial size of the memory area
103 * @type: the allocation strategy to use
105 * Creates a new memchunk that will allocate atom_sized memchunks.
106 * The initial area is set to area_size and will grow automatically
107 * when it is too small (with a small overhead when that happens)
109 * Returns: a new #GstMemChunk
114 gst_mem_chunk_new (gchar * name, gint atom_size, gulong area_size, gint type)
116 GstMemChunk *mem_chunk;
118 g_return_val_if_fail (atom_size > 0, NULL);
119 g_return_val_if_fail (area_size >= atom_size, NULL);
121 mem_chunk = g_malloc (sizeof (GstMemChunk));
123 mem_chunk->chunk_size = atom_size + sizeof (GstMemChunkElement);
124 area_size = (area_size / atom_size) * mem_chunk->chunk_size;
126 mem_chunk->name = g_strdup (name);
127 mem_chunk->atom_size = atom_size;
128 mem_chunk->area_size = area_size;
129 mem_chunk->cleanup = FALSE;
130 gst_trash_stack_init (&mem_chunk->stack);
132 populate (mem_chunk);
138 free_area (gpointer key, gpointer value, gpointer user_data)
141 GstMemChunk *chunk = (GstMemChunk *) user_data;
143 if (__gst_in_valgrind ()) {
144 /* copied from valgrind example */
145 munmap (key, chunk->area_size);
156 * gst_mem_chunk_destroy:
157 * @mem_chunk: the GstMemChunk to destroy
159 * Free the memory allocated by the memchunk. This function
160 * is not Threadsafe as it does not wait for all outstanding
161 * allocations to be freed.
164 gst_mem_chunk_destroy (GstMemChunk * mem_chunk)
166 GHashTable *elements = g_hash_table_new (NULL, NULL);
169 mem_chunk->cleanup = TRUE;
171 data = gst_mem_chunk_alloc (mem_chunk);
173 GstMemChunkElement *elem = GST_MEM_CHUNK_LINK (data);
175 g_hash_table_insert (elements, GST_MEM_CHUNK_AREA (elem), NULL);
177 data = gst_mem_chunk_alloc (mem_chunk);
179 g_hash_table_foreach_remove (elements, free_area, mem_chunk);
181 g_hash_table_destroy (elements);
182 g_free (mem_chunk->name);
187 * gst_mem_chunk_alloc:
188 * @mem_chunk: the mem chunk to use
190 * Allocate a new memory region from the chunk. The size
191 * of the allocated memory was specified when the memchunk
194 * Returns: a pointer to the allocated memory region.
199 gst_mem_chunk_alloc (GstMemChunk * mem_chunk)
201 GstMemChunkElement *chunk;
203 g_return_val_if_fail (mem_chunk != NULL, NULL);
206 chunk = gst_trash_stack_pop (&mem_chunk->stack);
207 /* chunk is empty, try to refill */
208 if (G_UNLIKELY (!chunk)) {
209 if (G_LIKELY (populate (mem_chunk))) {
212 /* this happens when we are in cleanup mode and we
213 * allocate all remaining chunks for cleanup */
218 if (G_UNLIKELY (__gst_in_valgrind ())) {
219 VALGRIND_MALLOCLIKE_BLOCK (GST_MEM_CHUNK_DATA (chunk), mem_chunk->atom_size,
223 return GST_MEM_CHUNK_DATA (chunk);
227 * gst_mem_chunk_alloc0:
228 * @mem_chunk: the mem chunk to use
230 * Allocate a new memory region from the chunk. The size
231 * of the allocated memory was specified when the memchunk
232 * was created. The memory will be set to all zeroes.
234 * Returns: a pointer to the allocated memory region.
239 gst_mem_chunk_alloc0 (GstMemChunk * mem_chunk)
241 gpointer mem = gst_mem_chunk_alloc (mem_chunk);
244 memset (mem, 0, mem_chunk->atom_size);
250 * gst_mem_chunk_free:
251 * @mem_chunk: the mem chunk to use
252 * @mem: the memory region to hand back to the chunk
254 * Free the memeory region allocated from the chunk.
259 gst_mem_chunk_free (GstMemChunk * mem_chunk, gpointer mem)
261 GstMemChunkElement *chunk;
263 g_return_if_fail (mem_chunk != NULL);
264 g_return_if_fail (mem != NULL);
266 chunk = GST_MEM_CHUNK_LINK (mem);
269 if (G_UNLIKELY (__gst_in_valgrind ())) {
270 VALGRIND_FREELIKE_BLOCK (mem, 0);
273 gst_trash_stack_push (&mem_chunk->stack, chunk);