atomics: Move atomics/recounting support to separate files
authorMartin Willi <martin@revosec.ch>
Wed, 15 Apr 2015 13:48:17 +0000 (15:48 +0200)
committerMartin Willi <martin@revosec.ch>
Thu, 16 Apr 2015 12:49:19 +0000 (14:49 +0200)
src/libstrongswan/Android.mk
src/libstrongswan/Makefile.am
src/libstrongswan/utils/utils.c
src/libstrongswan/utils/utils.h
src/libstrongswan/utils/utils/atomics.c [new file with mode: 0644]
src/libstrongswan/utils/utils/atomics.h [new file with mode: 0644]

index b137b73..65bed0f 100644 (file)
@@ -39,7 +39,8 @@ selectors/traffic_selector.c settings/settings.c settings/settings_types.c \
 settings/settings_parser.c settings/settings_lexer.c utils/cpu_feature.c \
 utils/utils.c utils/chunk.c utils/debug.c utils/enum.c utils/identification.c \
 utils/lexparser.c utils/optionsfrom.c utils/capabilities.c utils/backtrace.c \
-utils/parser_helper.c utils/test.c utils/process.c utils/utils/strerror.c
+utils/parser_helper.c utils/test.c utils/process.c utils/utils/strerror.c \
+utils/utils/atomics.c
 
 libstrongswan_la_SOURCES += \
     threading/thread.c \
index 462c34b..ab98695 100644 (file)
@@ -37,7 +37,8 @@ selectors/traffic_selector.c settings/settings.c settings/settings_types.c \
 settings/settings_parser.y settings/settings_lexer.l utils/cpu_feature.c \
 utils/utils.c utils/chunk.c utils/debug.c utils/enum.c utils/identification.c \
 utils/lexparser.c utils/optionsfrom.c utils/capabilities.c utils/backtrace.c \
-utils/parser_helper.c utils/test.c utils/process.c utils/utils/strerror.c
+utils/parser_helper.c utils/test.c utils/process.c utils/utils/strerror.c \
+utils/utils/atomics.c
 
 if !USE_WINDOWS
   libstrongswan_la_SOURCES += \
@@ -106,7 +107,8 @@ utils/lexparser.h utils/optionsfrom.h utils/capabilities.h utils/backtrace.h \
 utils/cpu_feature.h utils/leak_detective.h utils/printf_hook/printf_hook.h \
 utils/printf_hook/printf_hook_vstr.h utils/printf_hook/printf_hook_builtin.h \
 utils/parser_helper.h utils/test.h utils/integrity_checker.h utils/process.h \
-utils/utils/strerror.h utils/compat/windows.h utils/compat/apple.h
+utils/utils/strerror.h utils/compat/windows.h utils/compat/apple.h \
+utils/utils/atomics.h
 endif
 
 library.lo :   $(top_builddir)/config.status
index 119c656..8a52d04 100644 (file)
@@ -39,7 +39,6 @@
 #include <utils/debug.h>
 #include <utils/chunk.h>
 #include <collections/enumerator.h>
-#include <threading/spinlock.h>
 #include <threading/mutex.h>
 #include <threading/condvar.h>
 
@@ -724,78 +723,6 @@ void nop()
 {
 }
 
-#if !defined(HAVE_GCC_ATOMIC_OPERATIONS) && !defined(HAVE_GCC_SYNC_OPERATIONS)
-
-/**
- * Spinlock for ref_get/put
- */
-static spinlock_t *ref_lock;
-
-/**
- * Increase refcount
- */
-refcount_t ref_get(refcount_t *ref)
-{
-       refcount_t current;
-
-       ref_lock->lock(ref_lock);
-       current = ++(*ref);
-       ref_lock->unlock(ref_lock);
-
-       return current;
-}
-
-/**
- * Decrease refcount
- */
-bool ref_put(refcount_t *ref)
-{
-       bool more_refs;
-
-       ref_lock->lock(ref_lock);
-       more_refs = --(*ref) > 0;
-       ref_lock->unlock(ref_lock);
-       return !more_refs;
-}
-
-/**
- * Current refcount
- */
-refcount_t ref_cur(refcount_t *ref)
-{
-       refcount_t current;
-
-       ref_lock->lock(ref_lock);
-       current = *ref;
-       ref_lock->unlock(ref_lock);
-
-       return current;
-}
-
-/**
- * Spinlock for all compare and swap operations.
- */
-static spinlock_t *cas_lock;
-
-/**
- * Compare and swap if equal to old value
- */
-#define _cas_impl(name, type) \
-bool cas_##name(type *ptr, type oldval, type newval) \
-{ \
-       bool swapped; \
-       cas_lock->lock(cas_lock); \
-       if ((swapped = (*ptr == oldval))) { *ptr = newval; } \
-       cas_lock->unlock(cas_lock); \
-       return swapped; \
-}
-
-_cas_impl(bool, bool)
-_cas_impl(ptr, void*)
-
-#endif /* !HAVE_GCC_ATOMIC_OPERATIONS && !HAVE_GCC_SYNC_OPERATIONS */
-
-
 #ifdef HAVE_FMEMOPEN_FALLBACK
 
 static int fmemread(chunk_t *cookie, char *buf, int size)
