diff --git a/gst/Makefile.am b/gst/Makefile.am index 393b0f947b..14bd2f6fae 100644 --- a/gst/Makefile.am +++ b/gst/Makefile.am @@ -135,6 +135,7 @@ gst_headers = \ gstsystemclock.h \ gstthread.h \ gsttrace.h \ + gsttrashstack.h \ gsttype.h \ gsttypefind.h \ gstutils.h \ diff --git a/gst/gstatomic.h b/gst/gstatomic.h index f35946f1d5..76676165c4 100644 --- a/gst/gstatomic.h +++ b/gst/gstatomic.h @@ -113,138 +113,6 @@ G_STMT_START { \ #endif /* HAVE_ATOMIC_H */ -typedef struct _GstAtomicSwap GstAtomicSwap; - -#define GST_ATOMIC_SWAP_VALUE(swap) ((swap)->value) - -struct _GstAtomicSwap { - volatile gpointer value; - volatile gulong cnt; /* for the ABA problem */ - GMutex *lock; /* lock for C fallback */ -}; - -#if defined (__i386__) && defined (__GNUC__) && __GNUC__ >= 2 - -#define GST_ATOMIC_LOCK "lock ; " - -#define _GST_ATOMIC_SWAP_INIT(swap,val) \ -G_STMT_START { \ - (swap)->value = (gpointer)(val); \ - (swap)->cnt = 0; \ -} G_STMT_END - -#define _GST_ATOMIC_SWAP(swap, val) \ -G_STMT_START { \ - __asm__ __volatile__ ("1:" \ - " movl %2, (%1);" \ - GST_ATOMIC_LOCK "cmpxchg %1, %0;" \ - " jnz 1b;" \ - : \ - : "m" (*swap), \ - "r" (val), \ - "a" ((swap)->value)); \ -} G_STMT_END - -#define _GST_ATOMIC_SWAP_GET(swap, val, res) \ -G_STMT_START { \ - __asm__ __volatile__ (" testl %%eax, %%eax;" \ - " jz 20f;" \ - "10:" \ - " movl (%%eax), %%ebx;" \ - " movl %%edx, %%ecx;" \ - " incl %%ecx;" \ - GST_ATOMIC_LOCK "cmpxchg8b %1;" \ - " jnz 10b;" \ - "20:\t" \ - : "=a" (*res) \ - : "m" (*(swap)), \ - "a" (val), \ - "d" ((swap)->cnt) \ - : "ecx", "ebx"); \ -} G_STMT_END - -#elif defined (__powerpcfoobarred__) && defined (__GNUC__) && __GNUC__ >= 2 - -#define _GST_ATOMIC_SWAP_INIT(swap,val) \ -G_STMT_START { \ - (swap)->value = (gpointer)(val); \ - (swap)->cnt = 0; \ -} G_STMT_END - -#define _GST_ATOMIC_SWAP(swap, val) \ -G_STMT_START { \ - int tmp; \ - __asm__ __volatile__ ("1:" \ - " lwarx %0, 0, %2 \n" \ - " stwcx. %3, 0, %2 \n" \ - " bne- 1b \n" \ - : "=&r" (tmp), \ - "=m" (*swap) \ - : "r" (swap), \ - "r" (val), \ - "m" (* swap) \ - : "9", "cc"); \ -} G_STMT_END - -#define _GST_ATOMIC_SWAP_GET(swap, val, res) \ -G_STMT_START { \ - __asm__ __volatile__ ("1:" \ - " lwarx %0, 0, %2 \n" \ - " stwcx. %3, 0, %2 \n" \ - " bne- 1b \n" \ - : "=&r" (*(res)), \ - "=m" (*swap) \ - : "r" (swap), \ - "r" (val), \ - "m" (*swap) \ - : "cc"); \ -} G_STMT_END - -#else - -#define _GST_ATOMIC_SWAP_INIT(swap,val) \ -G_STMT_START { \ - (swap)->lock = g_mutex_new(); \ - (swap)->value = (gpointer)val; \ -} G_STMT_END - -#define _GST_ATOMIC_SWAP(swap, val) \ -G_STMT_START { \ - gpointer tmp; \ - g_mutex_lock ((swap)->lock); \ - tmp = (swap)->value; \ - (swap)->value = val; \ - ((gpointer)*val) = tmp; \ - g_mutex_unlock ((swap)->lock); \ -} G_STMT_END - -#define _GST_ATOMIC_SWAP_GET(swap, val, res) \ -G_STMT_START { \ - if (val) { \ - gpointer tmp; \ - gint *tmp2; /* this is pretty EVIL */ \ - g_mutex_lock ((swap)->lock); \ - tmp = (swap)->value; \ - tmp2 = val; \ - (swap)->value = (gpointer)*tmp2; \ - (*res) = (gpointer) (*tmp2 = (gint*)tmp); \ - g_mutex_unlock ((swap)->lock); \ - } \ -} G_STMT_END -#endif - -/* initialize the swap structure with an initial value */ -#define GST_ATOMIC_SWAP_INIT(swap,val) _GST_ATOMIC_SWAP_INIT(swap, val) - -/* atomically swap the contents the swap value with the value pointed to - * by val. */ -#define GST_ATOMIC_SWAP(swap, val) _GST_ATOMIC_SWAP(swap, val) - -/* atomically swap the contents the swap value with the value pointed to - * by val. The new value of the swap value is returned in the memory pointed - * to by res */ -#define GST_ATOMIC_SWAP_GET(swap,val,res) _GST_ATOMIC_SWAP_GET(swap, val, res) - G_END_DECLS #endif /* __GST_ATOMIC_H__ */ diff --git a/gst/gstmemchunk.c b/gst/gstmemchunk.c index 0fb8bc6827..e4f7bf628b 100644 --- a/gst/gstmemchunk.c +++ b/gst/gstmemchunk.c @@ -20,22 +20,43 @@ #include /* memset */ #include "gstlog.h" -#include "gstmemchunk.h" #include "gstutils.h" +#include "gstmemchunk.h" +#define __GST_TRASH_STACK_C__ +#include "gsttrashstack.h" #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))) +typedef struct _GstMemChunkElement GstMemChunkElement; + +struct _GstMemChunkElement +{ + GstTrashStackElement elem; /* make sure we can safely push it on the trashstack */ + gpointer area; /* pointer to data areas */ +}; + +struct _GstMemChunk +{ + GstTrashStack stack; + + gchar *name; + gulong area_size; + gulong chunk_size; + gulong atom_size; + gboolean cleanup; +}; + /******************************************************* * area size - * +-----------------------------------------+ + * +-------------------------------------------------------+ * chunk size - * +------------+ + * +-----------------+ * - * !next!data... !next!data.... !next!data... - * ! ^ ! ^ ! - * +-------------+ +------------+ +---> NULL + * !next!area|data... !next!area!data.... !next!area!data... + * ! ^ ! ^ ! + * +------------------+ +-----------------+ +--------> NULL * */ static gboolean @@ -46,12 +67,12 @@ populate (GstMemChunk *mem_chunk) if (mem_chunk->cleanup) return FALSE; - + area = (guint8 *) g_malloc0 (mem_chunk->area_size); 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)); + GST_MEM_CHUNK_AREA (area + i) = area; + gst_trash_stack_push (&mem_chunk->stack, area + i); } return TRUE; @@ -87,7 +108,7 @@ gst_mem_chunk_new (gchar* name, gint atom_size, gulong area_size, gint type) mem_chunk->atom_size = atom_size; mem_chunk->area_size = area_size; mem_chunk->cleanup = FALSE; - GST_ATOMIC_SWAP_INIT (&mem_chunk->swap, NULL); + gst_trash_stack_init (&mem_chunk->stack); populate (mem_chunk); @@ -144,21 +165,20 @@ gst_mem_chunk_destroy (GstMemChunk *mem_chunk) gpointer gst_mem_chunk_alloc (GstMemChunk *mem_chunk) { - GstMemChunkElement *chunk = NULL; + GstMemChunkElement *chunk; g_return_val_if_fail (mem_chunk != NULL, NULL); again: - GST_ATOMIC_SWAP_GET (&mem_chunk->swap, - GST_ATOMIC_SWAP_VALUE (&mem_chunk->swap), - &chunk); - + chunk = gst_trash_stack_pop (&mem_chunk->stack); + /* chunk is empty, try to refill */ if (!chunk) { if (populate (mem_chunk)) goto again; else return NULL; } + return GST_MEM_CHUNK_DATA (chunk); } @@ -200,5 +220,5 @@ gst_mem_chunk_free (GstMemChunk *mem_chunk, gpointer mem) chunk = GST_MEM_CHUNK_LINK (mem); - GST_ATOMIC_SWAP (&mem_chunk->swap, &chunk->link); + gst_trash_stack_push (&mem_chunk->stack, chunk); } diff --git a/gst/gstmemchunk.h b/gst/gstmemchunk.h index f31cc75dd0..6e0d7087e5 100644 --- a/gst/gstmemchunk.h +++ b/gst/gstmemchunk.h @@ -21,30 +21,10 @@ #define __GST_MEM_CHUNK_H__ #include -#include G_BEGIN_DECLS typedef struct _GstMemChunk GstMemChunk; -typedef struct _GstMemChunkElement GstMemChunkElement; - -struct _GstMemChunkElement -{ - GstMemChunkElement *link; /* next cell in the lifo */ - GstMemChunkElement *area; -}; - -struct _GstMemChunk -{ - GstAtomicSwap swap; - - gchar *name; - gulong area_size; - gulong chunk_size; - gulong atom_size; - gboolean cleanup; - GMutex *lock; -}; GstMemChunk* gst_mem_chunk_new (gchar *name, gint atom_size, diff --git a/gst/gsttrashstack.h b/gst/gsttrashstack.h new file mode 100644 index 0000000000..98259671e7 --- /dev/null +++ b/gst/gsttrashstack.h @@ -0,0 +1,181 @@ +/* GStreamer + * Copyright (C) <1999> Erik Walthinsen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_TRASH_STACK_H__ +#define __GST_TRASH_STACK_H__ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +G_BEGIN_DECLS + +typedef struct _GstTrashStack GstTrashStack; +typedef struct _GstTrashStackElement GstTrashStackElement; + +struct _GstTrashStackElement { + GstTrashStackElement *next; +}; + +struct _GstTrashStack { + volatile gpointer head; + volatile gulong count; /* for the ABA problem */ + GMutex *lock; /* lock for C fallback */ +}; + +G_INLINE_FUNC GstTrashStack* gst_trash_stack_new (void); +G_INLINE_FUNC void gst_trash_stack_init (GstTrashStack *stack); +G_INLINE_FUNC void gst_trash_stack_destroy (GstTrashStack *stack); +G_INLINE_FUNC void gst_trash_stack_free (GstTrashStack *stack); + +G_INLINE_FUNC void gst_trash_stack_push (GstTrashStack *stack, gpointer mem); +G_INLINE_FUNC gpointer gst_trash_stack_pop (GstTrashStack *stack); + +#if defined (G_CAN_INLINE) || defined (__GST_TRASH_STACK_C__) + +#if defined (__i386__) && defined (__GNUC__) && __GNUC__ >= 2 + +/* + * intel ia32 optimized lockfree implementations + */ +G_INLINE_FUNC void +gst_trash_stack_init (GstTrashStack *stack) +{ + stack->head = NULL; + stack->count = 0; +} + +G_INLINE_FUNC void +gst_trash_stack_destroy (GstTrashStack *stack) +{ +} + +G_INLINE_FUNC void +gst_trash_stack_push (GstTrashStack *stack, gpointer mem) +{ + __asm__ __volatile__ ( + "1: \n\t" + " movl %2, (%1); \n\t" + " lock; cmpxchg %1, %0; \n\t" + " jnz 1b; \n" + : + : "m" (*stack), + "r" (mem), + "a" (stack->head) + ); +} + +G_INLINE_FUNC gpointer +gst_trash_stack_pop (GstTrashStack *stack) +{ + GstTrashStackElement *head; + + __asm__ __volatile__ ( + " testl %%eax, %%eax; \n\t" + " jz 20f; \n\t" + "10: \n\t" + " movl (%%eax), %%ebx; \n\t" + " movl %%edx, %%ecx; \n\t" + " incl %%ecx; \n\t" + " lock; cmpxchg8b %1; \n\t" + " jnz 10b; \n\t" + "20: \n" + : "=a" (head) + : "m" (*stack), + "a" (stack->head), + "d" (stack->count) + : "ecx", "ebx" + ); + + return head; +} + +#else + +/* + * generic implementation + */ +G_INLINE_FUNC void +gst_trash_stack_init (GstTrashStack *stack) +{ + stack->head = NULL; + stack->lock = g_mutex_new(); +} + +G_INLINE_FUNC void +gst_trash_stack_destroy (GstTrashStack *stack) +{ + g_mutex_free (stack->lock); +} + +G_INLINE_FUNC void +gst_trash_stack_push (GstTrashStack *stack, gpointer mem) +{ + GstTrashStackElement *elem = (GstTrashStackElement *) mem; + + g_mutex_lock (stack->lock); + elem->next = stack->head; + stack->head = elem; + g_mutex_unlock (stack->lock); +} + +G_INLINE_FUNC gpointer +gst_trash_stack_pop (GstTrashStack *stack) +{ + GstTrashStackElement *head; + + g_mutex_lock (stack->lock); + head = (GstTrashStackElement *) stack->head; + if (head) + stack->head = head->next; + g_mutex_unlock (stack->lock); + + return head; +} + +#endif + +/* + * common functions + */ +G_INLINE_FUNC GstTrashStack* +gst_trash_stack_new (void) +{ + GstTrashStack *stack; + + stack = g_new (GstTrashStack, 1); + gst_trash_stack_init (stack); + + return stack; +} + +G_INLINE_FUNC void +gst_trash_stack_free (GstTrashStack *stack) +{ + gst_trash_stack_destroy (stack); + g_free (stack); +} + +#endif /* defined (G_CAN_INLINE) || defined (__GST_TRASH_STACK_C__)*/ + +G_END_DECLS + +#endif /* __GST_TRASH_STACK_H__ */