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 #ifdef __cplusplus
362 }
363 #endif
364 
365 #endif /* _h_atomic32_ */
366