- First pass at cleaning up the atomic mess
authorWim Taymans <wim.taymans@gmail.com>
Sun, 29 Dec 2002 19:19:45 +0000 (19:19 +0000)
committerWim Taymans <wim.taymans@gmail.com>
Sun, 29 Dec 2002 19:19:45 +0000 (19:19 +0000)
Original commit message from CVS:
- First pass at cleaning up the atomic mess
- moved weird asm to datastructure that makes sense
- this should also make the trasition to libatomic less painful

gst/Makefile.am
gst/gstatomic.h
gst/gstmemchunk.c
gst/gstmemchunk.h
gst/gsttrashstack.h [new file with mode: 0644]

index 393b0f9..14bd2f6 100644 (file)
@@ -135,6 +135,7 @@ gst_headers =                       \
        gstsystemclock.h        \
        gstthread.h             \
        gsttrace.h              \
+       gsttrashstack.h         \
        gsttype.h               \
        gsttypefind.h           \
        gstutils.h              \
index f35946f..7667616 100644 (file)
@@ -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__ */
index 0fb8bc6..e4f7bf6 100644 (file)
 #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
@@ -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);
 }
index f31cc75..6e0d708 100644 (file)
 #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,
diff --git a/gst/gsttrashstack.h b/gst/gsttrashstack.h
new file mode 100644 (file)
index 0000000..9825967
--- /dev/null
@@ -0,0 +1,181 @@
+/* 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__ */