gallium: Use `_new' name, `new' is a reserved keyword in C++.
[mesa.git] / src / gallium / include / pipe / p_atomic.h
1 /**
2 * Many similar implementations exist. See for example libwsbm
3 * or the linux kernel include/atomic.h
4 *
5 * No copyright claimed on this file.
6 *
7 */
8
9 #ifndef P_ATOMIC_H
10 #define P_ATOMIC_H
11
12 #include "p_compiler.h"
13 #include "p_defines.h"
14
15 #ifdef __cplusplus
16 extern "C" {
17 #endif
18
19 #if (defined(PIPE_CC_GCC))
20 struct pipe_atomic {
21 int32_t count;
22 };
23
24 #define p_atomic_set(_v, _i) ((_v)->count = (_i))
25 #define p_atomic_read(_v) ((_v)->count)
26
27
28 static INLINE boolean
29 p_atomic_dec_zero(struct pipe_atomic *v)
30 {
31 #ifdef __i386__
32 unsigned char c;
33
34 __asm__ __volatile__("lock; decl %0; sete %1":"+m"(v->count), "=qm"(c)
35 ::"memory");
36
37 return c != 0;
38 #else /* __i386__*/
39 return (__sync_sub_and_fetch(&v->count, 1) == 0);
40 #endif /* __i386__*/
41 }
42
43 static INLINE void
44 p_atomic_inc(struct pipe_atomic *v)
45 {
46 #ifdef __i386__
47 __asm__ __volatile__("lock; incl %0":"+m"(v->count));
48 #else /* __i386__*/
49 (void) __sync_add_and_fetch(&v->count, 1);
50 #endif /* __i386__*/
51 }
52
53 static INLINE void
54 p_atomic_dec(struct pipe_atomic *v)
55 {
56 #ifdef __i386__
57 __asm__ __volatile__("lock; decl %0":"+m"(v->count));
58 #else /* __i386__*/
59 (void) __sync_sub_and_fetch(&v->count, 1);
60 #endif /* __i386__*/
61 }
62
63 static INLINE int32_t
64 p_atomic_cmpxchg(struct pipe_atomic *v, int32_t old, int32_t _new)
65 {
66 return __sync_val_compare_and_swap(&v->count, old, _new);
67 }
68
69 #elif (defined(PIPE_SUBSYSTEM_WINDOWS_DISPLAY) || defined(PIPE_SUBSYSTEM_WINDOWS_MINIPORT)) /* (defined(PIPE_CC_GCC)) */
70
71 struct pipe_atomic
72 {
73 int32_t count;
74 };
75
76 #define p_atomic_set(_v, _i) ((_v)->count = (_i))
77 #define p_atomic_read(_v) ((_v)->count)
78 #define p_atomic_dec_zero(_v) ((boolean) --(_v)->count)
79 #define p_atomic_inc(_v) ((void) (_v)->count++)
80 #define p_atomic_dec(_v) ((void) (_v)->count--)
81 #define p_atomic_cmpxchg(_v, old, _new) ((_v)->count == old ? (_v)->count = (_new) : (_v)->count)
82
83 #elif (defined(PIPE_ARCH_X86) && defined(PIPE_CC_MSVC)) /* (defined(PIPE_SUBSYSTEM_WINDOWS_DISPLAY) || defined(PIPE_SUBSYSTEM_WINDOWS_MINIPORT)) */
84
85 struct pipe_atomic
86 {
87 int32_t count;
88 };
89
90 #define p_atomic_set(_v, _i) ((_v)->count = (_i))
91 #define p_atomic_read(_v) ((_v)->count)
92
93 static INLINE boolean
94 p_atomic_dec_zero(struct pipe_atomic *v)
95 {
96 int32_t *pcount = &v->count;
97 unsigned char c;
98
99 __asm {
100 mov eax, [pcount]
101 lock dec dword ptr [eax]
102 sete byte ptr [c]
103 }
104
105 return c != 0;
106 }
107
108 static INLINE void
109 p_atomic_inc(struct pipe_atomic *v)
110 {
111 int32_t *pcount = &v->count;
112
113 __asm {
114 mov eax, [pcount]
115 lock inc dword ptr [eax]
116 }
117 }
118
119 static INLINE void
120 p_atomic_dec(struct pipe_atomic *v)
121 {
122 int32_t *pcount = &v->count;
123
124 __asm {
125 mov eax, [pcount]
126 lock dec dword ptr [eax]
127 }
128 }
129
130 static INLINE int32_t
131 p_atomic_cmpxchg(struct pipe_atomic *v, int32_t old, int32_t _new)
132 {
133 int32_t *pcount = &v->count;
134 int32_t orig;
135
136 __asm {
137 mov ecx, [pcount]
138 mov eax, [old]
139 mov edx, [_new]
140 lock cmpxchg [ecx], edx
141 mov [orig], eax
142 }
143
144 return orig;
145 }
146
147 #elif (defined(PIPE_SUBSYSTEM_WINDOWS_USER)) /* (defined(PIPE_ARCH_X86) && defined(PIPE_CC_MSVC)) */
148
149 struct pipe_atomic
150 {
151 long count;
152 };
153
154 #define p_atomic_set(_v, _i) ((_v)->count = (_i))
155 #define p_atomic_read(_v) ((_v)->count)
156
157 static INLINE boolean
158 p_atomic_dec_zero(struct pipe_atomic *v)
159 {
160 return InterlockedDecrement(&v->count);
161 }
162
163 static INLINE void
164 p_atomic_inc(struct pipe_atomic *v)
165 {
166 InterlockedIncrement(&v->count);
167 }
168
169 static INLINE void
170 p_atomic_dec(struct pipe_atomic *v)
171 {
172 InterlockedDecrement(&v->count);
173 }
174
175 static INLINE int32_t
176 p_atomic_cmpxchg(struct pipe_atomic *v, int32_t old, int32_t _new)
177 {
178 return InterlockedCompareExchange(&v->count, _new, old);
179 }
180
181 #else /* (defined(PIPE_SUBSYSTEM_WINDOWS_USER)) */
182
183 #include "pipe/p_thread.h"
184
185 /**
186 * This implementation should really not be used.
187 * Add an assembly port instead. It may abort and
188 * doesn't destroy used mutexes.
189 */
190
191 struct pipe_atomic {
192 pipe_mutex mutex;
193 int32_t count;
194 };
195
196 static INLINE void
197 p_atomic_set(struct pipe_atomic *v, int32_t i)
198 {
199 pipe_mutex_init(v->mutex);
200 pipe_mutex_lock(v->mutex);
201 v->count = i;
202 pipe_mutex_unlock(v->mutex);
203 }
204
205 static INLINE int32_t
206 p_atomic_read(struct pipe_atomic *v)
207 {
208 int32_t ret;
209
210 pipe_mutex_lock(v->mutex);
211 ret = v->count;
212 pipe_mutex_unlock(v->mutex);
213 return ret;
214 }
215
216 static INLINE void
217 p_atomic_inc(struct pipe_atomic *v)
218 {
219 pipe_mutex_lock(v->mutex);
220 ++v->count;
221 pipe_mutex_unlock(v->mutex);
222 }
223
224 static INLINE void
225 p_atomic_dec(struct pipe_atomic *v)
226 {
227 pipe_mutex_lock(v->mutex);
228 --v->count;
229 pipe_mutex_unlock(v->mutex);
230 }
231
232 static INLINE boolean
233 p_atomic_dec_zero(struct pipe_atomic *v)
234 {
235 boolean ret;
236
237 pipe_mutex_lock(v->mutex);
238 ret = (--v->count == 0);
239 pipe_mutex_unlock(v->mutex);
240 return ret;
241 }
242
243 static INLINE int32_t
244 p_atomic_cmpxchg(struct pipe_atomic *v, int32_t old, int32_t _new)
245 {
246 int32_t ret;
247
248 pipe_mutex_lock(v->mutex);
249 ret = v->count;
250 if (ret == old)
251 v->count = _new;
252 pipe_mutex_unlock(v->mutex);
253
254 return ret;
255 }
256
257 #endif /* (defined(PIPE_CC_GCC)) */
258
259 #ifdef __cplusplus
260 }
261 #endif
262
263 #endif /* P_ATOMIC_H */