source: trunk/third/gstreamer/gst/gstmemchunk.c @ 21005

Revision 21005, 6.4 KB checked in by ghudson, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r21004, which included commits to RCS files with non-trunk default branches.
Line 
1/* GStreamer
2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 */
19#include "gst_private.h"
20
21#include <string.h>             /* memset */
22
23#include "gstutils.h"
24#include "gstmemchunk.h"
25#include "gsttrashstack.h"
26#ifdef HAVE_VALGRIND
27#include <sys/mman.h>
28#include <valgrind/valgrind.h>
29#endif
30
31
32#define GST_MEM_CHUNK_AREA(chunk)       (((GstMemChunkElement*)(chunk))->area)
33#define GST_MEM_CHUNK_DATA(chunk)       ((gpointer)(((GstMemChunkElement*)(chunk)) + 1))
34#define GST_MEM_CHUNK_LINK(mem)         ((GstMemChunkElement*)((guint8*)(mem) - sizeof (GstMemChunkElement)))
35
36typedef struct _GstMemChunkElement GstMemChunkElement;
37
38struct _GstMemChunkElement
39{
40  GstTrashStackElement elem;    /* make sure we can safely push it on the trashstack */
41  gpointer area;                /* pointer to data areas */
42};
43
44struct _GstMemChunk
45{
46  GstTrashStack stack;
47
48  gchar *name;
49  gulong area_size;
50  gulong chunk_size;
51  gulong atom_size;
52  gboolean cleanup;
53};
54
55/*******************************************************
56 *         area size
57 * +-------------------------------------------------------+
58 *   chunk size
59 * +-----------------+
60 *
61 * !next!area|data... !next!area!data.... !next!area!data...
62 *  !                  ^ !                 ^ !
63 *  +------------------+ +-----------------+ +--------> NULL
64 *
65 */
66static gboolean
67populate (GstMemChunk * mem_chunk)
68{
69  guint8 *area;
70  gint i;
71
72  if (mem_chunk->cleanup)
73    return FALSE;
74
75  /* FIXME: if we don't do this here and use g_malloc, valgrind crashes */
76#if HAVE_VALGRIND
77  if (__gst_in_valgrind ()) {
78    /* copied from valgrind example */
79    area =
80        (guint8 *) mmap (0, mem_chunk->area_size,
81        PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANON, -1, 0);
82  } else
83#endif
84  {
85    area = g_malloc0 (mem_chunk->area_size);
86  }
87
88  for (i = 0; i < mem_chunk->area_size; i += mem_chunk->chunk_size) {
89    GST_MEM_CHUNK_AREA (area + i) = area;
90    gst_trash_stack_push (&mem_chunk->stack, area + i);
91  }
92
93  return TRUE;
94}
95
96/**
97 * gst_mem_chunk_new:
98 * @name: the name of the chunk
99 * @atom_size: the size of the allocated atoms
100 * @area_size: the initial size of the memory area
101 * @type: the allocation strategy to use
102 *
103 * Creates a new memchunk that will allocate atom_sized memchunks.
104 * The initial area is set to area_size and will grow automatically
105 * when it is too small (with a small overhead when that happens)
106 *
107 * Returns: a new #GstMemChunk
108 */
109GstMemChunk *
110gst_mem_chunk_new (gchar * name, gint atom_size, gulong area_size, gint type)
111{
112  GstMemChunk *mem_chunk;
113
114  g_return_val_if_fail (atom_size > 0, NULL);
115  g_return_val_if_fail (area_size >= atom_size, NULL);
116
117  mem_chunk = g_malloc (sizeof (GstMemChunk));
118
119  mem_chunk->chunk_size = atom_size + sizeof (GstMemChunkElement);
120  area_size = (area_size / atom_size) * mem_chunk->chunk_size;
121
122  mem_chunk->name = g_strdup (name);
123  mem_chunk->atom_size = atom_size;
124  mem_chunk->area_size = area_size;
125  mem_chunk->cleanup = FALSE;
126  gst_trash_stack_init (&mem_chunk->stack);
127
128  populate (mem_chunk);
129
130  return mem_chunk;
131}
132
133static gboolean
134free_area (gpointer key, gpointer value, gpointer user_data)
135{
136#if HAVE_VALGRIND
137  GstMemChunk *chunk = (GstMemChunk *) user_data;
138
139  if (__gst_in_valgrind ()) {
140    /* copied from valgrind example */
141    munmap (key, chunk->area_size);
142  } else
143#endif
144  {
145    g_free (key);
146  }
147
148  return TRUE;
149}
150
151/**
152 * gst_mem_chunk_destroy:
153 * @mem_chunk: the GstMemChunk to destroy
154 *
155 * Free the memory allocated by the memchunk
156 */
157void
158gst_mem_chunk_destroy (GstMemChunk * mem_chunk)
159{
160  GHashTable *elements = g_hash_table_new (NULL, NULL);
161  gpointer data;
162
163  mem_chunk->cleanup = TRUE;
164
165  data = gst_mem_chunk_alloc (mem_chunk);
166  while (data) {
167    GstMemChunkElement *elem = GST_MEM_CHUNK_LINK (data);
168
169    g_hash_table_insert (elements, GST_MEM_CHUNK_AREA (elem), NULL);
170
171    data = gst_mem_chunk_alloc (mem_chunk);
172  }
173  g_hash_table_foreach_remove (elements, free_area, mem_chunk);
174
175  g_hash_table_destroy (elements);
176  g_free (mem_chunk->name);
177  g_free (mem_chunk);
178}
179
180/**
181 * gst_mem_chunk_alloc:
182 * @mem_chunk: the mem chunk to use
183 *
184 * Allocate a new memory region from the chunk. The size
185 * of the allocated memory was specified when the memchunk
186 * was created.
187 *
188 * Returns: a pointer to the allocated memory region.
189 */
190gpointer
191gst_mem_chunk_alloc (GstMemChunk * mem_chunk)
192{
193  GstMemChunkElement *chunk;
194
195  g_return_val_if_fail (mem_chunk != NULL, NULL);
196
197again:
198  chunk = gst_trash_stack_pop (&mem_chunk->stack);
199  /* chunk is empty, try to refill */
200  if (!chunk) {
201    if (populate (mem_chunk))
202      goto again;
203    else
204      return NULL;
205  }
206#ifdef HAVE_VALGRIND
207  VALGRIND_MALLOCLIKE_BLOCK (GST_MEM_CHUNK_DATA (chunk), mem_chunk->atom_size,
208      0, 0);
209#endif
210  return GST_MEM_CHUNK_DATA (chunk);
211}
212
213/**
214 * gst_mem_chunk_alloc0:
215 * @mem_chunk: the mem chunk to use
216 *
217 * Allocate a new memory region from the chunk. The size
218 * of the allocated memory was specified when the memchunk
219 * was created. The memory will be set to all zeroes.
220 *
221 * Returns: a pointer to the allocated memory region.
222 */
223gpointer
224gst_mem_chunk_alloc0 (GstMemChunk * mem_chunk)
225{
226  gpointer mem = gst_mem_chunk_alloc (mem_chunk);
227
228  if (mem)
229    memset (mem, 0, mem_chunk->atom_size);
230
231  return mem;
232}
233
234/**
235 * gst_mem_chunk_free:
236 * @mem_chunk: the mem chunk to use
237 * @mem: the memory region to hand back to the chunk
238 *
239 * Free the memeory region allocated from the chunk.
240 */
241void
242gst_mem_chunk_free (GstMemChunk * mem_chunk, gpointer mem)
243{
244  GstMemChunkElement *chunk;
245
246  g_return_if_fail (mem_chunk != NULL);
247  g_return_if_fail (mem != NULL);
248
249  chunk = GST_MEM_CHUNK_LINK (mem);
250
251#ifdef HAVE_VALGRIND
252  VALGRIND_FREELIKE_BLOCK (mem, 0);
253#endif
254  gst_trash_stack_push (&mem_chunk->stack, chunk);
255}
Note: See TracBrowser for help on using the repository browser.