atomics: Move atomics/recounting support to separate files
This commit is contained in:
@@ -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 \
|
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/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/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 += \
|
libstrongswan_la_SOURCES += \
|
||||||
threading/thread.c \
|
threading/thread.c \
|
||||||
|
|||||||
@@ -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 \
|
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/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/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
|
if !USE_WINDOWS
|
||||||
libstrongswan_la_SOURCES += \
|
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/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/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/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
|
endif
|
||||||
|
|
||||||
library.lo : $(top_builddir)/config.status
|
library.lo : $(top_builddir)/config.status
|
||||||
|
|||||||
@@ -39,7 +39,6 @@
|
|||||||
#include <utils/debug.h>
|
#include <utils/debug.h>
|
||||||
#include <utils/chunk.h>
|
#include <utils/chunk.h>
|
||||||
#include <collections/enumerator.h>
|
#include <collections/enumerator.h>
|
||||||
#include <threading/spinlock.h>
|
|
||||||
#include <threading/mutex.h>
|
#include <threading/mutex.h>
|
||||||
#include <threading/condvar.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
|
#ifdef HAVE_FMEMOPEN_FALLBACK
|
||||||
|
|
||||||
static int fmemread(chunk_t *cookie, char *buf, int size)
|
static int fmemread(chunk_t *cookie, char *buf, int size)
|
||||||
@@ -848,12 +775,7 @@ void utils_init()
|
|||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
windows_init();
|
windows_init();
|
||||||
#endif
|
#endif
|
||||||
|
atomics_init();
|
||||||
#if !defined(HAVE_GCC_ATOMIC_OPERATIONS) && !defined(HAVE_GCC_SYNC_OPERATIONS)
|
|
||||||
ref_lock = spinlock_create();
|
|
||||||
cas_lock = spinlock_create();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
strerror_init();
|
strerror_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -865,12 +787,7 @@ void utils_deinit()
|
|||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
windows_deinit();
|
windows_deinit();
|
||||||
#endif
|
#endif
|
||||||
|
atomics_deinit();
|
||||||
#if !defined(HAVE_GCC_ATOMIC_OPERATIONS) && !defined(HAVE_GCC_SYNC_OPERATIONS)
|
|
||||||
ref_lock->destroy(ref_lock);
|
|
||||||
cas_lock->destroy(cas_lock);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
strerror_deinit();
|
strerror_deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -96,6 +96,7 @@
|
|||||||
#endif /* TRUE */
|
#endif /* TRUE */
|
||||||
|
|
||||||
#include "enum.h"
|
#include "enum.h"
|
||||||
|
#include "utils/atomics.h"
|
||||||
#include "utils/strerror.h"
|
#include "utils/strerror.h"
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
# include "compat/apple.h"
|
# include "compat/apple.h"
|
||||||
@@ -968,101 +969,6 @@ static inline size_t round_down(size_t size, size_t alignment)
|
|||||||
return size - (size % 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
|
#ifndef HAVE_FMEMOPEN
|
||||||
# ifdef HAVE_FUNOPEN
|
# ifdef HAVE_FUNOPEN
|
||||||
# define HAVE_FMEMOPEN
|
# define HAVE_FMEMOPEN
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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_ @} */
|
||||||
Reference in New Issue
Block a user