From: Martin Willi Date: Wed, 15 Apr 2015 13:48:17 +0000 (+0200) Subject: atomics: Move atomics/recounting support to separate files X-Git-Url: http://git.ipfire.org/?p=people%2Fms%2Fstrongswan.git;a=commitdiff_plain;h=717313c542d3f0a1667494a0165467da0d890ea7 atomics: Move atomics/recounting support to separate files --- diff --git a/src/libstrongswan/Android.mk b/src/libstrongswan/Android.mk index b137b73f9..65bed0f63 100644 --- a/src/libstrongswan/Android.mk +++ b/src/libstrongswan/Android.mk @@ -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 \ diff --git a/src/libstrongswan/Makefile.am b/src/libstrongswan/Makefile.am index 462c34bb2..ab986958e 100644 --- a/src/libstrongswan/Makefile.am +++ b/src/libstrongswan/Makefile.am @@ -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 diff --git a/src/libstrongswan/utils/utils.c b/src/libstrongswan/utils/utils.c index 119c6563a..8a52d04c5 100644 --- a/src/libstrongswan/utils/utils.c +++ b/src/libstrongswan/utils/utils.c @@ -39,7 +39,6 @@ #include #include #include -#include #include #include @@ -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(); } diff --git a/src/libstrongswan/utils/utils.h b/src/libstrongswan/utils/utils.h index c42f88168..bd3245d23 100644 --- a/src/libstrongswan/utils/utils.h +++ b/src/libstrongswan/utils/utils.h @@ -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 index 000000000..17e823e70 --- /dev/null +++ b/src/libstrongswan/utils/utils/atomics.c @@ -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 . + * + * 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 + +#if !defined(HAVE_GCC_ATOMIC_OPERATIONS) && !defined(HAVE_GCC_SYNC_OPERATIONS) + +#include + +/** + * 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 index 000000000..e5db0a1cb --- /dev/null +++ b/src/libstrongswan/utils/utils/atomics.h @@ -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 . + * + * 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_ @} */