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.
25 * @short_description: Atomic chunk allocator
26 * @see_also: #GstBuffer, #GstEvent, #GstData
28 * GstMemChunk is an atomic chunk allocator. It uses atomic operations to
29 * allocate fixed size memory regions and is therefore thread safe without the
30 * overhead of mutexes or other heavyweight locking mechanisms.
32 * The GstMemChunk is used to allocate critical resources for #GstBuffer and
35 #include "gst_private.h"
37 #include <string.h> /* memset */
39 #include "gstmemchunk.h"
40 #include "gsttrashstack.h"
43 #include <valgrind/valgrind.h>
46 #define GST_MEM_CHUNK_AREA(chunk) (((GstMemChunkElement*)(chunk))->area)
47 #define GST_MEM_CHUNK_DATA(chunk) ((gpointer)(((GstMemChunkElement*)(chunk)) + 1))
48 #define GST_MEM_CHUNK_LINK(mem) ((GstMemChunkElement*)((guint8*)(mem) - sizeof (GstMemChunkElement)))
50 typedef struct _GstMemChunkElement GstMemChunkElement;
52 struct _GstMemChunkElement
54 GstTrashStackElement elem; /* make sure we can safely push it on the trashstack */
55 gpointer area; /* pointer to data areas */
69 /*******************************************************
71 * +-------------------------------------------------------+
75 * !next!area|data... !next!area!data.... !next!area!data...
77 * +------------------+ +-----------------+ +--------> NULL
81 populate (GstMemChunk * mem_chunk)
86 if (mem_chunk->cleanup)
89 /* FIXME: if we don't do this here and use g_malloc, valgrind crashes */
91 if (__gst_in_valgrind ()) {
92 /* copied from valgrind example */
94 (guint8 *) mmap (0, mem_chunk->area_size,
95 PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANON, -1, 0);
99 area = g_malloc0 (mem_chunk->area_size);
102 for (i = 0; i < mem_chunk->area_size; i += mem_chunk->chunk_size) {
103 GST_MEM_CHUNK_AREA (area + i) = area;
104 gst_trash_stack_push (&mem_chunk->stack, area + i);
112 * @name: the name of the chunk
113 * @atom_size: the size of the allocated atoms
114 * @area_size: the initial size of the memory area
115 * @type: the allocation strategy to use
117 * Creates a new memchunk that will allocate atom_sized memchunks.
118 * The initial area is set to area_size and will grow automatically
119 * when it is too small (with a small overhead when that happens)
121 * Returns: a new #GstMemChunk
126 gst_mem_chunk_new (gchar * name, gint atom_size, gulong area_size, gint type)
128 GstMemChunk *mem_chunk;
130 g_return_val_if_fail (atom_size > 0, NULL);
131 g_return_val_if_fail (area_size >= atom_size, NULL);
133 mem_chunk = g_malloc (sizeof (GstMemChunk));
135 mem_chunk->chunk_size = atom_size + sizeof (GstMemChunkElement);
136 area_size = (area_size / atom_size) * mem_chunk->chunk_size;
138 mem_chunk->name = g_strdup (name);
139 mem_chunk->atom_size = atom_size;
140 mem_chunk->area_size = area_size;
141 mem_chunk->cleanup = FALSE;
142 gst_trash_stack_init (&mem_chunk->stack);
144 populate (mem_chunk);
150 free_area (gpointer key, gpointer value, gpointer user_data)
153 GstMemChunk *chunk = (GstMemChunk *) user_data;
155 if (__gst_in_valgrind ()) {
156 /* copied from valgrind example */
157 munmap (key, chunk->area_size);
168 * gst_mem_chunk_destroy:
169 * @mem_chunk: the GstMemChunk to destroy
171 * Free the memory allocated by the memchunk. This function
172 * is not Threadsafe as it does not wait for all outstanding
173 * allocations to be freed.
176 gst_mem_chunk_destroy (GstMemChunk * mem_chunk)
178 GHashTable *elements = g_hash_table_new (NULL, NULL);
181 mem_chunk->cleanup = TRUE;
183 data = gst_mem_chunk_alloc (mem_chunk);
185 GstMemChunkElement *elem = GST_MEM_CHUNK_LINK (data);
187 g_hash_table_insert (elements, GST_MEM_CHUNK_AREA (elem), NULL);
189 data = gst_mem_chunk_alloc (mem_chunk);
191 g_hash_table_foreach_remove (elements, free_area, mem_chunk);
193 g_hash_table_destroy (elements);
194 g_free (mem_chunk->name);
199 * gst_mem_chunk_alloc:
200 * @mem_chunk: the mem chunk to use
202 * Allocate a new memory region from the chunk. The size
203 * of the allocated memory was specified when the memchunk
206 * Returns: a pointer to the allocated memory region.
211 gst_mem_chunk_alloc (GstMemChunk * mem_chunk)
213 GstMemChunkElement *chunk;
215 g_return_val_if_fail (mem_chunk != NULL, NULL);
218 chunk = gst_trash_stack_pop (&mem_chunk->stack);
219 /* chunk is empty, try to refill */
220 if (G_UNLIKELY (!chunk)) {
221 if (G_LIKELY (populate (mem_chunk))) {
224 /* this happens when we are in cleanup mode and we
225 * allocate all remaining chunks for cleanup */
230 if (G_UNLIKELY (__gst_in_valgrind ())) {
231 VALGRIND_MALLOCLIKE_BLOCK (GST_MEM_CHUNK_DATA (chunk), mem_chunk->atom_size,
235 return GST_MEM_CHUNK_DATA (chunk);
239 * gst_mem_chunk_alloc0:
240 * @mem_chunk: the mem chunk to use
242 * Allocate a new memory region from the chunk. The size
243 * of the allocated memory was specified when the memchunk
244 * was created. The memory will be set to all zeroes.
246 * Returns: a pointer to the allocated memory region.
251 gst_mem_chunk_alloc0 (GstMemChunk * mem_chunk)
253 gpointer mem = gst_mem_chunk_alloc (mem_chunk);
256 memset (mem, 0, mem_chunk->atom_size);
262 * gst_mem_chunk_free:
263 * @mem_chunk: the mem chunk to use
264 * @mem: the memory region to hand back to the chunk
266 * Free the memeory region allocated from the chunk.
271 gst_mem_chunk_free (GstMemChunk * mem_chunk, gpointer mem)
273 GstMemChunkElement *chunk;
275 g_return_if_fail (mem_chunk != NULL);
276 g_return_if_fail (mem != NULL);
278 chunk = GST_MEM_CHUNK_LINK (mem);
281 if (G_UNLIKELY (__gst_in_valgrind ())) {
282 VALGRIND_FREELIKE_BLOCK (mem, 0);
285 gst_trash_stack_push (&mem_chunk->stack, chunk);