gallium: Implement atomic interface for windows user mode subsystem.
[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_USER)) /* (defined(PIPE_CC_GCC)) */
70
71 struct pipe_atomic
72 {
73 long 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 return InterlockedDecrement(&v->count);
83 }
84
85 static INLINE void
86 p_atomic_inc(struct pipe_atomic *v)
87 {
88 InterlockedIncrement(&v->count);
89 }
90
91 static INLINE void
92 p_atomic_dec(struct pipe_atomic *v)
93 {
94 InterlockedDecrement(&v->count);
95 }
96
97 static INLINE int32_t
98 p_atomic_cmpxchg(struct pipe_atomic *v, int32_t old, int32_t new)
99 {
100 return InterlockedCompareExchange(&v->count, new, old);
101 }
102
103 #else /* (defined(PIPE_SUBSYSTEM_WINDOWS_USER)) */
104
105 #include "pipe/p_thread.h"
106
107 /**
108 * This implementation should really not be used.
109 * Add an assembly port instead. It may abort and
110 * doesn't destroy used mutexes.
111 */
112
113 struct pipe_atomic {
114 pipe_mutex mutex;
115 int32_t count;
116 };
117
118 static INLINE void
119 p_atomic_set(struct pipe_atomic *v, int32_t i)
120 {
121 pipe_mutex_init(v->mutex);
122 pipe_mutex_lock(v->mutex);
123 v->count = i;
124 pipe_mutex_unlock(v->mutex);
125 }
126
127 static INLINE int32_t
128 p_atomic_read(struct pipe_atomic *v)
129 {
130 int32_t ret;
131
132 pipe_mutex_lock(v->mutex);
133 ret = v->count;
134 pipe_mutex_unlock(v->mutex);
135 return ret;
136 }
137
138 static INLINE void
139 p_atomic_inc(struct pipe_atomic *v)
140 {
141 pipe_mutex_lock(v->mutex);
142 ++v->count;
143 pipe_mutex_unlock(v->mutex);
144 }
145
146 static INLINE void
147 p_atomic_dec(struct pipe_atomic *v)
148 {
149 pipe_mutex_lock(v->mutex);
150 --v->count;
151 pipe_mutex_unlock(v->mutex);
152 }
153
154 static INLINE boolean
155 p_atomic_dec_zero(struct pipe_atomic *v)
156 {
157 boolean ret;
158
159 pipe_mutex_lock(v->mutex);
160 ret = (--v->count == 0);
161 pipe_mutex_unlock(v->mutex);
162 return ret;
163 }
164
165 static INLINE int32_t
166 p_atomic_cmpxchg(struct pipe_atomic *v, int32_t old, int32_t new)
167 {
168 int32_t ret;
169
170 pipe_mutex_lock(v->mutex);
171 ret = v->count;
172 if (ret == old)
173 v->count = new;
174 pipe_mutex_unlock(v->mutex);
175
176 return ret;
177 }
178
179 #endif /* (defined(PIPE_CC_GCC)) */
180
181 #ifdef __cplusplus
182 }
183 #endif
184
185 #endif /* P_ATOMIC_H */