gallium: Implement atomic for MSVC on x86.
[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_ARCH_X86) && defined(PIPE_CC_MSVC)) /* (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
79 static INLINE boolean
80 p_atomic_dec_zero(struct pipe_atomic *v)
81 {
82 int32_t *pcount = &v->count;
83 unsigned char c;
84
85 __asm {
86 mov eax, [pcount]
87 lock dec dword ptr [eax]
88 sete byte ptr [c]
89 }
90
91 return c != 0;
92 }
93
94 static INLINE void
95 p_atomic_inc(struct pipe_atomic *v)
96 {
97 int32_t *pcount = &v->count;
98
99 __asm {
100 mov eax, [pcount]
101 lock inc dword ptr [eax]
102 }
103 }
104
105 static INLINE void
106 p_atomic_dec(struct pipe_atomic *v)
107 {
108 int32_t *pcount = &v->count;
109
110 __asm {
111 mov eax, [pcount]
112 lock dec dword ptr [eax]
113 }
114 }
115
116 static INLINE int32_t
117 p_atomic_cmpxchg(struct pipe_atomic *v, int32_t old, int32_t new)
118 {
119 int32_t *pcount = &v->count;
120 int32_t orig;
121
122 __asm {
123 mov ecx, [pcount]
124 mov eax, [old]
125 mov edx, [new]
126 lock cmpxchg [ecx], edx
127 mov [orig], eax
128 }
129
130 return orig;
131 }
132
133 #elif (defined(PIPE_SUBSYSTEM_WINDOWS_USER)) /* (defined(PIPE_ARCH_X86) && defined(PIPE_CC_MSVC)) */
134
135 struct pipe_atomic
136 {
137 long count;
138 };
139
140 #define p_atomic_set(_v, _i) ((_v)->count = (_i))
141 #define p_atomic_read(_v) ((_v)->count)
142
143 static INLINE boolean
144 p_atomic_dec_zero(struct pipe_atomic *v)
145 {
146 return InterlockedDecrement(&v->count);
147 }
148
149 static INLINE void
150 p_atomic_inc(struct pipe_atomic *v)
151 {
152 InterlockedIncrement(&v->count);
153 }
154
155 static INLINE void
156 p_atomic_dec(struct pipe_atomic *v)
157 {
158 InterlockedDecrement(&v->count);
159 }
160
161 static INLINE int32_t
162 p_atomic_cmpxchg(struct pipe_atomic *v, int32_t old, int32_t new)
163 {
164 return InterlockedCompareExchange(&v->count, new, old);
165 }
166
167 #else /* (defined(PIPE_SUBSYSTEM_WINDOWS_USER)) */
168
169 #include "pipe/p_thread.h"
170
171 /**
172 * This implementation should really not be used.
173 * Add an assembly port instead. It may abort and
174 * doesn't destroy used mutexes.
175 */
176
177 struct pipe_atomic {
178 pipe_mutex mutex;
179 int32_t count;
180 };
181
182 static INLINE void
183 p_atomic_set(struct pipe_atomic *v, int32_t i)
184 {
185 pipe_mutex_init(v->mutex);
186 pipe_mutex_lock(v->mutex);
187 v->count = i;
188 pipe_mutex_unlock(v->mutex);
189 }
190
191 static INLINE int32_t
192 p_atomic_read(struct pipe_atomic *v)
193 {
194 int32_t ret;
195
196 pipe_mutex_lock(v->mutex);
197 ret = v->count;
198 pipe_mutex_unlock(v->mutex);
199 return ret;
200 }
201
202 static INLINE void
203 p_atomic_inc(struct pipe_atomic *v)
204 {
205 pipe_mutex_lock(v->mutex);
206 ++v->count;
207 pipe_mutex_unlock(v->mutex);
208 }
209
210 static INLINE void
211 p_atomic_dec(struct pipe_atomic *v)
212 {
213 pipe_mutex_lock(v->mutex);
214 --v->count;
215 pipe_mutex_unlock(v->mutex);
216 }
217
218 static INLINE boolean
219 p_atomic_dec_zero(struct pipe_atomic *v)
220 {
221 boolean ret;
222
223 pipe_mutex_lock(v->mutex);
224 ret = (--v->count == 0);
225 pipe_mutex_unlock(v->mutex);
226 return ret;
227 }
228
229 static INLINE int32_t
230 p_atomic_cmpxchg(struct pipe_atomic *v, int32_t old, int32_t new)
231 {
232 int32_t ret;
233
234 pipe_mutex_lock(v->mutex);
235 ret = v->count;
236 if (ret == old)
237 v->count = new;
238 pipe_mutex_unlock(v->mutex);
239
240 return ret;
241 }
242
243 #endif /* (defined(PIPE_CC_GCC)) */
244
245 #ifdef __cplusplus
246 }
247 #endif
248
249 #endif /* P_ATOMIC_H */