gstsystemclock.h \
gstthread.h \
gsttrace.h \
+ gsttrashstack.h \
gsttype.h \
gsttypefind.h \
gstutils.h \
#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__ */
#include <string.h> /* 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
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;
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);
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);
}
chunk = GST_MEM_CHUNK_LINK (mem);
- GST_ATOMIC_SWAP (&mem_chunk->swap, &chunk->link);
+ gst_trash_stack_push (&mem_chunk->stack, chunk);
}
#define __GST_MEM_CHUNK_H__
#include <glib.h>
-#include <gst/gstatomic.h>
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,
--- /dev/null
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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 <glib.h>
+
+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__ */