1 /*===========================================================================
2 *
3 * PUBLIC DOMAIN NOTICE
4 * National Center for Biotechnology Information
5 *
6 * This software/database is a "United States Government Work" under the
7 * terms of the United States Copyright Act. It was written as part of
8 * the author's official duties as a United States Government employee and
9 * thus cannot be copyrighted. This software/database is freely available
10 * to the public for use. The National Library of Medicine and the U.S.
11 * Government have not placed any restriction on its use or reproduction.
12 *
13 * Although all reasonable efforts have been taken to ensure the accuracy
14 * and reliability of the software and data, the NLM and the U.S.
15 * Government do not and cannot warrant the performance or results that
16 * may be obtained by using this software or data. The NLM and the U.S.
17 * Government disclaim all warranties, express or implied, including
18 * warranties of performance, merchantability or fitness for any particular
19 * purpose.
20 *
21 * Please cite the author in any work or product based on this material.
22 *
23 * ===========================================================================
24 *
25 */
26
27 #ifndef _h_atomic32_
28 #define _h_atomic32_
29
30 #ifdef __cplusplus
31 extern "C" {
32 #endif
33
34 /*
35 * Make sure gcc doesn't try to be clever and move things around
36 * on us. We need to use _exactly_ the address the user gave us,
37 * not some alias that contains the same information.
38 */
39 typedef struct atomic32_t atomic32_t;
40 struct atomic32_t
41 {
42 volatile int counter;
43 };
44
45 /* int atomic32_read ( const atomic32_t *v ); */
46 #define atomic32_read( v ) \
47 ( ( v ) -> counter )
48
49 /* void atomic32_set ( atomic32_t *v, int i ); */
50 #define atomic32_set( v, i ) \
51 ( ( void ) ( ( ( v ) -> counter ) = ( i ) ) )
52
53 /* add to v -> counter and return the prior value */
atomic32_read_and_add(atomic32_t * v,int i)54 static __inline__ int atomic32_read_and_add ( atomic32_t *v, int i )
55 {
56 int rtn, sum;
57 __asm__ __volatile__
58 (
59 "mov (%2), %0;"
60 "1:"
61 "mov %3, %1;"
62 "add %0, %1;"
63 "lock;"
64 "cmpxchg %1, (%2);"
65 "jne 1b"
66 : "=&a" ( rtn ), "=&r" ( sum )
67 : "r" ( & v -> counter ), "r" ( i )
68 );
69 return rtn;
70 }
71
72 /* if no read is needed, define the least expensive atomic add */
73 #define atomic32_add( v, i ) \
74 atomic32_read_and_add ( v, i )
75
76 /* add to v -> counter and return the result */
atomic32_add_and_read(atomic32_t * v,int i)77 static __inline__ int atomic32_add_and_read ( atomic32_t *v, int i )
78 {
79 int rtn, cmp;
80 __asm__ __volatile__
81 (
82 "mov (%2), %0;"
83 "1:"
84 "mov %3, %1;"
85 "add %0, %1;"
86 "lock;"
87 "cmpxchg %1,(%2);"
88 "jne 1b;"
89 : "=&a" ( cmp ), "=&r" ( rtn )
90 : "r" ( & v -> counter ), "r" ( i )
91 );
92 return rtn;
93 }
94
95 /* just don't try to find out what the result was */
atomic32_inc(atomic32_t * v)96 static __inline__ void atomic32_inc ( atomic32_t *v )
97 {
98 __asm__ __volatile__
99 (
100 "lock;"
101 "incl %0"
102 : "=m" ( v -> counter )
103 : "m" ( v -> counter )
104 );
105 }
106
atomic32_dec(atomic32_t * v)107 static __inline__ void atomic32_dec ( atomic32_t *v )
108 {
109 __asm__ __volatile__
110 (
111 "lock;"
112 "decl %0"
113 : "=m" ( v -> counter )
114 : "m" ( v -> counter )
115 );
116 }
117
118 /* decrement by one and test result for 0 */
atomic32_dec_and_test(atomic32_t * v)119 static __inline__ int atomic32_dec_and_test ( atomic32_t *v )
120 {
121 unsigned char c;
122 __asm__ __volatile__
123 (
124 "lock;"
125 "decl %1;"
126 "sete %0"
127 : "=r" ( c ), "=m" ( v -> counter )
128 : "m" ( v -> counter )
129 );
130 return c;
131 }
132
133 /* when atomic32_dec_and_test uses predecrement, you want
134 postincrement to this function. so it isn't very useful */
atomic32_inc_and_test(atomic32_t * v)135 static __inline__ int atomic32_inc_and_test ( atomic32_t *v )
136 {
137 unsigned char c;
138 __asm__ __volatile__
139 (
140 "lock;"
141 "incl %1;"
142 "sete %0"
143 : "=r" ( c ), "=m" ( v -> counter )
144 : "m" ( v -> counter )
145 );
146 return c;
147 }
148
149 /* HERE's useful */
150 #define atomic32_test_and_inc( v ) \
151 ( atomic32_read_and_add ( v, 1 ) == 0 )
152
atomic32_test_and_set(atomic32_t * v,int s,int t)153 static __inline__ int atomic32_test_and_set ( atomic32_t *v, int s, int t )
154 {
155 int rtn;
156 __asm__ __volatile__
157 (
158 "lock;"
159 "cmpxchg %2, (%1)"
160 : "=a" ( rtn )
161 : "r" ( & v -> counter ), "r" ( s ), "a" ( t )
162 );
163 return rtn;
164 }
165
166 /* conditional modifications */
167 static __inline__
atomic32_read_and_add_lt(atomic32_t * v,int i,int t)168 int atomic32_read_and_add_lt ( atomic32_t *v, int i, int t )
169 {
170 int rtn, sum;
171 __asm__ __volatile__
172 (
173 "mov (%2), %0;"
174 "1:"
175 "cmp %4, %0;"
176 "mov %3, %1;"
177 "jge 2f;"
178 "add %0, %1;"
179 "lock;"
180 "cmpxchg %1, (%2);"
181 "jne 1b;"
182 "2:"
183 : "=&a" ( rtn ), "=&r" ( sum )
184 : "r" ( & v -> counter ), "r" ( i ), "r" ( t )
185 );
186 return rtn;
187 }
188
189 #define atomic32_add_if_lt( v, i, t ) \
190 ( atomic32_read_and_add_lt ( v, i, t ) < ( t ) )
191
192 static __inline__
atomic32_read_and_add_le(atomic32_t * v,int i,int t)193 int atomic32_read_and_add_le ( atomic32_t *v, int i, int t )
194 {
195 int rtn, sum;
196 __asm__ __volatile__
197 (
198 "mov (%2), %0;"
199 "1:"
200 "cmp %4, %0;"
201 "mov %3, %1;"
202 "jg 2f;"
203 "add %0, %1;"
204 "lock;"
205 "cmpxchg %1, (%2);"
206 "jne 1b;"
207 "2:"
208 : "=&a" ( rtn ), "=&r" ( sum )
209 : "r" ( & v -> counter ), "r" ( i ), "r" ( t )
210 );
211 return rtn;
212 }
213
214 #define atomic32_add_if_le( v, i, t ) \
215 ( atomic32_read_and_add_le ( v, i, t ) <= ( t ) )
216
217 static __inline__
atomic32_read_and_add_eq(atomic32_t * v,int i,int t)218 int atomic32_read_and_add_eq ( atomic32_t *v, int i, int t )
219 {
220 int rtn, sum;
221 __asm__ __volatile__
222 (
223 "mov (%2), %0;"
224 "1:"
225 "cmp %4, %0;"
226 "mov %3, %1;"
227 "jne 2f;"
228 "add %0, %1;"
229 "lock;"
230 "cmpxchg %1, (%2);"
231 "jne 1b;"
232 "2:"
233 : "=&a" ( rtn ), "=&r" ( sum )
234 : "r" ( & v -> counter ), "r" ( i ), "r" ( t )
235 );
236 return rtn;
237 }
238
239 #define atomic32_add_if_eq( v, i, t ) \
240 ( atomic32_read_and_add_eq ( v, i, t ) == ( t ) )
241
242 static __inline__
atomic32_read_and_add_ne(atomic32_t * v,int i,int t)243 int atomic32_read_and_add_ne ( atomic32_t *v, int i, int t )
244 {
245 int rtn, sum;
246 __asm__ __volatile__
247 (
248 "mov (%2), %0;"
249 "1:"
250 "cmp %4, %0;"
251 "mov %3, %1;"
252 "je 2f;"
253 "add %0, %1;"
254 "lock;"
255 "cmpxchg %1, (%2);"
256 "jne 1b;"
257 "2:"
258 : "=&a" ( rtn ), "=&r" ( sum )
259 : "r" ( & v -> counter ), "r" ( i ), "r" ( t )
260 );
261 return rtn;
262 }
263
264 #define atomic32_add_if_ne( v, i, t ) \
265 ( atomic32_read_and_add_ne ( v, i, t ) != ( t ) )
266
267 static __inline__
atomic32_read_and_add_ge(atomic32_t * v,int i,int t)268 int atomic32_read_and_add_ge ( atomic32_t *v, int i, int t )
269 {
270 int rtn, sum;
271 __asm__ __volatile__
272 (
273 "mov (%2), %0;"
274 "1:"
275 "cmp %4, %0;"
276 "mov %3, %1;"
277 "jl 2f;"
278 "add %0, %1;"
279 "lock;"
280 "cmpxchg %1, (%2);"
281 "jne 1b;"
282 "2:"
283 : "=&a" ( rtn ), "=&r" ( sum )
284 : "r" ( & v -> counter ), "r" ( i ), "r" ( t )
285 );
286 return rtn;
287 }
288
289 #define atomic32_add_if_ge( v, i, t ) \
290 ( atomic32_read_and_add_ge ( v, i, t ) >= ( t ) )
291
292 static __inline__
atomic32_read_and_add_gt(atomic32_t * v,int i,int t)293 int atomic32_read_and_add_gt ( atomic32_t *v, int i, int t )
294 {
295 int rtn, sum;
296 __asm__ __volatile__
297 (
298 "mov (%2), %0;"
299 "1:"
300 "cmp %4, %0;"
301 "mov %3, %1;"
302 "jle 2f;"
303 "add %0, %1;"
304 "lock;"
305 "cmpxchg %1, (%2);"
306 "jne 1b;"
307 "2:"
308 : "=&a" ( rtn ), "=&r" ( sum )
309 : "r" ( & v -> counter ), "r" ( i ), "r" ( t )
310 );
311 return rtn;
312 }
313
314 #define atomic32_add_if_gt( v, i, t ) \
315 ( atomic32_read_and_add_gt ( v, i, t ) > ( t ) )
316
317 static __inline__
atomic32_read_and_add_odd(atomic32_t * v,int i)318 int atomic32_read_and_add_odd ( atomic32_t *v, int i )
319 {
320 int rtn, sum;
321 __asm__ __volatile__
322 (
323 "mov (%2), %0;"
324 "1:"
325 "bt $0, %0;"
326 "mov %3, %1;"
327 "jnc 2f;"
328 "add %0, %1;"
329 "lock;"
330 "cmpxchg %1, (%2);"
331 "jne 1b;"
332 "2:"
333 : "=&a" ( rtn ), "=&r" ( sum )
334 : "r" ( & v -> counter ), "r" ( i )
335 );
336 return rtn;
337 }
338
339 static __inline__
atomic32_read_and_add_even(atomic32_t * v,int i)340 int atomic32_read_and_add_even ( atomic32_t *v, int i )
341 {
342 int rtn, sum;
343 __asm__ __volatile__
344 (
345 "mov (%2), %0;"
346 "1:"
347 "bt $0, %0;"
348 "mov %3, %1;"
349 "jc 2f;"
350 "add %0, %1;"
351 "lock;"
352 "cmpxchg %1, (%2);"
353 "jne 1b;"
354 "2:"
355 : "=&a" ( rtn ), "=&r" ( sum )
356 : "r" ( & v -> counter ), "r" ( i )
357 );
358 return rtn;
359 }
360
361
362 #ifdef __cplusplus
363 }
364 #endif
365
366 #endif /* _h_atomic32_ */
367