@@ -848,12 +775,7 @@ void utils_init()
 #ifdef WIN32
        windows_init();
 #endif
-
-#if !defined(HAVE_GCC_ATOMIC_OPERATIONS) && !defined(HAVE_GCC_SYNC_OPERATIONS)
-       ref_lock = spinlock_create();
-       cas_lock = spinlock_create();
-#endif
-
+       atomics_init();
        strerror_init();
 }
 
@@ -865,12 +787,7 @@ void utils_deinit()
 #ifdef WIN32
        windows_deinit();
 #endif
-
-#if !defined(HAVE_GCC_ATOMIC_OPERATIONS) && !defined(HAVE_GCC_SYNC_OPERATIONS)
-       ref_lock->destroy(ref_lock);
-       cas_lock->destroy(cas_lock);
-#endif
-
+       atomics_deinit();
        strerror_deinit();
 }
 
index c42f881..bd3245d 100644 (file)
@@ -96,6 +96,7 @@
 #endif /* TRUE */
 
 #include "enum.h"
+#include "utils/atomics.h"
 #include "utils/strerror.h"
 #ifdef __APPLE__
 # include "compat/apple.h"
@@ -968,101 +969,6 @@ static inline size_t round_down(size_t size, size_t alignment)
        return size - (size % alignment);
 }
 
-/**
- * Special type to count references
- */
-typedef u_int refcount_t;
-
-/* use __atomic* built-ins with GCC 4.7 and newer */
-#ifdef __GNUC__
-# if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 6))
-#  define HAVE_GCC_ATOMIC_OPERATIONS
-# endif
-#endif
-
-#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_bool(ptr, oldval, newval) \
-                                       (__sync_bool_compare_and_swap(ptr, oldval, newval))
-#define cas_ptr(ptr, oldval, newval) \
-                                       (__sync_bool_compare_and_swap(ptr, oldval, newval))
-
-#else /* !HAVE_GCC_ATOMIC_OPERATIONS && !HAVE_GCC_SYNC_OPERATIONS */
-
-/**
- * Get a new reference.
- *
- * Increments the reference counter atomically.
- *
- * @param ref  pointer to ref counter
- * @return             new value of ref
- */
-refcount_t ref_get(refcount_t *ref);
-
-/**
- * Put back a unused reference.
- *
- * Decrements the reference counter atomically and
- * says if more references available.
- *
- * @param ref  pointer to ref counter
- * @return             TRUE if no more references counted
- */
-bool ref_put(refcount_t *ref);
-
-/**
- * Get the current value of the reference counter.
- *
- * @param ref  pointer to ref counter
- * @return             current value of ref
- */
-refcount_t ref_cur(refcount_t *ref);
-
-/**
- * Atomically replace value of ptr with newval if it currently equals oldval.
- *
- * @param ptr          pointer to variable
- * @param oldval       old value of the variable
- * @param newval       new value set if possible
- * @return                     TRUE if value equaled oldval and newval was written
- */
-bool cas_bool(bool *ptr, bool oldval, bool newval);
-
-/**
- * Atomically replace value of ptr with newval if it currently equals oldval.
- *
- * @param ptr          pointer to variable
- * @param oldval       old value of the variable
- * @param newval       new value set if possible
- * @return                     TRUE if value equaled oldval and newval was written
- */
-bool cas_ptr(void **ptr, void *oldval, void *newval);
-
-#endif /* HAVE_GCC_ATOMIC_OPERATIONS */
-
 #ifndef HAVE_FMEMOPEN
 # ifdef HAVE_FUNOPEN
 #  define HAVE_FMEMOPEN
