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 return __sync_fetch_and_add( & v -> counter, i );
57 }
58
59 /* if no read is needed, define the least expensive atomic add */
60 #define atomic32_add( v, i ) \
61 atomic32_read_and_add ( v, i )
62
63 /* add to v -> counter and return the result */
atomic32_add_and_read(atomic32_t * v,int i)64 static __inline__ int atomic32_add_and_read ( atomic32_t *v, int i )
65 {
66 return __sync_add_and_fetch( & v -> counter, i );
67 }
68
69 /* just don't try to find out what the result was */
atomic32_inc(atomic32_t * v)70 static __inline__ void atomic32_inc ( atomic32_t *v )
71 {
72 atomic32_add( v, 1 );
73 }
74
atomic32_dec(atomic32_t * v)75 static __inline__ void atomic32_dec ( atomic32_t *v )
76 {
77 atomic32_add( v, -1 );
78 }
79
80 /* decrement by one and test result for 0 */
atomic32_dec_and_test(atomic32_t * v)81 static __inline__ int atomic32_dec_and_test ( atomic32_t *v )
82 {
83 return __sync_add_and_fetch( & v -> counter, -1 ) == 0;
84 }
85
86 /* when atomic32_dec_and_test uses predecrement, you want
87 postincrement to this function. so it isn't very useful */
atomic32_inc_and_test(atomic32_t * v)88 static __inline__ int atomic32_inc_and_test ( atomic32_t *v )
89 {
90 return __sync_add_and_fetch( & v -> counter, 1 ) == 0;
91 }
92
93 /* HERE's useful */
94 #define atomic32_test_and_inc( v ) \
95 ( atomic32_read_and_add ( v, 1 ) == 0 )
96
atomic32_test_and_set(atomic32_t * v,int newval,int oldval)97 static __inline__ int atomic32_test_and_set ( atomic32_t *v, int newval, int oldval )
98 {
99 return __sync_val_compare_and_swap( & v -> counter, oldval, newval ); //NB: newval/oldval switched around
100 }
101
102 /* conditional modifications */
103 static __inline__
atomic32_read_and_add_lt(atomic32_t * v,int i,int t)104 int atomic32_read_and_add_lt ( atomic32_t *v, int i, int t )
105 {
106 int val, val_intern;
107 for ( val = atomic32_read ( v ); val < t; val = val_intern )
108 {
109 val_intern = atomic32_test_and_set ( v, val + i, val );
110 if ( val_intern == val )
111 break;
112 }
113 return val;
114 }
115
116 #define atomic32_add_if_lt( v, i, t ) \
117 ( atomic32_read_and_add_lt ( v, i, t ) < ( t ) )
118
119 static __inline__
atomic32_read_and_add_le(atomic32_t * v,int i,int t)120 int atomic32_read_and_add_le ( atomic32_t *v, int i, int t )
121 {
122 int val, val_intern;
123 for ( val = atomic32_read ( v ); val <= t; val = val_intern )
124 {
125 val_intern = atomic32_test_and_set ( v, val + i, val );
126 if ( val_intern == val )
127 break;
128 }
129 return val;
130 }
131
132 #define atomic32_add_if_le( v, i, t ) \
133 ( atomic32_read_and_add_le ( v, i, t ) <= ( t ) )
134
135 static __inline__
atomic32_read_and_add_eq(atomic32_t * v,int i,int t)136 int atomic32_read_and_add_eq ( atomic32_t *v, int i, int t )
137 {
138 int val, val_intern;
139 for ( val = atomic32_read ( v ); val == t; val = val_intern )
140 {
141 val_intern = atomic32_test_and_set ( v, val + i, val );
142 if ( val_intern == val )
143 break;
144 }
145 return val;
146 }
147
148 #define atomic32_add_if_eq( v, i, t ) \
149 ( atomic32_read_and_add_eq ( v, i, t ) == ( t ) )
150
151 static __inline__
atomic32_read_and_add_ne(atomic32_t * v,int i,int t)152 int atomic32_read_and_add_ne ( atomic32_t *v, int i, int t )
153 {
154 int val, val_intern;
155 for ( val = atomic32_read ( v ); val != t; val = val_intern )
156 {
157 val_intern = atomic32_test_and_set ( v, val + i, val );
158 if ( val_intern == val )
159 break;
160 }
161 return val;
162 }
163
164 #define atomic32_add_if_ne( v, i, t ) \
165 ( atomic32_read_and_add_ne ( v, i, t ) != ( t ) )
166
167 static __inline__
atomic32_read_and_add_ge(atomic32_t * v,int i,int t)168 int atomic32_read_and_add_ge ( atomic32_t *v, int i, int t )
169 {
170 int val, val_intern;
171 for ( val = atomic32_read ( v ); val >= t; val = val_intern )
172 {
173 val_intern = atomic32_test_and_set ( v, val + i, val );
174 if ( val_intern == val )
175 break;
176 }
177 return val;
178 }
179
180 #define atomic32_add_if_ge( v, i, t ) \
181 ( atomic32_read_and_add_ge ( v, i, t ) >= ( t ) )
182
183 static __inline__
atomic32_read_and_add_gt(atomic32_t * v,int i,int t)184 int atomic32_read_and_add_gt ( atomic32_t *v, int i, int t )
185 {
186 int val, val_intern;
187 for ( val = atomic32_read ( v ); val > t; val = val_intern )
188 {
189 val_intern = atomic32_test_and_set ( v, val + i, val );
190 if ( val_intern == val )
191 break;
192 }
193 return val;
194 }
195
196 #define atomic32_add_if_gt( v, i, t ) \
197 ( atomic32_read_and_add_gt ( v, i, t ) > ( t ) )
198
199 static __inline__
atomic32_read_and_add_odd(atomic32_t * v,int i)200 int atomic32_read_and_add_odd ( atomic32_t *v, int i )
201 {
202 int val, val_intern;
203 for ( val = atomic32_read ( v ); val & 1; val = val_intern )
204 {
205 val_intern = atomic32_test_and_set ( v, val + i, val );
206 if ( val_intern == val )
207 break;
208 }
209 return val;
210 }
211
212 static __inline__
atomic32_read_and_add_even(atomic32_t * v,int i)213 int atomic32_read_and_add_even ( atomic32_t *v, int i )
214 {
215 int val, val_intern;
216 for ( val = atomic32_read ( v ); ! (val & 1); val = val_intern )
217 {
218 val_intern = atomic32_test_and_set ( v, val + i, val );
219 if ( val_intern == val )
220 break;
221 }
222 return val;
223 }
224
225 #ifdef __cplusplus
226 }
227 #endif
228
229 #endif /* _h_atomic32_ */
230