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#ifndef SURICATA_UTIL_ATOMIC_H
34#define SURICATA_UTIL_ATOMIC_H
35
36#if HAVE_STDATOMIC_H==1
37
38#include <stdatomic.h>
39
40#define SC_ATOMIC_MEMORY_ORDER_RELAXED memory_order_relaxed
41#define SC_ATOMIC_MEMORY_ORDER_CONSUME memory_order_consume
42#define SC_ATOMIC_MEMORY_ORDER_ACQUIRE memory_order_acquire
43#define SC_ATOMIC_MEMORY_ORDER_RELEASE memory_order_release
44#define SC_ATOMIC_MEMORY_ORDER_ACQ_REL memory_order_acq_rel
45#define SC_ATOMIC_MEMORY_ORDER_SEQ_CST memory_order_seq_cst
46
47/**
48 * \brief wrapper for declaring atomic variables.
49 *
50 * \param type Type of the variable (char, short, int, long, long long)
51 * \param name Name of the variable.
52 *
53 * We just declare the variable here as we rely on atomic operations
54 * to modify it, so no need for locks.
55 *
56 * \warning variable is not initialized
57 */
58#define SC_ATOMIC_DECLARE(type, name) \
59 _Atomic(type) name ## _sc_atomic__
60
61/**
62 * \brief wrapper for referencing an atomic variable declared on another file.
63 *
64 * \param type Type of the variable (char, short, int, long, long long)
65 * \param name Name of the variable.
66 *
67 * We just declare the variable here as we rely on atomic operations
68 * to modify it, so no need for locks.
69 *
70 */
71#define SC_ATOMIC_EXTERN(type, name) \
72 extern _Atomic(type) (name ## _sc_atomic__)
73
74/**
75 * \brief wrapper for declaring an atomic variable and initializing it.
76 **/
77#define SC_ATOMIC_DECL_AND_INIT(type, name) \
78 _Atomic(type) (name ## _sc_atomic__) = 0
79
80/**
81 * \brief wrapper for declaring an atomic variable and initializing it
82 * to a specific value
83 **/
84#define SC_ATOMIC_DECL_AND_INIT_WITH_VAL(type, name, val) _Atomic(type)(name##_sc_atomic__) = val
85
86/**
87 * \brief wrapper for initializing an atomic variable.
88 **/
89#define SC_ATOMIC_INIT(name) \
90 (name ## _sc_atomic__) = 0
91#define SC_ATOMIC_INITPTR(name) \
92 (name ## _sc_atomic__) = NULL
93
94/**
95 * \brief wrapper for reinitializing an atomic variable.
96 **/
97#define SC_ATOMIC_RESET(name) \
98 SC_ATOMIC_INIT(name)
99
100/**
101 * \brief add a value to our atomic variable
102 *
103 * \param name the atomic variable
104 * \param val the value to add to the variable
105 */
106#define SC_ATOMIC_ADD(name, val) \
107 atomic_fetch_add(&(name ## _sc_atomic__), (val))
108
109/**
110 * \brief sub a value from our atomic variable
111 *
112 * \param name the atomic variable
113 * \param val the value to sub from the variable
114 */
115#define SC_ATOMIC_SUB(name, val) \
116 atomic_fetch_sub(&(name ## _sc_atomic__), (val))
117
118/**
119 * \brief Bitwise OR a value to our atomic variable
120 *
121 * \param name the atomic variable
122 * \param val the value to OR to the variable
123 */
124#define SC_ATOMIC_OR(name, val) \
125 atomic_fetch_or(&(name ## _sc_atomic__), (val))
126
127/**
128 * \brief Bitwise AND a value to our atomic variable
129 *
130 * \param name the atomic variable
131 * \param val the value to AND to the variable
132 */
133#define SC_ATOMIC_AND(name, val) \
134 atomic_fetch_and(&(name ## _sc_atomic__), (val))
135
136/**
137 * \brief atomic Compare and Switch
138 *
139 * \warning "name" is passed to us as "&var"
140 */
141#define SC_ATOMIC_CAS(name, cmpval, newval) \
142 atomic_compare_exchange_strong((name ## _sc_atomic__), &(cmpval), (newval))
143
144/**
145 * \brief Get the value from the atomic variable.
146 *
147 * \retval var value
148 */
149#define SC_ATOMIC_GET(name) \
150 atomic_load(&(name ## _sc_atomic__))
151
152#define SC_ATOMIC_LOAD_EXPLICIT(name, order) \
153 atomic_load_explicit(&(name ## _sc_atomic__), (order))
154
155/**
156 * \brief Set the value for the atomic variable.
157 *
158 * \retval var value
159 */
160#define SC_ATOMIC_SET(name, val) \
161 atomic_store(&(name ## _sc_atomic__), (val))
162
163#else
164
165#define SC_ATOMIC_MEMORY_ORDER_RELAXED
166#define SC_ATOMIC_MEMORY_ORDER_CONSUME
167#define SC_ATOMIC_MEMORY_ORDER_ACQUIRE
168#define SC_ATOMIC_MEMORY_ORDER_RELEASE
169#define SC_ATOMIC_MEMORY_ORDER_ACQ_REL
170#define SC_ATOMIC_MEMORY_ORDER_SEQ_CST
171
172/**
173 * \brief wrapper for OS/compiler specific atomic compare and swap (CAS)
174 * function.
175 *
176 * \param addr Address of the variable to CAS
177 * \param tv Test value to compare the value at address against
178 * \param nv New value to set the variable at addr to
179 *
180 * \retval 0 CAS failed
181 * \retval 1 CAS succeeded
182 */
183#define SCAtomicCompareAndSwap(addr, tv, nv) \
184 __sync_bool_compare_and_swap((addr), (tv), (nv))
185
186/**
187 * \brief wrapper for OS/compiler specific atomic fetch and add
188 * function.
189 *
190 * \param addr Address of the variable to add to
191 * \param value Value to add to the variable at addr
192 */
193#define SCAtomicFetchAndAdd(addr, value) \
194 __sync_fetch_and_add((addr), (value))
195
196/**
197 * \brief wrapper for OS/compiler specific atomic fetch and sub
198 * function.
199 *
200 * \param addr Address of the variable to add to
201 * \param value Value to sub from the variable at addr
202 */
203#define SCAtomicFetchAndSub(addr, value) \
204 __sync_fetch_and_sub((addr), (value))
205
206/**
207 * \brief wrapper for OS/compiler specific atomic fetch and add
208 * function.
209 *
210 * \param addr Address of the variable to add to
211 * \param value Value to add to the variable at addr
212 */
213#define SCAtomicAddAndFetch(addr, value) \
214 __sync_add_and_fetch((addr), (value))
215
216/**
217 * \brief wrapper for OS/compiler specific atomic fetch and sub
218 * function.
219 *
220 * \param addr Address of the variable to add to
221 * \param value Value to sub from the variable at addr
222 */
223#define SCAtomicSubAndFetch(addr, value) \
224 __sync_sub_and_fetch((addr), (value))
225
226/**
227 * \brief wrapper for OS/compiler specific atomic fetch and "AND"
228 * function.
229 *
230 * \param addr Address of the variable to AND to
231 * \param value Value to add to the variable at addr
232 */
233#define SCAtomicFetchAndAnd(addr, value) \
234 __sync_fetch_and_and((addr), (value))
235
236/**
237 * \brief wrapper for OS/compiler specific atomic fetch and "NAND"
238 * function.
239 *
240 * \param addr Address of the variable to NAND to
241 * \param value Value to add to the variable at addr
242 */
243#define SCAtomicFetchAndNand(addr, value) \
244 __sync_fetch_and_nand((addr), (value))
245
246/**
247 * \brief wrapper for OS/compiler specific atomic fetch and "XOR"
248 * function.
249 *
250 * \param addr Address of the variable to XOR to
251 * \param value Value to add to the variable at addr
252 */
253#define SCAtomicFetchAndXor(addr, value) \
254 __sync_fetch_and_xor((addr), (value))
255
256/**
257 * \brief wrapper for OS/compiler specific atomic fetch and or
258 * function.
259 *
260 * \param addr Address of the variable to or to
261 * \param value Value to add to the variable at addr
262 */
263#define SCAtomicFetchAndOr(addr, value) \
264 __sync_fetch_and_or((addr), (value))
265
266/**
267 * \brief wrapper for declaring atomic variables.
268 *
269 * \warning Only char, short, int, long, long long and their unsigned
270 * versions are supported.
271 *
272 * \param type Type of the variable (char, short, int, long, long long)
273 * \param name Name of the variable.
274 *
275 * We just declare the variable here as we rely on atomic operations
276 * to modify it, so no need for locks.
277 *
278 * \warning variable is not initialized
279 */
280#define SC_ATOMIC_DECLARE(type, name) \
281 type name ## _sc_atomic__
282
283/**
284 * \brief wrapper for referencing an atomic variable declared on another file.
285 *
286 * \warning Only char, short, int, long, long long and their unsigned
287 * versions are supported.
288 *
289 * \param type Type of the variable (char, short, int, long, long long)
290 * \param name Name of the variable.
291 *
292 * We just declare the variable here as we rely on atomic operations
293 * to modify it, so no need for locks.
294 *
295 */
296#define SC_ATOMIC_EXTERN(type, name) \
297 extern type name ## _sc_atomic__
298
299/**
300 * \brief wrapper for declaring an atomic variable and initializing it
301 * to a specific value
302 **/
303#define SC_ATOMIC_DECL_AND_INIT_WITH_VAL(type, name, val) type name##_sc_atomic__ = val
304
305/**
306 * \brief wrapper for declaring an atomic variable and initializing it.
307 **/
308#define SC_ATOMIC_DECL_AND_INIT(type, name) \
309 type name ## _sc_atomic__ = 0
310
311/**
312 * \brief wrapper for initializing an atomic variable.
313 **/
314#define SC_ATOMIC_INIT(name) \
315 (name ## _sc_atomic__) = 0
316
317#define SC_ATOMIC_INITPTR(name) \
318 (name ## _sc_atomic__) = NULL
319
320/**
321 * \brief wrapper for reinitializing an atomic variable.
322 **/
323#define SC_ATOMIC_RESET(name) \
324 (name ## _sc_atomic__) = 0
325
326/**
327 * \brief add a value to our atomic variable
328 *
329 * \param name the atomic variable
330 * \param val the value to add to the variable
331 */
332#define SC_ATOMIC_ADD(name, val) \
333 SCAtomicFetchAndAdd(&(name ## _sc_atomic__), (val))
334
335/**
336 * \brief sub a value from our atomic variable
337 *
338 * \param name the atomic variable
339 * \param val the value to sub from the variable
340 */
341#define SC_ATOMIC_SUB(name, val) \
342 SCAtomicFetchAndSub(&(name ## _sc_atomic__), (val))
343
344/**
345 * \brief Bitwise OR a value to our atomic variable
346 *
347 * \param name the atomic variable
348 * \param val the value to OR to the variable
349 */
350#define SC_ATOMIC_OR(name, val) \
351 SCAtomicFetchAndOr(&(name ## _sc_atomic__), (val))
352
353/**
354 * \brief Bitwise AND a value to our atomic variable
355 *
356 * \param name the atomic variable
357 * \param val the value to AND to the variable
358 */
359#define SC_ATOMIC_AND(name, val) \
360 SCAtomicFetchAndAnd(&(name ## _sc_atomic__), (val))
361
362/**
363 * \brief atomic Compare and Switch
364 *
365 * \warning "name" is passed to us as "&var"
366 */
367#define SC_ATOMIC_CAS(name, cmpval, newval) \
368 SCAtomicCompareAndSwap((name ## _sc_atomic__), cmpval, newval)
369
370/**
371 * \brief Get the value from the atomic variable.
372 *
373 * \retval var value
374 */
375#define SC_ATOMIC_GET(name) \
376 (name ## _sc_atomic__)
377
378#define SC_ATOMIC_LOAD_EXPLICIT(name, order) \
379 (name ## _sc_atomic__)
380
381/**
382 * \brief Set the value for the atomic variable.
383 *
384 * \retval var value
385 */
386#define SC_ATOMIC_SET(name, val) ({ \
387 while (SC_ATOMIC_CAS(&name, SC_ATOMIC_GET(name), val) == 0) \
388 ; \
389 })
390
391#endif /* no c11 atomics */
392
393void SCAtomicRegisterTests(void);
394
395#endif /* SURICATA_UTIL_ATOMIC_H */
void SCAtomicRegisterTests(void)
Definition util-atomic.c:67