gallium: Add simple atomic class api.
[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_defines.h"
13 #include <stdint.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 #else /* (defined(PIPE_CC_GCC)) */
70
71 #include "pipe/p_thread.h"
72
73 /**
74 * This implementation should really not be used.
75 * Add an assembly port instead. It may abort and
76 * doesn't destroy used mutexes.
77 */
78
79 struct pipe_atomic {
80 pipe_mutex mutex;
81 int32_t count;
82 };
83
84 static INLINE void
85 p_atomic_set(struct pipe_atomic *v, int32_t i)
86 {
87 int ret;
88 ret = pipe_mutex_init(v->mutex);
89 if (ret)
90 abort();
91 pipe_mutex_lock(v->mutex);
92 v->count = i;
93 pipe_mutex_unlock(v->mutex);
94 }
95
96 static INLINE int32_t
97 p_atomic_read(struct pipe_atomic *v)
98 {
99 int32_t ret;
100
101 pipe_mutex_lock(v->mutex);
102 ret = v->count;
103 pipe_mutex_unlock(v->mutex);
104 return ret;
105 }
106
107 static INLINE void
108 p_atomic_inc(struct pipe_atomic *v)
109 {
110 pipe_mutex_lock(v->mutex);
111 ++v->count;
112 pipe_mutex_unlock(v->mutex);
113 }
114
115 static INLINE void
116 p_atomic_dec(struct pipe_atomic *v)
117 {
118 pipe_mutex_lock(v->mutex);
119 --v->count;
120 pipe_mutex_unlock(v->mutex);
121 }
122
123 static INLINE boolean
124 p_atomic_dec_zero(struct pipe_atomic *v)
125 {
126 boolean ret;
127
128 pipe_mutex_lock(v->mutex);
129 ret = (--v->count == 0);
130 pipe_mutex_unlock(v->mutex);
131 return ret;
132 }
133
134 static INLINE int32_t
135 p_atomic_cmpxchg(struct pipe_atomic *v, int32_t old, int32_t new)
136 {
137 int32_t ret;
138
139 pipe_mutex_lock(v->mutex);
140 ret = v->count;
141 if (ret == old)
142 v->count = new;
143 pipe_mutex_unlock(v->mutex);
144
145 return ret;
146 }
147
148 #endif /* (defined(PIPE_CC_GCC)) */
149
150 #ifdef __cplusplus
151 }
152 #endif
153
154 #endif /* P_ATOMIC_H */