mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-10 11:29:55 +00:00
192 lines
4.2 KiB
C
192 lines
4.2 KiB
C
|
#include "gstmempool.h"
|
||
|
|
||
|
#ifdef __SMP__
|
||
|
#define POOL_LOCK "lock ; "
|
||
|
#else
|
||
|
#define POOL_LOCK ""
|
||
|
#endif
|
||
|
|
||
|
#define GST_MEM_POOL_AREA(pool) (((GstMemPoolElement*)(pool))->area)
|
||
|
#define GST_MEM_POOL_DATA(pool) ((gpointer)(((GstMemPoolElement*)(pool)) + 1))
|
||
|
#define GST_MEM_POOL_LINK(mem) ((GstMemPoolElement*)((guint8*)(mem) - sizeof (GstMemPoolElement)))
|
||
|
|
||
|
#define USE_ASM
|
||
|
|
||
|
/*******************************************************
|
||
|
* area size
|
||
|
* +-----------------------------------------+
|
||
|
* pool size
|
||
|
* +------------+
|
||
|
*
|
||
|
* !next!data... !next!data.... !next!data...
|
||
|
* ! ^ ! ^ !
|
||
|
* +-------------+ +------------+ +---> NULL
|
||
|
*
|
||
|
*/
|
||
|
static gboolean
|
||
|
populate (GstMemPool *mem_pool)
|
||
|
{
|
||
|
guint8 *area;
|
||
|
gint i;
|
||
|
|
||
|
if (mem_pool->cleanup)
|
||
|
return FALSE;
|
||
|
|
||
|
area = (guint8 *) g_malloc (mem_pool->area_size);
|
||
|
|
||
|
for (i=0; i < mem_pool->area_size; i += mem_pool->pool_size) {
|
||
|
guint8 *areap = area + i;
|
||
|
|
||
|
GST_MEM_POOL_AREA (areap) = (GstMemPoolElement *)area;
|
||
|
|
||
|
if (mem_pool->alloc_func) {
|
||
|
mem_pool->alloc_func (mem_pool, GST_MEM_POOL_DATA (areap));
|
||
|
}
|
||
|
|
||
|
gst_mem_pool_free (mem_pool, GST_MEM_POOL_DATA (areap));
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
GstMemPool*
|
||
|
gst_mem_pool_new (gchar* name, gint atom_size, gulong area_size, gint type,
|
||
|
GstMemPoolAllocFunc alloc_func,
|
||
|
GstMemPoolFreeFunc free_func)
|
||
|
{
|
||
|
GstMemPool *mem_pool;
|
||
|
|
||
|
g_return_val_if_fail (atom_size > 0, NULL);
|
||
|
g_return_val_if_fail (area_size >= atom_size, NULL);
|
||
|
|
||
|
mem_pool = g_malloc (sizeof (GstMemPool));
|
||
|
|
||
|
mem_pool->pool_size = atom_size + sizeof (GstMemPoolElement);
|
||
|
area_size = (area_size/atom_size) * mem_pool->pool_size;
|
||
|
|
||
|
mem_pool->name = g_strdup (name);
|
||
|
mem_pool->free = NULL;
|
||
|
mem_pool->cnt = 0;
|
||
|
mem_pool->atom_size = atom_size;
|
||
|
mem_pool->area_size = area_size;
|
||
|
mem_pool->cleanup = FALSE;
|
||
|
mem_pool->alloc_func = alloc_func;
|
||
|
mem_pool->free_func = free_func;
|
||
|
mem_pool->chunk_lock = g_mutex_new ();
|
||
|
|
||
|
populate (mem_pool);
|
||
|
|
||
|
return mem_pool;
|
||
|
}
|
||
|
|
||
|
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_pool_destroy (GstMemPool *mem_pool)
|
||
|
{
|
||
|
GHashTable *elements = g_hash_table_new (NULL, NULL);
|
||
|
gpointer data;
|
||
|
|
||
|
mem_pool->cleanup = TRUE;
|
||
|
|
||
|
data = gst_mem_pool_alloc (mem_pool);
|
||
|
while (data) {
|
||
|
GstMemPoolElement *elem = GST_MEM_POOL_LINK (data);
|
||
|
|
||
|
g_hash_table_insert (elements, GST_MEM_POOL_AREA (elem), NULL);
|
||
|
|
||
|
data = gst_mem_pool_alloc (mem_pool);
|
||
|
}
|
||
|
g_hash_table_foreach_remove (elements, free_area, NULL);
|
||
|
|
||
|
g_hash_table_destroy (elements);
|
||
|
g_free (mem_pool->name);
|
||
|
g_free (mem_pool);
|
||
|
}
|
||
|
|
||
|
gpointer
|
||
|
gst_mem_pool_alloc (GstMemPool *mem_pool)
|
||
|
{
|
||
|
GstMemPoolElement *pool = NULL;
|
||
|
|
||
|
g_return_val_if_fail (mem_pool != NULL, NULL);
|
||
|
|
||
|
again:
|
||
|
#ifdef USE_ASM
|
||
|
__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"
|
||
|
POOL_LOCK "cmpxchg8b %1 \n\t"
|
||
|
" jz 20f \n\t"
|
||
|
" testl %%eax, %%eax \n\t"
|
||
|
" jnz 10b \n"
|
||
|
"20:\t"
|
||
|
:"=a" (pool)
|
||
|
:"m" (*mem_pool), "a" (mem_pool->free), "d" (mem_pool->cnt)
|
||
|
:"ecx", "ebx");
|
||
|
#else
|
||
|
g_mutex_lock (mem_pool->chunk_lock);
|
||
|
if (mem_pool->free) {
|
||
|
pool = mem_pool->free;
|
||
|
mem_pool->free = pool->link;
|
||
|
}
|
||
|
g_mutex_unlock (mem_pool->chunk_lock);
|
||
|
#endif
|
||
|
|
||
|
if (!pool) {
|
||
|
//g_print ("extending\n");
|
||
|
if (populate (mem_pool))
|
||
|
goto again;
|
||
|
else
|
||
|
return NULL;
|
||
|
}
|
||
|
return GST_MEM_POOL_DATA (pool);
|
||
|
}
|
||
|
|
||
|
gpointer
|
||
|
gst_mem_pool_alloc0 (GstMemPool *mem_pool)
|
||
|
{
|
||
|
gpointer mem = gst_mem_pool_alloc (mem_pool);
|
||
|
|
||
|
if (mem)
|
||
|
memset (mem, 0, mem_pool->atom_size);
|
||
|
|
||
|
return mem;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
gst_mem_pool_free (GstMemPool *mem_pool, gpointer mem)
|
||
|
{
|
||
|
GstMemPoolElement *pool;
|
||
|
|
||
|
g_return_if_fail (mem_pool != NULL);
|
||
|
g_return_if_fail (mem != NULL);
|
||
|
|
||
|
pool = GST_MEM_POOL_LINK (mem);
|
||
|
|
||
|
#ifdef USE_ASM
|
||
|
__asm__ __volatile__ ( "1: \t"
|
||
|
" movl %2, (%1) \n"
|
||
|
POOL_LOCK "cmpxchg %1, %0 \n\t"
|
||
|
" jnz 1b \n\t"
|
||
|
:
|
||
|
:"m" (*mem_pool), "r" (pool), "a" (mem_pool->free));
|
||
|
#else
|
||
|
g_mutex_lock (mem_pool->chunk_lock);
|
||
|
pool->link = mem_pool->free;
|
||
|
mem_pool->free = pool;
|
||
|
g_mutex_unlock (mem_pool->chunk_lock);
|
||
|
#endif
|
||
|
}
|