suricata
util-atomic.h
Go to the documentation of this file.
1 /* Copyright (C) 2007-2013 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 atomic instructions (GCC only at this time)
25  * where available, falls back to (spin)locked* 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  * Where available, we use __sync_fetch_and_add and
33  * __sync_bool_compare_and_swap. If those are unavailable, the API
34  * transparently created a matching (spin)lock for each atomic variable. The
35  * lock will be named "somevar_sc_lock__"
36  *
37  * (*) where spinlocks are unavailable, the threading api falls back to mutex
38  */
39 
40 
41 #ifndef __UTIL_ATOMIC_H__
42 #define __UTIL_ATOMIC_H__
43 
44 /* test if we have atomic operations support */
45 #if (!defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8) || !defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) || \
46  !defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2) || !defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1))
47 
48 /* Do not have atomic operations support, so implement them with locks. */
49 
50 /**
51  * \brief wrapper to declare an atomic variable including a (spin) lock
52  * to protect it.
53  *
54  * \warning Variable and lock are _not_ initialized.
55  */
56 #define SC_ATOMIC_DECLARE(type, name) \
57  type name ## _sc_atomic__; \
58  SCSpinlock name ## _sc_lock__
59 
60 /**
61  * \brief wrapper to reference an atomic variable already declared on another file (including the spin lock)
62  *
63  */
64 #define SC_ATOMIC_EXTERN(type, name) \
65  extern type name ## _sc_atomic__; \
66  extern SCSpinlock name ## _sc_lock__
67 
68 /**
69  * \brief wrapper to declare an atomic variable including a (spin) lock
70  * to protect it and initialize them.
71  */
72 #define SC_ATOMIC_DECL_AND_INIT(type, name) \
73  type name ## _sc_atomic__ = 0; \
74  SCSpinlock name ## _sc_lock__; \
75  SCSpinInit(&(name ## _sc_lock__), 0)
76 
77 /**
78  * \brief Initialize the previously declared atomic variable and it's
79  * lock.
80  */
81 #define SC_ATOMIC_INIT(name) do { \
82  SCSpinInit(&(name ## _sc_lock__), 0); \
83  (name ## _sc_atomic__) = 0; \
84  } while(0)
85 
86 /**
87  * \brief Initialize the previously declared atomic variable and it's
88  * lock.
89  */
90 #define SC_ATOMIC_RESET(name) do { \
91  (name ## _sc_atomic__) = 0; \
92  } while(0)
93 
94 /**
95  * \brief Destroy the lock used to protect this variable
96  */
97 #define SC_ATOMIC_DESTROY(name) do { \
98  SCSpinDestroy(&(name ## _sc_lock__)); \
99  } while (0)
100 
101 /**
102  * \brief add a value to our atomic variable
103  *
104  * \param name the atomic variable
105  * \param val the value to add to the variable
106  */
107 #define SC_ATOMIC_ADD(name, val) ({\
108  typeof(name ## _sc_atomic__) var; \
109  do { \
110  SCSpinLock(&(name ## _sc_lock__)); \
111  (name ## _sc_atomic__) += (val); \
112  var = (name ## _sc_atomic__); \
113  SCSpinUnlock(&(name ## _sc_lock__)); \
114  } while(0); \
115  var ; \
116 })
117 
118 /**
119  * \brief sub a value from our atomic variable
120  *
121  * \param name the atomic variable
122  * \param val the value to sub from the variable
123  */
124 #define SC_ATOMIC_SUB(name, val) ({ \
125  typeof(name ## _sc_atomic__) var; \
126  do { \
127  SCSpinLock(&(name ## _sc_lock__)); \
128  (name ## _sc_atomic__) -= (val); \
129  var = (name ## _sc_atomic__); \
130  SCSpinUnlock(&(name ## _sc_lock__)); \
131  } while(0); \
132  var ; \
133 })
134 
135 /**
136  * \brief Bitwise AND a value from our atomic variable
137  *
138  * \param name the atomic variable
139  * \param val the value to sub from the variable
140  */
141 #define SC_ATOMIC_AND(name, val) \
142  do { \
143  SCSpinLock(&(name ## _sc_lock__)); \
144  (name ## _sc_atomic__) &= (val); \
145  SCSpinUnlock(&(name ## _sc_lock__)); \
146  } while(0)
147 
148 /**
149  * \brief Bitwise OR a value from our atomic variable
150  *
151  * \param name the atomic variable
152  * \param val the value to sub from the variable
153  */
154 #define SC_ATOMIC_OR(name, val) \
155  do { \
156  SCSpinLock(&(name ## _sc_lock__)); \
157  (name ## _sc_atomic__) |= (val); \
158  SCSpinUnlock(&(name ## _sc_lock__)); \
159  } while(0)
160 
161 /**
162  * \brief Bitwise NAND a value from our atomic variable
163  *
164  * \param name the atomic variable
165  * \param val the value to sub from the variable
166  */
167 #define SC_ATOMIC_NAND(name, val) \
168  do { \
169  SCSpinLock(&(name ## _sc_lock__)); \
170  (name ## _sc_atomic__) = ~(name ## _sc_atomic__) & (val); \
171  SCSpinUnlock(&(name ## _sc_lock__)); \
172  } while(0)
173 
174 /**
175  * \brief Bitwise XOR a value from our atomic variable
176  *
177  * \param name the atomic variable
178  * \param val the value to sub from the variable
179  */
180 #define SC_ATOMIC_XOR(name, val) \
181  do { \
182  SCSpinLock(&(name ## _sc_lock__)); \
183  (name ## _sc_atomic__) ^= (val); \
184  SCSpinUnlock(&(name ## _sc_lock__)); \
185  } while(0)
186 
187 /**
188  * \brief Get the value from the atomic variable.
189  *
190  * \retval var value
191  */
192 #define SC_ATOMIC_GET(name) ({ \
193  typeof(name ## _sc_atomic__) var; \
194  do { \
195  SCSpinLock(&(name ## _sc_lock__)); \
196  var = (name ## _sc_atomic__); \
197  SCSpinUnlock(&(name ## _sc_lock__)); \
198  } while (0); \
199  var; \
200 })
201 
202 /**
203  * \brief Set the value for the atomic variable.
204  *
205  * \retval var value
206  */
207 #define SC_ATOMIC_SET(name, val) ({ \
208  typeof(name ## _sc_atomic__) var; \
209  do { \
210  SCSpinLock(&(name ## _sc_lock__)); \
211  var = (name ## _sc_atomic__) = val; \
212  SCSpinUnlock(&(name ## _sc_lock__)); \
213  } while (0); \
214  var; \
215 })
216 
217 /**
218  * \brief atomic Compare and Switch
219  *
220  * \warning "name" is passed to us as "&var"
221  */
222 #define SC_ATOMIC_CAS(name, cmpval, newval) ({ \
223  char r = 0; \
224  do { \
225  SCSpinLock((name ## _sc_lock__)); \
226  if (*(name ## _sc_atomic__) == (cmpval)) { \
227  *(name ## _sc_atomic__) = (newval); \
228  r = 1; \
229  } \
230  SCSpinUnlock((name ## _sc_lock__)); \
231  } while(0); \
232  r; \
233 })
234 
235 #else /* we do have support for CAS */
236 
237 /**
238  * \brief wrapper for OS/compiler specific atomic compare and swap (CAS)
239  * function.
240  *
241  * \param addr Address of the variable to CAS
242  * \param tv Test value to compare the value at address against
243  * \param nv New value to set the variable at addr to
244  *
245  * \retval 0 CAS failed
246  * \retval 1 CAS succeeded
247  */
248 #define SCAtomicCompareAndSwap(addr, tv, nv) \
249  __sync_bool_compare_and_swap((addr), (tv), (nv))
250 
251 /**
252  * \brief wrapper for OS/compiler specific atomic fetch and add
253  * function.
254  *
255  * \param addr Address of the variable to add to
256  * \param value Value to add to the variable at addr
257  */
258 #define SCAtomicFetchAndAdd(addr, value) \
259  __sync_fetch_and_add((addr), (value))
260 
261 /**
262  * \brief wrapper for OS/compiler specific atomic fetch and sub
263  * function.
264  *
265  * \param addr Address of the variable to add to
266  * \param value Value to sub from the variable at addr
267  */
268 #define SCAtomicFetchAndSub(addr, value) \
269  __sync_fetch_and_sub((addr), (value))
270 
271 /**
272  * \brief wrapper for OS/compiler specific atomic fetch and add
273  * function.
274  *
275  * \param addr Address of the variable to add to
276  * \param value Value to add to the variable at addr
277  */
278 #define SCAtomicAddAndFetch(addr, value) \
279  __sync_add_and_fetch((addr), (value))
280 
281 /**
282  * \brief wrapper for OS/compiler specific atomic fetch and sub
283  * function.
284  *
285  * \param addr Address of the variable to add to
286  * \param value Value to sub from the variable at addr
287  */
288 #define SCAtomicSubAndFetch(addr, value) \
289  __sync_sub_and_fetch((addr), (value))
290 
291 
292 
293 /**
294  * \brief wrapper for OS/compiler specific atomic fetch and "AND"
295  * function.
296  *
297  * \param addr Address of the variable to AND to
298  * \param value Value to add to the variable at addr
299  */
300 #define SCAtomicFetchAndAnd(addr, value) \
301  __sync_fetch_and_and((addr), (value))
302 
303 /**
304  * \brief wrapper for OS/compiler specific atomic fetch and "NAND"
305  * function.
306  *
307  * \param addr Address of the variable to NAND to
308  * \param value Value to add to the variable at addr
309  */
310 #define SCAtomicFetchAndNand(addr, value) \
311  __sync_fetch_and_nand((addr), (value))
312 
313 /**
314  * \brief wrapper for OS/compiler specific atomic fetch and "XOR"
315  * function.
316  *
317  * \param addr Address of the variable to XOR to
318  * \param value Value to add to the variable at addr
319  */
320 #define SCAtomicFetchAndXor(addr, value) \
321  __sync_fetch_and_xor((addr), (value))
322 
323 
324 /**
325  * \brief wrapper for OS/compiler specific atomic fetch and or
326  * function.
327  *
328  * \param addr Address of the variable to or to
329  * \param value Value to add to the variable at addr
330  */
331 #define SCAtomicFetchAndOr(addr, value) \
332  __sync_fetch_and_or((addr), (value))
333 
334 /**
335  * \brief wrapper for declaring atomic variables.
336  *
337  * \warning Only char, short, int, long, long long and their unsigned
338  * versions are supported.
339  *
340  * \param type Type of the variable (char, short, int, long, long long)
341  * \param name Name of the variable.
342  *
343  * We just declare the variable here as we rely on atomic operations
344  * to modify it, so no need for locks.
345  *
346  * \warning variable is not initialized
347  */
348 #define SC_ATOMIC_DECLARE(type, name) \
349  type name ## _sc_atomic__
350 
351 /**
352  * \brief wrapper for referencing an atomic variable declared on another file.
353  *
354  * \warning Only char, short, int, long, long long and their unsigned
355  * versions are supported.
356  *
357  * \param type Type of the variable (char, short, int, long, long long)
358  * \param name Name of the variable.
359  *
360  * We just declare the variable here as we rely on atomic operations
361  * to modify it, so no need for locks.
362  *
363  */
364 #define SC_ATOMIC_EXTERN(type, name) \
365  extern type name ## _sc_atomic__
366 
367 /**
368  * \brief wrapper for declaring an atomic variable and initializing it.
369  **/
370 #define SC_ATOMIC_DECL_AND_INIT(type, name) \
371  type name ## _sc_atomic__ = 0
372 
373 /**
374  * \brief wrapper for initializing an atomic variable.
375  **/
376 #define SC_ATOMIC_INIT(name) \
377  (name ## _sc_atomic__) = 0
378 
379 /**
380  * \brief wrapper for reinitializing an atomic variable.
381  **/
382 #define SC_ATOMIC_RESET(name) \
383  (name ## _sc_atomic__) = 0
384 
385 /**
386  * \brief No-op.
387  */
388 #define SC_ATOMIC_DESTROY(name)
389 
390 /**
391  * \brief add a value to our atomic variable
392  *
393  * \param name the atomic variable
394  * \param val the value to add to the variable
395  */
396 #define SC_ATOMIC_ADD(name, val) \
397  SCAtomicAddAndFetch(&(name ## _sc_atomic__), (val))
398 
399 /**
400  * \brief sub a value from our atomic variable
401  *
402  * \param name the atomic variable
403  * \param val the value to sub from the variable
404  */
405 #define SC_ATOMIC_SUB(name, val) \
406  SCAtomicSubAndFetch(&(name ## _sc_atomic__), (val))
407 
408 /**
409  * \brief Bitwise OR a value to our atomic variable
410  *
411  * \param name the atomic variable
412  * \param val the value to OR to the variable
413  */
414 #define SC_ATOMIC_OR(name, val) \
415  SCAtomicFetchAndOr(&(name ## _sc_atomic__), (val))
416 
417 /**
418  * \brief Bitwise AND a value to our atomic variable
419  *
420  * \param name the atomic variable
421  * \param val the value to AND to the variable
422  */
423 #define SC_ATOMIC_AND(name, val) \
424  SCAtomicFetchAndAnd(&(name ## _sc_atomic__), (val))
425 
426 /**
427  * \brief Bitwise NAND a value to our atomic variable
428  *
429  * \param name the atomic variable
430  * \param val the value to NAND to the variable
431  */
432 #define SC_ATOMIC_NAND(name, val) \
433  SCAtomicFetchAndNand(&(name ## _sc_atomic__), (val))
434 
435 /**
436  * \brief Bitwise XOR a value to our atomic variable
437  *
438  * \param name the atomic variable
439  * \param val the value to XOR to the variable
440  */
441 #define SC_ATOMIC_XOR(name, val) \
442  SCAtomicFetchAndXor(&(name ## _sc_atomic__), (val))
443 
444 /**
445  * \brief atomic Compare and Switch
446  *
447  * \warning "name" is passed to us as "&var"
448  */
449 #define SC_ATOMIC_CAS(name, cmpval, newval) \
450  SCAtomicCompareAndSwap((name ## _sc_atomic__), cmpval, newval)
451 
452 /**
453  * \brief Get the value from the atomic variable.
454  *
455  * \retval var value
456  */
457 #define SC_ATOMIC_GET(name) \
458  (name ## _sc_atomic__)
459 
460 /**
461  * \brief Set the value for the atomic variable.
462  *
463  * \retval var value
464  */
465 #define SC_ATOMIC_SET(name, val) ({ \
466  while (SC_ATOMIC_CAS(&name, SC_ATOMIC_GET(name), val) == 0) \
467  ; \
468  })
469 
470 #endif /* !no atomic operations */
471 
472 void SCAtomicRegisterTests(void);
473 
474 #endif /* __UTIL_ATOMIC_H__ */
475 
void SCAtomicRegisterTests(void)
Definition: util-atomic.c:66