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