atomics: Move atomics/recounting support to separate files
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user