diff --git a/src/libstrongswan/utils/utils/atomics.c b/src/libstrongswan/utils/utils/atomics.c
new file mode 100644 (file)
index 0000000..17e823e
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2008-2014 Tobias Brunner
+ * Copyright (C) 2005-2008 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include <utils/utils.h>
+
+#if !defined(HAVE_GCC_ATOMIC_OPERATIONS) && !defined(HAVE_GCC_SYNC_OPERATIONS)
+
+#include <threading/spinlock.h>
+
+/**
+ * Spinlock for ref_get/put
+ */
+static spinlock_t *ref_lock;
+
+/**
+ * Increase refcount
+ */
+refcount_t ref_get(refcount_t *ref)
+{
+       refcount_t current;
+
+       ref_lock->lock(ref_lock);
+       current = ++(*ref);
+       ref_lock->unlock(ref_lock);
+
+       return current;
+}
+
+/**
+ * Decrease refcount
+ */
+bool ref_put(refcount_t *ref)
+{
+       bool more_refs;
+
+       ref_lock->lock(ref_lock);
+       more_refs = --(*ref) > 0;
+       ref_lock->unlock(ref_lock);
+       return !more_refs;
+}
+
+/**
+ * Current refcount
+ */
+refcount_t ref_cur(refcount_t *ref)
+{
+       refcount_t current;
+
+       ref_lock->lock(ref_lock);
+       current = *ref;
+       ref_lock->unlock(ref_lock);
+
+       return current;
+}
+
+/**
+ * Spinlock for all compare and swap operations.
+ */
+static spinlock_t *cas_lock;
+
+/**
+ * Compare and swap if equal to old value
+ */
+#define _cas_impl(name, type) \
+bool cas_##name(type *ptr, type oldval, type newval) \
+{ \
+       bool swapped; \
+       cas_lock->lock(cas_lock); \
+       if ((swapped = (*ptr == oldval))) { *ptr = newval; } \
+       cas_lock->unlock(cas_lock); \
+       return swapped; \
+}
+
+_cas_impl(bool, bool)
+_cas_impl(ptr, void*)
+
+#endif /* !HAVE_GCC_ATOMIC_OPERATIONS && !HAVE_GCC_SYNC_OPERATIONS */
+
+/**
+ * See header
+ */
+void atomics_init()
+{
+#if !defined(HAVE_GCC_ATOMIC_OPERATIONS) && !defined(HAVE_GCC_SYNC_OPERATIONS)
+       ref_lock = spinlock_create();
+       cas_lock = spinlock_create();
+#endif
+}
+
+/**
+ * See header
+ */
+void atomics_deinit()
+{
+#if !defined(HAVE_GCC_ATOMIC_OPERATIONS) && !defined(HAVE_GCC_SYNC_OPERATIONS)
+       ref_lock->destroy(ref_lock);
+       cas_lock->destroy(cas_lock);
+#endif
+}
diff --git a/src/libstrongswan/utils/utils/atomics.h b/src/libstrongswan/utils/utils/atomics.h
new file mode 100644 (file)
index 0000000..e5db0a1
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2008-2014 Tobias Brunner
+ * Copyright (C) 2008 Martin Willi
+ * Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup atomics_i atomics
+ * @{ @ingroup utils_i
+ */
+
+#ifndef ATOMICS_H_
+#define ATOMICS_H_
+
+/**
+ * Special type to count references
+ */
+typedef u_int refcount_t;
+
+/* use __atomic* built-ins with GCC 4.7 and newer */
+#ifdef __GNUC__
+# if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 6))
+#  define HAVE_GCC_ATOMIC_OPERATIONS
+# endif
+#endif
+
+#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_bool(ptr, oldval, newval) \
+                                       (__sync_bool_compare_and_swap(ptr, oldval, newval))
+#define cas_ptr(ptr, oldval, newval) \
+                                       (__sync_bool_compare_and_swap(ptr, oldval, newval))
+
+#else /* !HAVE_GCC_ATOMIC_OPERATIONS && !HAVE_GCC_SYNC_OPERATIONS */
+
+/**
+ * Get a new reference.
+ *
+ * Increments the reference counter atomically.
+ *
+ * @param ref  pointer to ref counter
+ * @return             new value of ref
+ */
+refcount_t ref_get(refcount_t *ref);
+
+/**
+ * Put back a unused reference.
+ *
+ * Decrements the reference counter atomically and
+ * says if more references available.
+ *
+ * @param ref  pointer to ref counter
+ * @return             TRUE if no more references counted
+ */
+bool ref_put(refcount_t *ref);
+
+/**
+ * Get the current value of the reference counter.
+ *
+ * @param ref  pointer to ref counter
+ * @return             current value of ref
+ */
+refcount_t ref_cur(refcount_t *ref);
+
+/**
+ * Atomically replace value of ptr with newval if it currently equals oldval.
+ *
+ * @param ptr          pointer to variable
+ * @param oldval       old value of the variable
+ * @param newval       new value set if possible
+ * @return                     TRUE if value equaled oldval and newval was written
+ */
+bool cas_bool(bool *ptr, bool oldval, bool newval);
+
+/**
+ * Atomically replace value of ptr with newval if it currently equals oldval.
+ *
+ * @param ptr          pointer to variable
+ * @param oldval       old value of the variable
+ * @param newval       new value set if possible
+ * @return                     TRUE if value equaled oldval and newval was written
+ */
+bool cas_ptr(void **ptr, void *oldval, void *newval);
+
+#endif /* HAVE_GCC_ATOMIC_OPERATIONS */
+
+/**
+ * Initialize atomics utility functions
+ */
+void atomics_init();
+
+/**
+ * Clean up atomics utility functions
+ */
+void atomics_deinit();
+
+#endif /** ATOMICS_H_ @} */