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