suricata
util-atomic.h
Go to the documentation of this file.
1 /* Copyright (C) 2007-2020 Open Information Security Foundation
2  *
3  * You can copy, redistribute or modify this Program under the terms of
4  * the GNU General Public License version 2 as published by the Free
5  * Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * version 2 along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15  * 02110-1301, USA.
16  */
17 
18 /**
19  * \file
20  *
21  * \author Victor Julien <victor@inliniac.net>
22  * \author Pablo Rincon <pablo.rincon.crespo@gmail.com>
23  *
24  * API for atomic operations. Uses C11 atomic instructions
25  * where available, GCC/clang specific (gnu99) operations otherwise.
26  *
27  * To prevent developers from accidentally working with the atomic variables
28  * directly instead of through the proper macro's, a marco trick is performed
29  * that exposes different variable names than the developer uses. So if the dev
30  * uses "somevar", internally "somevar_sc_atomic__" is used.
31  */
32 
33 
34 #ifndef __UTIL_ATOMIC_H__
35 #define __UTIL_ATOMIC_H__
36 
37 #if HAVE_STDATOMIC_H==1
38 
39 #include <stdatomic.h>
40 
41 /**
42  * \brief wrapper for declaring atomic variables.
43  *
44  * \param type Type of the variable (char, short, int, long, long long)
45  * \param name Name of the variable.
46  *
47  * We just declare the variable here as we rely on atomic operations
48  * to modify it, so no need for locks.
49  *
50  * \warning variable is not initialized
51  */
52 #define SC_ATOMIC_DECLARE(type, name) \
53  _Atomic(type) name ## _sc_atomic__
54 
55 /**
56  * \brief wrapper for referencing an atomic variable declared on another file.
57  *
58  * \param type Type of the variable (char, short, int, long, long long)
59  * \param name Name of the variable.
60  *
61  * We just declare the variable here as we rely on atomic operations
62  * to modify it, so no need for locks.
63  *
64  */
65 #define SC_ATOMIC_EXTERN(type, name) \
66  extern _Atomic(type) (name ## _sc_atomic__)
67 
68 /**
69  * \brief wrapper for declaring an atomic variable and initializing it.
70  **/
71 #define SC_ATOMIC_DECL_AND_INIT(type, name) \
72  _Atomic(type) (name ## _sc_atomic__) = 0
73 
74 /**
75  * \brief wrapper for initializing an atomic variable.
76  **/
77 #define SC_ATOMIC_INIT(name) \
78  (name ## _sc_atomic__) = 0
79 #define SC_ATOMIC_INITPTR(name) \
80  (name ## _sc_atomic__) = NULL
81 
82 /**
83  * \brief wrapper for reinitializing an atomic variable.
84  **/
85 #define SC_ATOMIC_RESET(name) \
86  SC_ATOMIC_INIT(name)
87 
88 /**
89  * \brief add a value to our atomic variable
90  *
91  * \param name the atomic variable
92  * \param val the value to add to the variable
93  */
94 #define SC_ATOMIC_ADD(name, val) \
95  atomic_fetch_add(&(name ## _sc_atomic__), (val))
96 
97 /**
98  * \brief sub a value from our atomic variable
99  *
100  * \param name the atomic variable
101  * \param val the value to sub from the variable
102  */
103 #define SC_ATOMIC_SUB(name, val) \
104  atomic_fetch_sub(&(name ## _sc_atomic__), (val))
105 
106 /**
107  * \brief Bitwise OR a value to our atomic variable
108  *
109  * \param name the atomic variable
110  * \param val the value to OR to the variable
111  */
112 #define SC_ATOMIC_OR(name, val) \
113  atomic_fetch_or(&(name ## _sc_atomic__), (val))
114 
115 /**
116  * \brief Bitwise AND a value to our atomic variable
117  *
118  * \param name the atomic variable
119  * \param val the value to AND to the variable
120  */
121 #define SC_ATOMIC_AND(name, val) \
122  atomic_fetch_and(&(name ## _sc_atomic__), (val))
123 
124 /**
125  * \brief atomic Compare and Switch
126  *
127  * \warning "name" is passed to us as "&var"
128  */
129 #define SC_ATOMIC_CAS(name, cmpval, newval) \
130  atomic_compare_exchange_strong((name ## _sc_atomic__), &(cmpval), (newval))
131 
132 /**
133  * \brief Get the value from the atomic variable.
134  *
135  * \retval var value
136  */
137 #define SC_ATOMIC_GET(name) \
138  atomic_load(&(name ## _sc_atomic__))
139 
140 /**
141  * \brief Set the value for the atomic variable.
142  *
143  * \retval var value
144  */
145 #define SC_ATOMIC_SET(name, val) \
146  atomic_store(&(name ## _sc_atomic__), (val))
147 
148 #else
149 
150 /**
151  * \brief wrapper for OS/compiler specific atomic compare and swap (CAS)
152  * function.
153  *
154  * \param addr Address of the variable to CAS
155  * \param tv Test value to compare the value at address against
156  * \param nv New value to set the variable at addr to
157  *
158  * \retval 0 CAS failed
159  * \retval 1 CAS succeeded
160  */
161 #define SCAtomicCompareAndSwap(addr, tv, nv) \
162  __sync_bool_compare_and_swap((addr), (tv), (nv))
163 
164 /**
165  * \brief wrapper for OS/compiler specific atomic fetch and add
166  * function.
167  *
168  * \param addr Address of the variable to add to
169  * \param value Value to add to the variable at addr
170  */
171 #define SCAtomicFetchAndAdd(addr, value) \
172  __sync_fetch_and_add((addr), (value))
173 
174 /**
175  * \brief wrapper for OS/compiler specific atomic fetch and sub
176  * function.
177  *
178  * \param addr Address of the variable to add to
179  * \param value Value to sub from the variable at addr
180  */
181 #define SCAtomicFetchAndSub(addr, value) \
182  __sync_fetch_and_sub((addr), (value))
183 
184 /**
185  * \brief wrapper for OS/compiler specific atomic fetch and add
186  * function.
187  *
188  * \param addr Address of the variable to add to
189  * \param value Value to add to the variable at addr
190  */
191 #define SCAtomicAddAndFetch(addr, value) \
192  __sync_add_and_fetch((addr), (value))
193 
194 /**
195  * \brief wrapper for OS/compiler specific atomic fetch and sub
196  * function.
197  *
198  * \param addr Address of the variable to add to
199  * \param value Value to sub from the variable at addr
200  */
201 #define SCAtomicSubAndFetch(addr, value) \
202  __sync_sub_and_fetch((addr), (value))
203 
204 /**
205  * \brief wrapper for OS/compiler specific atomic fetch and "AND"
206  * function.
207  *
208  * \param addr Address of the variable to AND to
209  * \param value Value to add to the variable at addr
210  */
211 #define SCAtomicFetchAndAnd(addr, value) \
212  __sync_fetch_and_and((addr), (value))
213 
214 /**
215  * \brief wrapper for OS/compiler specific atomic fetch and "NAND"
216  * function.
217  *
218  * \param addr Address of the variable to NAND to
219  * \param value Value to add to the variable at addr
220  */
221 #define SCAtomicFetchAndNand(addr, value) \
222  __sync_fetch_and_nand((addr), (value))
223 
224 /**
225  * \brief wrapper for OS/compiler specific atomic fetch and "XOR"
226  * function.
227  *
228  * \param addr Address of the variable to XOR to
229  * \param value Value to add to the variable at addr
230  */
231 #define SCAtomicFetchAndXor(addr, value) \
232  __sync_fetch_and_xor((addr), (value))
233 
234 /**
235  * \brief wrapper for OS/compiler specific atomic fetch and or
236  * function.
237  *
238  * \param addr Address of the variable to or to
239  * \param value Value to add to the variable at addr
240  */
241 #define SCAtomicFetchAndOr(addr, value) \
242  __sync_fetch_and_or((addr), (value))
243 
244 /**
245  * \brief wrapper for declaring atomic variables.
246  *
247  * \warning Only char, short, int, long, long long and their unsigned
248  * versions are supported.
249  *
250  * \param type Type of the variable (char, short, int, long, long long)
251  * \param name Name of the variable.
252  *
253  * We just declare the variable here as we rely on atomic operations
254  * to modify it, so no need for locks.
255  *
256  * \warning variable is not initialized
257  */
258 #define SC_ATOMIC_DECLARE(type, name) \
259  type name ## _sc_atomic__
260 
261 /**
262  * \brief wrapper for referencing an atomic variable declared on another file.
263  *
264  * \warning Only char, short, int, long, long long and their unsigned
265  * versions are supported.
266  *
267  * \param type Type of the variable (char, short, int, long, long long)
268  * \param name Name of the variable.
269  *
270  * We just declare the variable here as we rely on atomic operations
271  * to modify it, so no need for locks.
272  *
273  */
274 #define SC_ATOMIC_EXTERN(type, name) \
275  extern type name ## _sc_atomic__
276 
277 /**
278  * \brief wrapper for declaring an atomic variable and initializing it.
279  **/
280 #define SC_ATOMIC_DECL_AND_INIT(type, name) \
281  type name ## _sc_atomic__ = 0
282 
283 /**
284  * \brief wrapper for initializing an atomic variable.
285  **/
286 #define SC_ATOMIC_INIT(name) \
287  (name ## _sc_atomic__) = 0
288 
289 #define SC_ATOMIC_INITPTR(name) \
290  (name ## _sc_atomic__) = NULL
291 
292 /**
293  * \brief wrapper for reinitializing an atomic variable.
294  **/
295 #define SC_ATOMIC_RESET(name) \
296  (name ## _sc_atomic__) = 0
297 
298 /**
299  * \brief add a value to our atomic variable
300  *
301  * \param name the atomic variable
302  * \param val the value to add to the variable
303  */
304 #define SC_ATOMIC_ADD(name, val) \
305  SCAtomicFetchAndAdd(&(name ## _sc_atomic__), (val))
306 
307 /**
308  * \brief sub a value from our atomic variable
309  *
310  * \param name the atomic variable
311  * \param val the value to sub from the variable
312  */
313 #define SC_ATOMIC_SUB(name, val) \
314  SCAtomicFetchAndSub(&(name ## _sc_atomic__), (val))
315 
316 /**
317  * \brief Bitwise OR a value to our atomic variable
318  *
319  * \param name the atomic variable
320  * \param val the value to OR to the variable
321  */
322 #define SC_ATOMIC_OR(name, val) \
323  SCAtomicFetchAndOr(&(name ## _sc_atomic__), (val))
324 
325 /**
326  * \brief Bitwise AND a value to our atomic variable
327  *
328  * \param name the atomic variable
329  * \param val the value to AND to the variable
330  */
331 #define SC_ATOMIC_AND(name, val) \
332  SCAtomicFetchAndAnd(&(name ## _sc_atomic__), (val))
333 
334 /**
335  * \brief atomic Compare and Switch
336  *
337  * \warning "name" is passed to us as "&var"
338  */
339 #define SC_ATOMIC_CAS(name, cmpval, newval) \
340  SCAtomicCompareAndSwap((name ## _sc_atomic__), cmpval, newval)
341 
342 /**
343  * \brief Get the value from the atomic variable.
344  *
345  * \retval var value
346  */
347 #define SC_ATOMIC_GET(name) \
348  (name ## _sc_atomic__)
349 
350 /**
351  * \brief Set the value for the atomic variable.
352  *
353  * \retval var value
354  */
355 #define SC_ATOMIC_SET(name, val) ({ \
356  while (SC_ATOMIC_CAS(&name, SC_ATOMIC_GET(name), val) == 0) \
357  ; \
358  })
359 
360 #endif /* no c11 atomics */
361 
362 void SCAtomicRegisterTests(void);
363 
364 #endif /* __UTIL_ATOMIC_H__ */
365 
SCAtomicRegisterTests
void SCAtomicRegisterTests(void)
Definition: util-atomic.c:67