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.
26 * @short_description: Atomic chunk allocator
27 * @see_also: #GstBuffer, #GstEvent, #GstData
29 * GstMemChunk is an atomic chunk allocator. It uses atomic operations to
30 * allocate fixed size memory regions and is therefore thread safe without the
31 * overhead of mutexes or other heavyweight locking mechanisms.
33 * The GstMemChunk is used to allocate critical resources for #GstBuffer and
37 #include "gst_private.h"
39 #include <string.h> /* memset */
41 #include "gstmemchunk.h"
42 #include "gsttrashstack.h"
45 #include <valgrind/valgrind.h>
48 #define GST_MEM_CHUNK_AREA(chunk) (((GstMemChunkElement*)(chunk))->area)
49 #define GST_MEM_CHUNK_DATA(chunk) ((gpointer)(((GstMemChunkElement*)(chunk)) + 1))
50 #define GST_MEM_CHUNK_LINK(mem) ((GstMemChunkElement*)((guint8*)(mem) - sizeof (GstMemChunkElement)))
52 typedef struct _GstMemChunkElement GstMemChunkElement;
54 struct _GstMemChunkElement
56 GstTrashStackElement elem; /* make sure we can safely push it on the trashstack */
57 gpointer area; /* pointer to data areas */
71 /*******************************************************
73 * +-------------------------------------------------------+
77 * !next!area|data... !next!area!data.... !next!area!data...
79 * +------------------+ +-----------------+ +--------> NULL
83 populate (GstMemChunk * mem_chunk)
88 if (mem_chunk->cleanup)
91 /* FIXME: if we don't do this here and use g_malloc, valgrind crashes */
93 if (__gst_in_valgrind ()) {
94 /* copied from valgrind example */
96 (guint8 *) mmap (0, mem_chunk->area_size,
97 PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANON, -1, 0);
101 area = g_malloc0 (mem_chunk->area_size);
104 for (i = 0; i < mem_chunk->area_size; i += mem_chunk->chunk_size) {
105 GST_MEM_CHUNK_AREA (area + i) = area;
106 gst_trash_stack_push (&mem_chunk->stack, area + i);
114 * @name: the name of the chunk
115 * @atom_size: the size of the allocated atoms
116 * @area_size: the initial size of the memory area
117 * @type: the allocation strategy to use
119 * Creates a new memchunk that will allocate atom_sized memchunks.
120 * The initial area is set to area_size and will grow automatically
121 * when it is too small (with a small overhead when that happens)
123 * Returns: a new #GstMemChunk
128 gst_mem_chunk_new (gchar * name, guint atom_size, gulong area_size, gint type)
130 GstMemChunk *mem_chunk;
132 g_return_val_if_fail (atom_size > 0, NULL);
133 g_return_val_if_fail (area_size >= atom_size, NULL);
135 mem_chunk = g_malloc (sizeof (GstMemChunk));
137 mem_chunk->chunk_size = atom_size + sizeof (GstMemChunkElement);
138 area_size = (area_size / atom_size) * mem_chunk->chunk_size;
140 mem_chunk->name = g_strdup (name);
141 mem_chunk->atom_size = atom_size;
142 mem_chunk->area_size = area_size;
143 mem_chunk->cleanup = FALSE;
144 gst_trash_stack_init (&mem_chunk->stack);
146 populate (mem_chunk);
152 free_area (gpointer key, gpointer value, gpointer user_data)
155 GstMemChunk *chunk = (GstMemChunk *) user_data;
157 if (__gst_in_valgrind ()) {
158 /* copied from valgrind example */
159 munmap (key, chunk->area_size);
170 * gst_mem_chunk_destroy:
171 * @mem_chunk: the GstMemChunk to destroy
173 * Free the memory allocated by the memchunk. This function
174 * is not Threadsafe as it does not wait for all outstanding
175 * allocations to be freed.
178 gst_mem_chunk_destroy (GstMemChunk * mem_chunk)
180 GHashTable *elements = g_hash_table_new (NULL, NULL);
183 mem_chunk->cleanup = TRUE;
185 data = gst_mem_chunk_alloc (mem_chunk);
187 GstMemChunkElement *elem = GST_MEM_CHUNK_LINK (data);
189 g_hash_table_insert (elements, GST_MEM_CHUNK_AREA (elem), NULL);
191 data = gst_mem_chunk_alloc (mem_chunk);
193 g_hash_table_foreach_remove (elements, free_area, mem_chunk);
195 g_hash_table_destroy (elements);
196 g_free (mem_chunk->name);
201 * gst_mem_chunk_alloc:
202 * @mem_chunk: the mem chunk to use
204 * Allocate a new memory region from the chunk. The size
205 * of the allocated memory was specified when the memchunk
208 * Returns: a pointer to the allocated memory region.
213 gst_mem_chunk_alloc (GstMemChunk * mem_chunk)
215 GstMemChunkElement *chunk;
217 g_return_val_if_fail (mem_chunk != NULL, NULL);
220 chunk = gst_trash_stack_pop (&mem_chunk->stack);
221 /* chunk is empty, try to refill */
222 if (G_UNLIKELY (!chunk)) {
223 if (G_LIKELY (populate (mem_chunk))) {
226 /* this happens when we are in cleanup mode and we
227 * allocate all remaining chunks for cleanup */
232 if (G_UNLIKELY (__gst_in_valgrind ())) {
233 VALGRIND_MALLOCLIKE_BLOCK (GST_MEM_CHUNK_DATA (chunk), mem_chunk->atom_size,
237 return GST_MEM_CHUNK_DATA (chunk);
241 * gst_mem_chunk_alloc0:
242 * @mem_chunk: the mem chunk to use
244 * Allocate a new memory region from the chunk. The size
245 * of the allocated memory was specified when the memchunk
246 * was created. The memory will be set to all zeroes.
248 * Returns: a pointer to the allocated memory region.
253 gst_mem_chunk_alloc0 (GstMemChunk * mem_chunk)
255 gpointer mem = gst_mem_chunk_alloc (mem_chunk);
258 memset (mem, 0, mem_chunk->atom_size);
264 * gst_mem_chunk_free:
265 * @mem_chunk: the mem chunk to use
266 * @mem: the memory region to hand back to the chunk
268 * Free the memeory region allocated from the chunk.
273 gst_mem_chunk_free (GstMemChunk * mem_chunk, gpointer mem)
275 GstMemChunkElement *chunk;
277 g_return_if_fail (mem_chunk != NULL);
278 g_return_if_fail (mem != NULL);
280 chunk = GST_MEM_CHUNK_LINK (mem);
283 if (G_UNLIKELY (__gst_in_valgrind ())) {
284 VALGRIND_FREELIKE_BLOCK (mem, 0);
287 gst_trash_stack_push (&mem_chunk->stack, chunk);