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_atomic64_
28 #define _h_atomic64_
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 atomic64_t atomic64_t;
40 struct atomic64_t
41 {
42     volatile long int counter;
43 };
44 
45 /* int atomic64_read ( const atomic64_t *v ); */
46 #define atomic64_read( v ) \
47     ( ( v ) -> counter )
48 
49 /* void atomic64_set ( atomic64_t *v, long int i ); */
50 #define atomic64_set( v, i ) \
51     ( ( void ) ( ( ( v ) -> counter ) = ( i ) ) )
52 
53 /* add to v -> counter and return the prior value */
atomic64_read_and_add(atomic64_t * v,long int i)54 static __inline__ long int atomic64_read_and_add ( atomic64_t *v, long 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 atomic64_add( v, i ) \
61     atomic64_read_and_add ( v, i )
62 
63 /* add to v -> counter and return the result */
atomic64_add_and_read(atomic64_t * v,long int i)64 static __inline__ long int atomic64_add_and_read ( atomic64_t *v, long 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 */
atomic64_inc(atomic64_t * v)70 static __inline__ void atomic64_inc ( atomic64_t *v )
71 {
72     atomic64_add( v, 1 );
73 }
74 
atomic64_dec(atomic64_t * v)75 static __inline__ void atomic64_dec ( atomic64_t *v )
76 {
77     atomic64_add( v, -1 );
78 }
79 
80 /* decrement by one and test result for 0 */
atomic64_dec_and_test(atomic64_t * v)81 static __inline__ int atomic64_dec_and_test ( atomic64_t *v )
82 {
83     return __sync_add_and_fetch( & v -> counter, -1 ) == 0;
84 }
85 
86 /* when atomic64_dec_and_test uses predecrement, you want
87    postincrement to this function. so it isn't very useful */
atomic64_inc_and_test(atomic64_t * v)88 static __inline__ int atomic64_inc_and_test ( atomic64_t *v )
89 {
90     return __sync_add_and_fetch( & v -> counter, 1 ) == 0;
91 }
92 
93 /* HERE's useful */
94 #define atomic64_test_and_inc( v ) \
95     ( atomic64_read_and_add ( v, 1L ) == 0 )
96 
atomic64_test_and_set(atomic64_t * v,long int newval,long int oldval)97 static __inline__ long int atomic64_test_and_set ( atomic64_t *v, long int newval, long 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__
atomic64_read_and_add_lt(atomic64_t * v,long int i,long int t)104 long int atomic64_read_and_add_lt ( atomic64_t *v, long int i, long int t )
105 {
106 	int val, val_intern;
107 	for ( val = atomic64_read ( v ); val < t; val = val_intern )
108 	{
109 		val_intern = atomic64_test_and_set ( v, val + i, val );
110 		if ( val_intern == val )
111 			break;
112 	}
113 	return val;
114 }
115 
116 #define atomic64_add_if_lt( v, i, t ) \
117     ( atomic64_read_and_add_lt ( v, i, t ) < ( t ) )
118 
119 static __inline__
atomic64_read_and_add_le(atomic64_t * v,long int i,long int t)120 long int atomic64_read_and_add_le ( atomic64_t *v, long int i, long int t )
121 {
122 	int val, val_intern;
123 	for ( val = atomic64_read ( v ); val <= t; val = val_intern )
124 	{
125 		val_intern = atomic64_test_and_set ( v, val + i, val );
126 		if ( val_intern == val )
127 			break;
128 	}
129 	return val;
130 }
131 
132 #define atomic64_add_if_le( v, i, t ) \
133     ( atomic64_read_and_add_le ( v, i, t ) <= ( t ) )
134 
135 static __inline__
atomic64_read_and_add_eq(atomic64_t * v,long int i,long int t)136 long int atomic64_read_and_add_eq ( atomic64_t *v, long int i, long int t )
137 {
138 	int val, val_intern;
139 	for ( val = atomic64_read ( v ); val == t; val = val_intern )
140 	{
141 		val_intern = atomic64_test_and_set ( v, val + i, val );
142 		if ( val_intern == val )
143 			break;
144 	}
145 	return val;
146 }
147 
148 #define atomic64_add_if_eq( v, i, t ) \
149     ( atomic64_read_and_add_eq ( v, i, t ) == ( t ) )
150 
151 static __inline__
atomic64_read_and_add_ne(atomic64_t * v,long int i,long int t)152 long int atomic64_read_and_add_ne ( atomic64_t *v, long int i, long int t )
153 {
154 	int val, val_intern;
155 	for ( val = atomic64_read ( v ); val != t; val = val_intern )
156 	{
157 		val_intern = atomic64_test_and_set ( v, val + i, val );
158 		if ( val_intern == val )
159 			break;
160 	}
161 	return val;
162 }
163 
164 #define atomic64_add_if_ne( v, i, t ) \
165     ( atomic64_read_and_add_ne ( v, i, t ) != ( t ) )
166 
167 static __inline__
atomic64_read_and_add_ge(atomic64_t * v,long int i,long int t)168 long int atomic64_read_and_add_ge ( atomic64_t *v, long int i, long int t )
169 {
170 	int val, val_intern;
171 	for ( val = atomic64_read ( v ); val >= t; val = val_intern )
172 	{
173 		val_intern = atomic64_test_and_set ( v, val + i, val );
174 		if ( val_intern == val )
175 			break;
176 	}
177 	return val;
178 }
179 
180 #define atomic64_add_if_ge( v, i, t ) \
181     ( atomic64_read_and_add_ge ( v, i, t ) >= ( t ) )
182 
183 static __inline__
atomic64_read_and_add_gt(atomic64_t * v,long int i,long int t)184 long int atomic64_read_and_add_gt ( atomic64_t *v, long int i, long int t )
185 {
186 	int val, val_intern;
187 	for ( val = atomic64_read ( v ); val > t; val = val_intern )
188 	{
189 		val_intern = atomic64_test_and_set ( v, val + i, val );
190 		if ( val_intern == val )
191 			break;
192 	}
193 	return val;
194 }
195 
196 #define atomic64_add_if_gt( v, i, t ) \
197     ( atomic64_read_and_add_gt ( v, i, t ) > ( t ) )
198 
199 static __inline__
atomic64_read_and_add_odd(atomic64_t * v,long int i)200 long int atomic64_read_and_add_odd ( atomic64_t *v, long int i )
201 {
202 	int val, val_intern;
203 	for ( val = atomic64_read ( v ); val & 1; val = val_intern )
204 	{
205 		val_intern = atomic64_test_and_set ( v, val + i, val );
206 		if ( val_intern == val )
207 			break;
208 	}
209 	return val;
210 }
211 
212 static __inline__
atomic64_read_and_add_even(atomic64_t * v,long int i)213 long int atomic64_read_and_add_even ( atomic64_t *v, long int i )
214 {
215 	int val, val_intern;
216 	for ( val = atomic64_read ( v ); ! ( val & 1 ); val = val_intern )
217 	{
218 		val_intern = atomic64_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_atomic64_ */
230