]>
git.ipfire.org Git - people/ms/strongswan.git/blob - src/libstrongswan/utils/utils/atomics.h
2 * Copyright (C) 2008-2014 Tobias Brunner
3 * Copyright (C) 2008 Martin Willi
4 * Hochschule fuer Technik Rapperswil
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 * @defgroup atomics_i atomics
26 * Special type to count references
28 typedef u_int refcount_t
;
30 /* use __atomic* built-ins with GCC 4.7 and newer */
32 # if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 6))
33 # define HAVE_GCC_ATOMIC_OPERATIONS
37 #ifdef HAVE_GCC_ATOMIC_OPERATIONS
39 #define ref_get(ref) __atomic_add_fetch(ref, 1, __ATOMIC_RELAXED)
40 /* The relaxed memory model works fine for increments as these (usually) don't
41 * change the state of refcounted objects. But here we have to ensure that we
42 * free the right stuff if ref counted objects are mutable. So we have to sync
43 * with other threads that call ref_put(). It would be sufficient to use
44 * __ATOMIC_RELEASE here and then call __atomic_thread_fence() with
45 * __ATOMIC_ACQUIRE if we reach 0, but since we don't have control over the use
46 * of ref_put() we have to make sure. */
47 #define ref_put(ref) (!__atomic_sub_fetch(ref, 1, __ATOMIC_ACQ_REL))
48 #define ref_cur(ref) __atomic_load_n(ref, __ATOMIC_RELAXED)
50 #define _cas_impl(ptr, oldval, newval) ({ typeof(oldval) _old = oldval; \
51 __atomic_compare_exchange_n(ptr, &_old, newval, FALSE, \
52 __ATOMIC_SEQ_CST, __ATOMIC_RELAXED); })
53 #define cas_bool(ptr, oldval, newval) _cas_impl(ptr, oldval, newval)
54 #define cas_ptr(ptr, oldval, newval) _cas_impl(ptr, oldval, newval)
56 #elif defined(HAVE_GCC_SYNC_OPERATIONS)
58 #define ref_get(ref) __sync_add_and_fetch(ref, 1)
59 #define ref_put(ref) (!__sync_sub_and_fetch(ref, 1))
60 #define ref_cur(ref) __sync_fetch_and_add(ref, 0)
62 #define cas_bool(ptr, oldval, newval) \
63 (__sync_bool_compare_and_swap(ptr, oldval, newval))
64 #define cas_ptr(ptr, oldval, newval) \
65 (__sync_bool_compare_and_swap(ptr, oldval, newval))
67 #else /* !HAVE_GCC_ATOMIC_OPERATIONS && !HAVE_GCC_SYNC_OPERATIONS */
70 * Get a new reference.
72 * Increments the reference counter atomically.
74 * @param ref pointer to ref counter
75 * @return new value of ref
77 refcount_t
ref_get(refcount_t
*ref
);
80 * Put back a unused reference.
82 * Decrements the reference counter atomically and
83 * says if more references available.
85 * @param ref pointer to ref counter
86 * @return TRUE if no more references counted
88 bool ref_put(refcount_t
*ref
);
91 * Get the current value of the reference counter.
93 * @param ref pointer to ref counter
94 * @return current value of ref
96 refcount_t
ref_cur(refcount_t
*ref
);
99 * Atomically replace value of ptr with newval if it currently equals oldval.
101 * @param ptr pointer to variable
102 * @param oldval old value of the variable
103 * @param newval new value set if possible
104 * @return TRUE if value equaled oldval and newval was written
106 bool cas_bool(bool *ptr
, bool oldval
, bool newval
);
109 * Atomically replace value of ptr with newval if it currently equals oldval.
111 * @param ptr pointer to variable
112 * @param oldval old value of the variable
113 * @param newval new value set if possible
114 * @return TRUE if value equaled oldval and newval was written
116 bool cas_ptr(void **ptr
, void *oldval
, void *newval
);
118 #endif /* HAVE_GCC_ATOMIC_OPERATIONS */
121 * Initialize atomics utility functions
126 * Clean up atomics utility functions
128 void atomics_deinit();
130 #endif /** ATOMICS_H_ @} */