[AC_MSG_RESULT([no])]
)
-AC_MSG_CHECKING([for gcc atomic operations])
+AC_MSG_CHECKING([for GCC __atomic operations])
AC_RUN_IFELSE([AC_LANG_SOURCE(
[[
int main() {
- volatile int ref = 1;
+ int ref = 1, val;
+ __atomic_fetch_add(&ref, 1, __ATOMIC_RELAXED);
+ val = __atomic_sub_fetch(&ref, 1, __ATOMIC_RELAXED);
+ __atomic_compare_exchange_n(&ref, &val, 0, 0, __ATOMIC_RELAXED,
+ __ATOMIC_RELAXED);
+ return ref;
+ }
+ ]])],
+ [AC_MSG_RESULT([yes]);
+ AC_DEFINE([HAVE_GCC_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);
- /* Make sure test fails if operations are not supported */
__sync_val_compare_and_swap(&ref, 1, 0);
return ref;
}
]])],
[AC_MSG_RESULT([yes]);
- AC_DEFINE([HAVE_GCC_ATOMIC_OPERATIONS], [],
- [have GCC __sync_* atomic operations])],
+ AC_DEFINE([HAVE_GCC_SYNC_OPERATIONS], [],
+ [have GCC __sync_* operations])],
[AC_MSG_RESULT([no])],
[AC_MSG_RESULT([no])]
)
#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_put(ref) (!__sync_sub_and_fetch(ref, 1))
#define ref_cur(ref) __sync_fetch_and_add(ref, 0)
#define cas_ptr(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.