fix doc build fix autogen
[platform/upstream/gstreamer.git] / gst / gsttrashstack.h
1 /* GStreamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #ifndef __GST_TRASH_STACK_H__
21 #define __GST_TRASH_STACK_H__
22
23 #include <glib.h>
24 #include "gstmacros.h"
25
26 G_BEGIN_DECLS
27
28 typedef struct _GstTrashStack GstTrashStack;
29 typedef struct _GstTrashStackElement GstTrashStackElement;
30
31 struct _GstTrashStackElement {
32   GstTrashStackElement *next;
33 };
34
35 typedef volatile gpointer gst_vgpointer;/* gtk-doc volatile workaround */
36 typedef volatile gulong gst_vgulong;    /* gtk-doc volatile workaround */
37                                                                                 
38 struct _GstTrashStack {
39   gst_vgpointer         head;  
40   gst_vgulong           count;          /* for the ABA problem */
41   GMutex                *lock;          /* lock for C fallback */
42 };
43
44 GST_INLINE_FUNC GstTrashStack*  gst_trash_stack_new     (void);
45 GST_INLINE_FUNC void            gst_trash_stack_init    (GstTrashStack *stack);
46 GST_INLINE_FUNC void            gst_trash_stack_destroy (GstTrashStack *stack);
47 GST_INLINE_FUNC void            gst_trash_stack_free    (GstTrashStack *stack);
48
49 GST_INLINE_FUNC void            gst_trash_stack_push    (GstTrashStack *stack, gpointer mem);
50 GST_INLINE_FUNC gpointer        gst_trash_stack_pop     (GstTrashStack *stack);
51
52 #if defined (GST_CAN_INLINE) || defined (__GST_TRASH_STACK_C__)
53
54 #if defined (USE_FAST_STACK_TRASH) && defined (__i386__) && defined (__GNUC__) && __GNUC__ >= 2 
55
56 #ifdef GST_CONFIG_NO_SMP
57 #define SMP_LOCK ""
58 #else
59 #define SMP_LOCK "lock ; "
60 #endif
61
62 /*
63  * intel ia32 optimized lockfree implementations
64  */
65 GST_INLINE_FUNC void
66 gst_trash_stack_init (GstTrashStack *stack)
67 {
68   stack->head = NULL;
69   stack->count = 0;
70 }
71
72 GST_INLINE_FUNC void
73 gst_trash_stack_destroy (GstTrashStack *stack)
74 {
75 }
76
77 GST_INLINE_FUNC void
78 gst_trash_stack_push (GstTrashStack *stack, gpointer mem)
79 {
80  __asm__ __volatile__ (
81    "1:                         \n\t"
82    "  movl %2, (%1);           \n\t"    /* mem->next == stack->head */
83    SMP_LOCK "cmpxchg %1, %0;   \n\t"    /* if head unchanged, move mem into it */
84    "  jnz 1b;                  \n"      /* head changed, retry */
85      :
86      : "m" (*stack),
87        "r" (mem),
88        "a" (stack->head)
89   );
90 }
91
92 GST_INLINE_FUNC gpointer
93 gst_trash_stack_pop (GstTrashStack *stack)
94 {
95   GstTrashStackElement *head;
96
97   /* pop is a little more complicated as we need to avoid the so called ABA
98    * problem that arises when a pop and push of the same element happens
99    * right between when we read head->next and try to swing the new pointer
100    * into place. This is usually solved using a counter which makes it highly
101    * inlikely that we manage to grab the wrong head->next value.
102    */
103   __asm__ __volatile__ (
104     "  testl %%eax, %%eax;      \n\t"   /* if (head == NULL) return */
105     "  jz 20f;                  \n\t"
106     "10:                        \n\t"
107     "  movl (%%eax), %%ebx;     \n\t"   /* take value pointed to by head (head->next) */
108     "  movl %%edx, %%ecx;       \n\t"   /* take counter */
109     "  incl %%ecx;              \n\t"   /* and increment */
110     SMP_LOCK "cmpxchg8b %1;     \n\t"   /* if eax:edx == *stack, move ebx:ecx to *stack,
111                                          * else *stack is moved into eax:edx again... */
112     "  jnz 10b;                 \n\t"   /* ... and we retry */
113     "20:                        \n"
114       : "=a" (head)
115       :  "m" (*stack),
116          "a" (stack->head),
117          "d" (stack->count)
118       :  "ecx", "ebx"
119   );
120
121   return head;
122 }
123
124 #else
125
126 /*
127  * generic implementation
128  */
129 GST_INLINE_FUNC void
130 gst_trash_stack_init (GstTrashStack *stack)
131 {
132   stack->head = NULL;
133   stack->lock = g_mutex_new();
134 }
135
136 GST_INLINE_FUNC void
137 gst_trash_stack_destroy (GstTrashStack *stack)
138 {
139   g_mutex_free (stack->lock);
140 }
141
142 GST_INLINE_FUNC void
143 gst_trash_stack_push (GstTrashStack *stack, gpointer mem)
144 {
145   GstTrashStackElement *elem = (GstTrashStackElement *) mem;
146
147   g_mutex_lock (stack->lock);
148   elem->next = stack->head;
149   stack->head = elem;
150   g_mutex_unlock (stack->lock);
151 }
152
153 GST_INLINE_FUNC gpointer
154 gst_trash_stack_pop (GstTrashStack *stack)
155 {
156   GstTrashStackElement *head;
157   
158   g_mutex_lock (stack->lock);
159   head = (GstTrashStackElement *) stack->head;
160   if (head)
161     stack->head = head->next;
162   g_mutex_unlock (stack->lock);
163
164   return head;
165 }
166
167 #endif
168
169 /*
170  * common functions
171  */
172 GST_INLINE_FUNC GstTrashStack*
173 gst_trash_stack_new (void)
174 {
175   GstTrashStack *stack;
176
177   stack = g_new (GstTrashStack, 1);
178   gst_trash_stack_init (stack);
179
180   return stack;
181 }
182
183 GST_INLINE_FUNC void
184 gst_trash_stack_free (GstTrashStack *stack)
185 {
186   gst_trash_stack_destroy (stack);
187   g_free (stack);
188 }
189
190 #endif /* defined (GST_CAN_INLINE) || defined (__GST_TRASH_STACK_C__)*/
191
192 G_END_DECLS
193
194 #endif /*  __GST_TRASH_STACK_H__ */