From: Andrei Tatar Date: Thu, 16 Nov 2023 18:04:30 +0000 (+0100) Subject: include: Add strong/weak reference counting X-Git-Tag: RELEASE-0.16.0~196 X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=243a4cb3322a224dcfb2dcb96af7f20c40abe81f;p=unikraft%2Funikraft.git include: Add strong/weak reference counting This change adds a utility header implementing a reference counting scheme that supports regular (strong) as well as weak references. Signed-off-by: Andrei Tatar Reviewed-by: Simon Kuenzer Approved-by: Simon Kuenzer GitHub-Closes: #1160 --- diff --git a/include/uk/weak_refcount.h b/include/uk/weak_refcount.h new file mode 100644 index 000000000..83d8e7734 --- /dev/null +++ b/include/uk/weak_refcount.h @@ -0,0 +1,88 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* Copyright (c) 2023, Unikraft GmbH and The Unikraft Authors. + * Licensed under the BSD-3-Clause License (the "License"). + * You may not use this file except in compliance with the License. + */ + +/* Strong/Weak reference counting */ + +#ifndef __UK_WEAK_REFCOUNT_H__ +#define __UK_WEAK_REFCOUNT_H__ + +#include +#include + +struct uk_swrefcount { + __atomic refcount; /* Total number of references */ + __atomic strong; /* Number of strong references; <= .refcount */ +}; + +#define UK_SWREFCOUNT_INITIALIZER(r, s) ((struct uk_swrefcount){ \ + .refcount = UK_REFCOUNT_INITIALIZER((r)), \ + .strong = UK_REFCOUNT_INITIALIZER((s)), \ +}) + +/** + * Initialize refcount with `ref` references, of which `strong` are strong. + */ +static inline +void uk_swrefcount_init(struct uk_swrefcount *sw, __u32 ref, __u32 strong) +{ + UK_ASSERT(ref >= strong); + uk_refcount_init(&sw->refcount, ref); + uk_refcount_init(&sw->strong, strong); +} + +/** + * Acquire a weak reference on `sw`. + */ +static inline +void uk_swrefcount_acquire_weak(struct uk_swrefcount *sw) +{ + uk_refcount_acquire(&sw->refcount); +} + +/** + * Acquire a strong reference on `sw`. + */ +static inline +void uk_swrefcount_acquire(struct uk_swrefcount *sw) +{ + uk_swrefcount_acquire_weak(sw); + uk_refcount_acquire(&sw->strong); +} + +#define UK_SWREFCOUNT_LAST_STRONG 2 /* Released last strong reference */ +#define UK_SWREFCOUNT_LAST_REF 1 /* Released last reference */ + +/** + * Release a weak reference on `sw` and return whether it was the last. + * + * @return + * 0 if there are more references left, or UK_SWREFCOUNT_LAST_REF if not. + */ +static inline +int uk_swrefcount_release_weak(struct uk_swrefcount *sw) +{ + return uk_refcount_release(&sw->refcount) ? UK_SWREFCOUNT_LAST_REF : 0; +} + +/** + * Release a strong reference on `sw` and return whether it was the last. + * + * @return + * 0 if there are more references left, otherwise a bitwise OR of: + * UK_SWREFCOUNT_LAST_STRONG, if we released the last strong reference + * UK_SWREFCOUNT_LAST_REF, if we released the last reference + */ +static inline +int uk_swrefcount_release(struct uk_swrefcount *sw) +{ + int ret = 0; + + if (uk_refcount_release(&sw->strong)) + ret |= UK_SWREFCOUNT_LAST_STRONG; + return ret | uk_swrefcount_release_weak(sw); +} + +#endif /* __UK_WEAK_REFCOUNT_H__ */