mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-16 13:26:36 +00:00
163 lines
3.6 KiB
C
163 lines
3.6 KiB
C
|
#include "gstmemchunk.h"
|
||
|
|
||
|
#ifdef __SMP__
|
||
|
#define CHUNK_LOCK "lock ; "
|
||
|
#else
|
||
|
#define CHUNK_LOCK ""
|
||
|
#endif
|
||
|
|
||
|
#define GST_MEM_CHUNK_AREA(chunk) (((GstMemChunkElement*)(chunk))->area)
|
||
|
#define GST_MEM_CHUNK_DATA(chunk) ((gpointer)(((GstMemChunkElement*)(chunk)) + 1))
|
||
|
#define GST_MEM_CHUNK_LINK(mem) ((GstMemChunkElement*)((guint8*)(mem) - sizeof (GstMemChunkElement)))
|
||
|
|
||
|
/*******************************************************
|
||
|
* area size
|
||
|
* +-----------------------------------------+
|
||
|
* chunk size
|
||
|
* +------------+
|
||
|
*
|
||
|
* !next!data... !next!data.... !next!data...
|
||
|
* ! ^ ! ^ !
|
||
|
* +-------------+ +------------+ +---> NULL
|
||
|
*
|
||
|
*/
|
||
|
static gboolean
|
||
|
populate (GstMemChunk *mem_chunk)
|
||
|
{
|
||
|
guint8 *area;
|
||
|
gint i;
|
||
|
|
||
|
if (mem_chunk->cleanup)
|
||
|
return FALSE;
|
||
|
|
||
|
area = (guint8 *) g_malloc (mem_chunk->area_size);
|
||
|
g_print ("alloc %p\n", area);
|
||
|
|
||
|
for (i=0; i < mem_chunk->area_size; i += mem_chunk->chunk_size) {
|
||
|
GST_MEM_CHUNK_AREA (area + i) = (GstMemChunkElement *)area;
|
||
|
gst_mem_chunk_free (mem_chunk, GST_MEM_CHUNK_DATA (area + i));
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
GstMemChunk*
|
||
|
gst_mem_chunk_new (gchar* name, gint atom_size, gulong area_size, gint type)
|
||
|
{
|
||
|
GstMemChunk *mem_chunk;
|
||
|
|
||
|
g_return_val_if_fail (atom_size > 0, NULL);
|
||
|
g_return_val_if_fail (area_size >= atom_size, NULL);
|
||
|
|
||
|
mem_chunk = g_malloc (sizeof (GstMemChunk));
|
||
|
|
||
|
mem_chunk->chunk_size = atom_size + sizeof (GstMemChunkElement);
|
||
|
area_size = (area_size/atom_size) * mem_chunk->chunk_size;
|
||
|
|
||
|
mem_chunk->name = g_strdup (name);
|
||
|
mem_chunk->free = NULL;
|
||
|
mem_chunk->cnt = 0;
|
||
|
mem_chunk->atom_size = atom_size;
|
||
|
mem_chunk->area_size = area_size;
|
||
|
mem_chunk->cleanup = FALSE;
|
||
|
|
||
|
populate (mem_chunk);
|
||
|
|
||
|
return mem_chunk;
|
||
|
}
|
||
|
|
||
|
static gboolean
|
||
|
free_area (gpointer key, gpointer value, gpointer user_data)
|
||
|
{
|
||
|
g_print ("free %p\n", key);
|
||
|
g_free (key);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
gst_mem_chunk_destroy (GstMemChunk *mem_chunk)
|
||
|
{
|
||
|
GHashTable *elements = g_hash_table_new (NULL, NULL);
|
||
|
gpointer data;
|
||
|
|
||
|
mem_chunk->cleanup = TRUE;
|
||
|
|
||
|
data = gst_mem_chunk_alloc (mem_chunk);
|
||
|
while (data) {
|
||
|
GstMemChunkElement *elem = GST_MEM_CHUNK_LINK (data);
|
||
|
|
||
|
g_hash_table_insert (elements, GST_MEM_CHUNK_AREA (elem), NULL);
|
||
|
|
||
|
data = gst_mem_chunk_alloc (mem_chunk);
|
||
|
}
|
||
|
g_hash_table_foreach_remove (elements, free_area, NULL);
|
||
|
|
||
|
g_hash_table_destroy (elements);
|
||
|
g_free (mem_chunk->name);
|
||
|
g_free (mem_chunk);
|
||
|
}
|
||
|
|
||
|
gpointer
|
||
|
gst_mem_chunk_alloc (GstMemChunk *mem_chunk)
|
||
|
{
|
||
|
GstMemChunkElement *chunk = NULL;
|
||
|
|
||
|
g_return_val_if_fail (mem_chunk != NULL, NULL);
|
||
|
|
||
|
again:
|
||
|
__asm__ __volatile__ (" testl %%eax, %%eax \n\t"
|
||
|
" jz 20f \n"
|
||
|
"10: \t"
|
||
|
" movl (%%eax), %%ebx \n\t"
|
||
|
" movl %%edx, %%ecx \n\t"
|
||
|
" incl %%ecx \n\t"
|
||
|
CHUNK_LOCK "cmpxchg8b %1 \n\t"
|
||
|
" jz 20f \n\t"
|
||
|
" testl %%eax, %%eax \n\t"
|
||
|
" jnz 10b \n"
|
||
|
"20:\t"
|
||
|
:"=a" (chunk)
|
||
|
:"m" (*mem_chunk), "a" (mem_chunk->free), "d" (mem_chunk->cnt)
|
||
|
:"ecx", "ebx");
|
||
|
|
||
|
if (!chunk) {
|
||
|
//g_print ("extending\n");
|
||
|
if (populate (mem_chunk))
|
||
|
goto again;
|
||
|
else
|
||
|
return NULL;
|
||
|
}
|
||
|
return GST_MEM_CHUNK_DATA (chunk);
|
||
|
}
|
||
|
|
||
|
gpointer
|
||
|
gst_mem_chunk_alloc0 (GstMemChunk *mem_chunk)
|
||
|
{
|
||
|
gpointer mem = gst_mem_chunk_alloc (mem_chunk);
|
||
|
|
||
|
if (mem)
|
||
|
memset (mem, 0, mem_chunk->atom_size);
|
||
|
|
||
|
return mem;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
gst_mem_chunk_free (GstMemChunk *mem_chunk, gpointer mem)
|
||
|
{
|
||
|
GstMemChunkElement *chunk;
|
||
|
|
||
|
g_return_if_fail (mem_chunk != NULL);
|
||
|
g_return_if_fail (mem != NULL);
|
||
|
|
||
|
chunk = GST_MEM_CHUNK_LINK (mem);
|
||
|
|
||
|
__asm__ __volatile__ ( "1: \t"
|
||
|
" movl %2, (%1) \n"
|
||
|
CHUNK_LOCK "cmpxchg %1, %0 \n\t"
|
||
|
" jnz 1b \n\t"
|
||
|
:
|
||
|
:"m" (*mem_chunk), "r" (chunk), "a" (mem_chunk->free));
|
||
|
}
|