mirror of
https://github.com/strongswan/strongswan.git
synced 2025-10-08 00:02:03 -04:00
utils: Use GCC's __atomic built-ins if available
These are available since GCC 4.7 and will eventually replace the __sync operations. They support the memory model defined by C++11. For instance, by using __ATOMIC_RELAXED for some operations on the reference counters we can avoid memory barriers, which are required by __sync operations (whose memory model essentially is __ATOMIC_SEQ_CST).
This commit is contained in:
parent
efedd0d21e
commit
0f603d425d
32
configure.ac
32
configure.ac
@ -667,21 +667,39 @@ AC_COMPILE_IFELSE(
|
|||||||
[AC_MSG_RESULT([no])]
|
[AC_MSG_RESULT([no])]
|
||||||
)
|
)
|
||||||
|
|
||||||
AC_MSG_CHECKING([for gcc atomic operations])
|
AC_MSG_CHECKING([for GCC __atomic operations])
|
||||||
AC_RUN_IFELSE([AC_LANG_SOURCE(
|
AC_RUN_IFELSE([AC_LANG_SOURCE(
|
||||||
[[
|
[[
|
||||||
int main() {
|
int main() {
|
||||||
volatile int ref = 1;
|
int ref = 1, val;
|
||||||
__sync_fetch_and_add (&ref, 1);
|
__atomic_fetch_add(&ref, 1, __ATOMIC_RELAXED);
|
||||||
__sync_sub_and_fetch (&ref, 1);
|
val = __atomic_sub_fetch(&ref, 1, __ATOMIC_RELAXED);
|
||||||
/* Make sure test fails if operations are not supported */
|
__atomic_compare_exchange_n(&ref, &val, 0, 0, __ATOMIC_RELAXED,
|
||||||
__sync_val_compare_and_swap(&ref, 1, 0);
|
__ATOMIC_RELAXED);
|
||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
]])],
|
]])],
|
||||||
[AC_MSG_RESULT([yes]);
|
[AC_MSG_RESULT([yes]);
|
||||||
AC_DEFINE([HAVE_GCC_ATOMIC_OPERATIONS], [],
|
AC_DEFINE([HAVE_GCC_ATOMIC_OPERATIONS], [],
|
||||||
[have GCC __sync_* atomic operations])],
|
[have GCC __atomic_* operations])],
|
||||||
|
[AC_MSG_RESULT([no])],
|
||||||
|
[AC_MSG_RESULT([no])]
|
||||||
|
)
|
||||||
|
|
||||||
|
AC_MSG_CHECKING([for GCC __sync operations])
|
||||||
|
AC_RUN_IFELSE([AC_LANG_SOURCE(
|
||||||
|
[[
|
||||||
|
int main() {
|
||||||
|
int ref = 1;
|
||||||
|
__sync_fetch_and_add (&ref, 1);
|
||||||
|
__sync_sub_and_fetch (&ref, 1);
|
||||||
|
__sync_val_compare_and_swap(&ref, 1, 0);
|
||||||
|
return ref;
|
||||||
|
}
|
||||||
|
]])],
|
||||||
|
[AC_MSG_RESULT([yes]);
|
||||||
|
AC_DEFINE([HAVE_GCC_SYNC_OPERATIONS], [],
|
||||||
|
[have GCC __sync_* operations])],
|
||||||
[AC_MSG_RESULT([no])],
|
[AC_MSG_RESULT([no])],
|
||||||
[AC_MSG_RESULT([no])]
|
[AC_MSG_RESULT([no])]
|
||||||
)
|
)
|
||||||
|
@ -511,7 +511,7 @@ void nop()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef HAVE_GCC_ATOMIC_OPERATIONS
|
#if !defined(HAVE_GCC_ATOMIC_OPERATIONS) && !defined(HAVE_GCC_SYNC_OPERATIONS)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We use a single mutex for all refcount variables.
|
* We use a single mutex for all refcount variables.
|
||||||
@ -578,7 +578,7 @@ bool cas_##name(type *ptr, type oldval, type newval) \
|
|||||||
_cas_impl(bool, bool)
|
_cas_impl(bool, bool)
|
||||||
_cas_impl(ptr, void*)
|
_cas_impl(ptr, void*)
|
||||||
|
|
||||||
#endif /* HAVE_GCC_ATOMIC_OPERATIONS */
|
#endif /* !HAVE_GCC_ATOMIC_OPERATIONS && !HAVE_GCC_SYNC_OPERATIONS */
|
||||||
|
|
||||||
|
|
||||||
#ifdef HAVE_FMEMOPEN_FALLBACK
|
#ifdef HAVE_FMEMOPEN_FALLBACK
|
||||||
|
@ -750,6 +750,25 @@ typedef u_int refcount_t;
|
|||||||
|
|
||||||
#ifdef HAVE_GCC_ATOMIC_OPERATIONS
|
#ifdef HAVE_GCC_ATOMIC_OPERATIONS
|
||||||
|
|
||||||
|
#define ref_get(ref) __atomic_add_fetch(ref, 1, __ATOMIC_RELAXED)
|
||||||
|
/* The relaxed memory model works fine for increments as these (usually) don't
|
||||||
|
* change the state of refcounted objects. But here we have to ensure that we
|
||||||
|
* free the right stuff if ref counted objects are mutable. So we have to sync
|
||||||
|
* with other threads that call ref_put(). It would be sufficient to use
|
||||||
|
* __ATOMIC_RELEASE here and then call __atomic_thread_fence() with
|
||||||
|
* __ATOMIC_ACQUIRE if we reach 0, but since we don't have control over the use
|
||||||
|
* of ref_put() we have to make sure. */
|
||||||
|
#define ref_put(ref) (!__atomic_sub_fetch(ref, 1, __ATOMIC_ACQ_REL))
|
||||||
|
#define ref_cur(ref) __atomic_load_n(ref, __ATOMIC_RELAXED)
|
||||||
|
|
||||||
|
#define _cas_impl(ptr, oldval, newval) ({ typeof(oldval) _old = oldval; \
|
||||||
|
__atomic_compare_exchange_n(ptr, &_old, newval, FALSE, \
|
||||||
|
__ATOMIC_SEQ_CST, __ATOMIC_RELAXED); })
|
||||||
|
#define cas_bool(ptr, oldval, newval) _cas_impl(ptr, oldval, newval)
|
||||||
|
#define cas_ptr(ptr, oldval, newval) _cas_impl(ptr, oldval, newval)
|
||||||
|
|
||||||
|
#elif defined(HAVE_GCC_SYNC_OPERATIONS)
|
||||||
|
|
||||||
#define ref_get(ref) __sync_add_and_fetch(ref, 1)
|
#define ref_get(ref) __sync_add_and_fetch(ref, 1)
|
||||||
#define ref_put(ref) (!__sync_sub_and_fetch(ref, 1))
|
#define ref_put(ref) (!__sync_sub_and_fetch(ref, 1))
|
||||||
#define ref_cur(ref) __sync_fetch_and_add(ref, 0)
|
#define ref_cur(ref) __sync_fetch_and_add(ref, 0)
|
||||||
@ -759,7 +778,7 @@ typedef u_int refcount_t;
|
|||||||
#define cas_ptr(ptr, oldval, newval) \
|
#define cas_ptr(ptr, oldval, newval) \
|
||||||
(__sync_bool_compare_and_swap(ptr, oldval, newval))
|
(__sync_bool_compare_and_swap(ptr, oldval, newval))
|
||||||
|
|
||||||
#else /* !HAVE_GCC_ATOMIC_OPERATIONS */
|
#else /* !HAVE_GCC_ATOMIC_OPERATIONS && !HAVE_GCC_SYNC_OPERATIONS */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a new reference.
|
* Get a new reference.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user