[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Minios-devel] [UNIKRAFT PATCH v2] include/refcount: A reference counter support
This patch provides support to track the number of reference held to an object. The reference counter implementation provides support for: * uk_refcount_init - Initialize the counter * uk_refcount_acquire - Atomically increment the counter * uk_refcount_release - Release the reference * uk_refcount_acquire_if_not_zero - Atomically acquire the counter if greater than zero. * uk_refcount_release_if_not_last - Atomically release the reference if it is not last. The last release should free up the necessary memory tracked. Changes since v1: * The refcount data structure is independent of the UKDEBUG library which provides UK_ASSERT. * Asserting for overflow, in the uk_refcount_acquire_if_not_zero. Taken from Freebsd commit-id: 81c19620beed0e Signed-off-by: Sharan Santhanam <sharan.santhanam@xxxxxxxxx> --- include/uk/arch/atomic.h | 19 +++++ include/uk/arch/types.h | 4 ++ include/uk/refcount.h | 183 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 206 insertions(+) create mode 100644 include/uk/refcount.h diff --git a/include/uk/arch/atomic.h b/include/uk/arch/atomic.h index 558067d..5fec756 100644 --- a/include/uk/arch/atomic.h +++ b/include/uk/arch/atomic.h @@ -54,6 +54,25 @@ extern "C" { */ #define ukarch_load_n(src) \ __atomic_load_n(src, __ATOMIC_SEQ_CST) + +/** + * Perform a atomic store operation. + */ +#define ukarch_store_n(src, value) \ + __atomic_store_n(src, value, __ATOMIC_SEQ_CST) + +/** + * Perform a atomic fetch and add operation. + */ +#define ukarch_fetch_add(src, value) \ + __atomic_fetch_add(src, value, __ATOMIC_SEQ_CST) + +/** + * Perform a atomic increment operation. + */ +#define ukarch_inc(src) \ + ukarch_fetch_add(src, 1) + /** * Writes *src into *dst, and returns the previous contents of *dst. */ diff --git a/include/uk/arch/types.h b/include/uk/arch/types.h index a69dc49..9a25336 100644 --- a/include/uk/arch/types.h +++ b/include/uk/arch/types.h @@ -261,6 +261,10 @@ typedef __u64 __phys_addr; #define __NULL ((void *) 0) #endif +typedef struct { + __u32 counter; +} __atomic; + #endif /* !__ASSEMBLY__ */ #ifdef __cplusplus diff --git a/include/uk/refcount.h b/include/uk/refcount.h new file mode 100644 index 0000000..fba707c --- /dev/null +++ b/include/uk/refcount.h @@ -0,0 +1,183 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2005 John Baldwin <jhb@xxxxxxxxxxx> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ +/* Taken from the Freebsd and modified + * commit-id: 81c19620beed0e + */ + +#ifndef __UK_REFCOUNT_H__ +#define __UK_REFCOUNT_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include <uk/arch/types.h> +#include <uk/arch/limits.h> +#include <uk/arch/atomic.h> +#include <uk/arch/lcpu.h> +#include <uk/config.h> + +#ifdef CONFIG_LIBUKDEBUG +#include <uk/assert.h> + +#define __refcnt_assert(x) UK_ASSERT(x) +#else +#define __refcnt_assert(x) \ + do { \ + } while (0) +#endif /* CONFIG_LIBUKDEBUG */ + +/** + * Initialize the atomic reference. + * + * @param ref: + * A reference to the atomic data structure. + * @param value: + * A value to initialize. + */ +static inline void uk_refcount_init(__atomic *ref, __u32 value) +{ + __refcnt_assert(ref != __NULL); + + ukarch_store_n(&ref->counter, value); +} + +/** + * Increment the reference counter. + * @param refs + * Reference to the atomic counter. + */ +static inline void uk_refcount_acquire(__atomic *ref) +{ + __refcnt_assert((ref != __NULL) && (ref->counter < __U32_MAX)); + + ukarch_inc(&ref->counter); +} + +/** + * Decrement the reference counter. + * @param refs + * Reference to the atomic counter. + * @return + * 0: there are more active reference + * 1: this was let reference to the counter. + */ +static inline int uk_refcount_release(__atomic *ref) +{ + __u32 old; + + __refcnt_assert(ref != __NULL); + + /* Compiler Fence */ + barrier(); + + old = ukarch_fetch_add(&ref->counter, -1); + __refcnt_assert(old > 0); + if (old > 1) + return 0; + + /* + * Last reference. Signal the user to call the destructor. + * + * Ensure that the destructor sees all updates. The fence_rel + * at the start of the function synchronized with this fence. + */ + barrier(); + return 1; +} + +/** + * Increment the reference counter if it was already in use. + * @param refs + * Reference to the atomic counter. + * @return + * 0: Failed to acquire the counter. + * 1: Success in acquiring the counter. + */ +static inline int uk_refcount_acquire_if_not_zero(__atomic *ref) +{ + __u32 old; + + __refcnt_assert(ref != __NULL && ref->counter < __U32_MAX); + + old = ref->counter; + for (;;) { + if (old == 0) + return 0; + if (ukarch_compare_exchange_sync(&ref->counter, old, (old + 1)) + == (old + 1)) + return 1; + } +} + +/** + * refcount_read - get a refcount's value + * @r: the refcount + * + * Return: the refcount's value + */ +static inline __u32 uk_refcount_read(const __atomic *ref) +{ + __refcnt_assert(ref != __NULL); + + return ukarch_load_n(&ref->counter); +} + + +/** + * Decrement the reference counter if there are multiple users of the counter. + * @param refs + * Reference to the atomic counter. + * @return + * 0: Failed to acquire the counter. + * 1: Success in acquiring the counter. + */ +static inline int uk_refcount_release_if_not_last(__atomic *ref) +{ + __u32 old; + + __refcnt_assert(ref != __NULL); + + old = ref->counter; + for (;;) { + if (old == 1) + return 0; + if (ukarch_compare_exchange_sync(&ref->counter, old, (old - 1)) + == (old - 1)) + return 1; + } +} + +#undef __refcnt_assert +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __UK_REFCOUNT_H__*/ -- 2.7.4 _______________________________________________ Minios-devel mailing list Minios-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/minios-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |