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 */
28 #include "gstmemchunk.h"
29 #include "gsttrashstack.h"
32 #include <valgrind/valgrind.h>
35 #define GST_MEM_CHUNK_AREA(chunk) (((GstMemChunkElement*)(chunk))->area)
36 #define GST_MEM_CHUNK_DATA(chunk) ((gpointer)(((GstMemChunkElement*)(chunk)) + 1))
37 #define GST_MEM_CHUNK_LINK(mem) ((GstMemChunkElement*)((guint8*)(mem) - sizeof (GstMemChunkElement)))
39 typedef struct _GstMemChunkElement GstMemChunkElement;
41 struct _GstMemChunkElement
43 GstTrashStackElement elem; /* make sure we can safely push it on the trashstack */
44 gpointer area; /* pointer to data areas */
58 /*******************************************************
60 * +-------------------------------------------------------+
64 * !next!area|data... !next!area!data.... !next!area!data...
66 * +------------------+ +-----------------+ +--------> NULL
70 populate (GstMemChunk * mem_chunk)
75 if (mem_chunk->cleanup)
78 /* FIXME: if we don't do this here and use g_malloc, valgrind crashes */
80 if (__gst_in_valgrind ()) {
81 /* copied from valgrind example */
83 (guint8 *) mmap (0, mem_chunk->area_size,
84 PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANON, -1, 0);
88 area = g_malloc0 (mem_chunk->area_size);
91 for (i = 0; i < mem_chunk->area_size; i += mem_chunk->chunk_size) {
92 GST_MEM_CHUNK_AREA (area + i) = area;
93 gst_trash_stack_push (&mem_chunk->stack, area + i);
101 * @name: the name of the chunk
102 * @atom_size: the size of the allocated atoms
103 * @area_size: the initial size of the memory area
104 * @type: the allocation strategy to use
106 * Creates a new memchunk that will allocate atom_sized memchunks.
107 * The initial area is set to area_size and will grow automatically
108 * when it is too small (with a small overhead when that happens)
110 * Returns: a new #GstMemChunk
115 gst_mem_chunk_new (gchar * name, gint atom_size, gulong area_size, gint type)
117 GstMemChunk *mem_chunk;
119 g_return_val_if_fail (atom_size > 0, NULL);
120 g_return_val_if_fail (area_size >= atom_size, NULL);
122 mem_chunk = g_malloc (sizeof (GstMemChunk));
124 mem_chunk->chunk_size = atom_size + sizeof (GstMemChunkElement);
125 area_size = (area_size / atom_size) * mem_chunk->chunk_size;
127 mem_chunk->name = g_strdup (name);
128 mem_chunk->atom_size = atom_size;
129 mem_chunk->area_size = area_size;
130 mem_chunk->cleanup = FALSE;
131 gst_trash_stack_init (&mem_chunk->stack);
133 populate (mem_chunk);
139 free_area (gpointer key, gpointer value, gpointer user_data)
142 GstMemChunk *chunk = (GstMemChunk *) user_data;
144 if (__gst_in_valgrind ()) {
145 /* copied from valgrind example */
146 munmap (key, chunk->area_size);
157 * gst_mem_chunk_destroy:
158 * @mem_chunk: the GstMemChunk to destroy
160 * Free the memory allocated by the memchunk. This function
161 * is not Threadsafe as it does not wait for all outstanding
162 * allocations to be freed.
165 gst_mem_chunk_destroy (GstMemChunk * mem_chunk)
167 GHashTable *elements = g_hash_table_new (NULL, NULL);
170 mem_chunk->cleanup = TRUE;
172 data = gst_mem_chunk_alloc (mem_chunk);
174 GstMemChunkElement *elem = GST_MEM_CHUNK_LINK (data);
176 g_hash_table_insert (elements, GST_MEM_CHUNK_AREA (elem), NULL);
178 data = gst_mem_chunk_alloc (mem_chunk);
180 g_hash_table_foreach_remove (elements, free_area, mem_chunk);
182 g_hash_table_destroy (elements);
183 g_free (mem_chunk->name);
188 * gst_mem_chunk_alloc:
189 * @mem_chunk: the mem chunk to use
191 * Allocate a new memory region from the chunk. The size
192 * of the allocated memory was specified when the memchunk
195 * Returns: a pointer to the allocated memory region.
200 gst_mem_chunk_alloc (GstMemChunk * mem_chunk)
202 GstMemChunkElement *chunk;
204 g_return_val_if_fail (mem_chunk != NULL, NULL);
207 chunk = gst_trash_stack_pop (&mem_chunk->stack);
208 /* chunk is empty, try to refill */
209 if (G_UNLIKELY (!chunk)) {
210 if (G_LIKELY (populate (mem_chunk))) {
213 /* this happens when we are in cleanup mode and we
214 * allocate all remaining chunks for cleanup */
219 if (G_UNLIKELY (__gst_in_valgrind ())) {
220 VALGRIND_MALLOCLIKE_BLOCK (GST_MEM_CHUNK_DATA (chunk), mem_chunk->atom_size,
224 return GST_MEM_CHUNK_DATA (chunk);
228 * gst_mem_chunk_alloc0:
229 * @mem_chunk: the mem chunk to use
231 * Allocate a new memory region from the chunk. The size
232 * of the allocated memory was specified when the memchunk
233 * was created. The memory will be set to all zeroes.
235 * Returns: a pointer to the allocated memory region.
240 gst_mem_chunk_alloc0 (GstMemChunk * mem_chunk)
242 gpointer mem = gst_mem_chunk_alloc (mem_chunk);
245 memset (mem, 0, mem_chunk->atom_size);
251 * gst_mem_chunk_free:
252 * @mem_chunk: the mem chunk to use
253 * @mem: the memory region to hand back to the chunk
255 * Free the memeory region allocated from the chunk.
260 gst_mem_chunk_free (GstMemChunk * mem_chunk, gpointer mem)
262 GstMemChunkElement *chunk;
264 g_return_if_fail (mem_chunk != NULL);
265 g_return_if_fail (mem != NULL);
267 chunk = GST_MEM_CHUNK_LINK (mem);
270 if (G_UNLIKELY (__gst_in_valgrind ())) {
271 VALGRIND_FREELIKE_BLOCK (mem, 0);
274 gst_trash_stack_push (&mem_chunk->stack, chunk);